home · contact · privacy
Allow serving different protocols on different ports at the same time.
[plomrogue2-experiments] / new2 / plomrogue / io.py
index 12e74500eff1b7582d2a6a81601696e8076d4833..5450c343a031a721c64ae70289719f40729b1a7f 100644 (file)
@@ -1,53 +1,54 @@
 import queue
+import threading
 
 
 
 class GameIO():
 
-    def __init__(self, game):
+    def __init__(self, game, save_file='savefile'):
         from plomrogue.parser import Parser
-        self.clients = {}
         self.parser = Parser(game)
         self.game = game
+        self.save_file = save_file
+        self.servers = []
 
     def loop(self, q):
         """Handle commands coming through queue q, run game, send results back."""
         while True:
             try:
-                command, connection_id = q.get(timeout=1)
+                command, connection_id = q.get(timeout=0.001)
                 self.handle_input(connection_id, command)
             except queue.Empty:
                 self.game.run_tick()
 
-    def run_loop_with_server(self, port, server_class):
-        """Run connection of server talking to clients and game IO loop.
+    def start_loop(self):
+        """Start game loop, set up self.queue to communicate with it.
 
-        We have a server of self.server_class and we have the game IO loop,
-        a thread running self.loop. Both communicate with each other via a
-        queue.Queue. While the server may spawn parallel threads to many
-        clients, the IO loop works sequentially through game commands
-        received from the server's client connections.  A processed command
-        may trigger messages to the commanding client or to all clients,
-        delivered from the IO loop to the server via the queue.
+        The game loop works sequentially through game commands received
+        via self.queue from connected servers' clients."""
+        self.queue = queue.Queue()
+        c = threading.Thread(target=self.loop, args=(self.queue,))
+        c.start()
+
+    def start_server(self, port, server_class):
+        """Start server of server_class in talk with game loop.
 
+        The server communicates with the game loop via self.queue.
         """
-        import threading
-        q = queue.Queue()
-        c = threading.Thread(target=self.loop, daemon=True, args=(q,))
+        server = server_class(self.queue, port)
+        self.servers += [server]
+        c = threading.Thread(target=server.serve_forever)
         c.start()
-        self.server = server_class(q, port)
-        try:
-            self.server.serve_forever()
-        except KeyboardInterrupt:
-            pass
-        finally:
-            print('Killing server')
-            self.server.server_close()
-
-    def handle_input(self, input_, connection_id=None):
-        """Process input_ to command grammar, call command handler if found."""
+
+    def handle_input(self, input_, connection_id=None, god_mode=False):
+        """Process input_ to command grammar, call command handler if found.
+
+        Command handlers that have no connectin_i argument in their
+        signature will only be called if god_mode is set.
+
+        """
         from inspect import signature
-        from plomrogue.errors import GameError, ArgError
+        from plomrogue.errors import GameError, ArgError, PlayError
         from plomrogue.misc import quote
 
         def answer(connection_id, msg):
@@ -63,25 +64,34 @@ class GameIO():
             else:
                 if 'connection_id' in list(signature(command).parameters):
                     command(*args, connection_id=connection_id)
-                else:
+                elif god_mode:
                     command(*args)
                     #if store and not hasattr(command, 'dont_save'):
                     #    with open(self.game_file_name, 'a') as f:
                     #        f.write(input_ + '\n')
         except ArgError as e:
             answer(connection_id, 'ARGUMENT_ERROR ' + quote(str(e)))
+        except PlayError as e:
+            answer(connection_id, 'PLAY_ERROR ' + quote(str(e)))
         except GameError as e:
             answer(connection_id, 'GAME_ERROR ' + quote(str(e)))
 
     def send(self, msg, connection_id=None):
-        """Send message msg to server's client(s).
+        """Send message msg to servers' client(s).
 
         If a specific client is identified by connection_id, only
-        sends msg to that one. Else, sends it to all clients.
+        sends msg to that one. Else, sends it to all client sessions.
 
         """
         if connection_id:
-            self.server.clients[connection_id].put(msg)
+            for server in self.servers:
+                 if connection_id in server.clients:
+                    client = server.clients[connection_id]
+                    client.put(msg)
         else:
-            for c in self.server.clients.values():
-                c.put(msg)
+            for c_id in self.game.sessions:
+                for server in self.servers:
+                    if c_id in server.clients:
+                        client = server.clients[c_id]
+                        client.put(msg)
+                        break