--- /dev/null
+import queue
+
+
+
+class GameIO():
+
+ def __init__(self, game):
+ from plomrogue.parser import Parser
+ self.clients = {}
+ self.parser = Parser(game)
+ self.game = game
+
+ 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)
+ 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.
+
+ 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.
+
+ """
+ import threading
+ q = queue.Queue()
+ c = threading.Thread(target=self.loop, daemon=True, args=(q,))
+ 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."""
+ from inspect import signature
+ from plomrogue.errors import GameError, ArgError
+ from plomrogue.misc import quote
+
+ def answer(connection_id, msg):
+ if connection_id:
+ self.send(msg, connection_id)
+ else:
+ print(msg)
+
+ try:
+ command, args = self.parser.parse(input_)
+ if command is None:
+ answer(connection_id, 'UNHANDLED_INPUT')
+ else:
+ if 'connection_id' in list(signature(command).parameters):
+ command(*args, connection_id=connection_id)
+ else:
+ 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 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).
+
+ If a specific client is identified by connection_id, only
+ sends msg to that one. Else, sends it to all clients.
+
+ """
+ if connection_id:
+ self.server.clients[connection_id].put(msg)
+ else:
+ for c in self.server.clients.values():
+ c.put(msg)