home · contact · privacy
Allow serving different protocols on different ports at the same time.
[plomrogue2-experiments] / new2 / plomrogue / io.py
1 import queue
2 import threading
3
4
5
6 class GameIO():
7
8     def __init__(self, game, save_file='savefile'):
9         from plomrogue.parser import Parser
10         self.parser = Parser(game)
11         self.game = game
12         self.save_file = save_file
13         self.servers = []
14
15     def loop(self, q):
16         """Handle commands coming through queue q, run game, send results back."""
17         while True:
18             try:
19                 command, connection_id = q.get(timeout=0.001)
20                 self.handle_input(connection_id, command)
21             except queue.Empty:
22                 self.game.run_tick()
23
24     def start_loop(self):
25         """Start game loop, set up self.queue to communicate with it.
26
27         The game loop works sequentially through game commands received
28         via self.queue from connected servers' clients."""
29         self.queue = queue.Queue()
30         c = threading.Thread(target=self.loop, args=(self.queue,))
31         c.start()
32
33     def start_server(self, port, server_class):
34         """Start server of server_class in talk with game loop.
35
36         The server communicates with the game loop via self.queue.
37         """
38         server = server_class(self.queue, port)
39         self.servers += [server]
40         c = threading.Thread(target=server.serve_forever)
41         c.start()
42
43     def handle_input(self, input_, connection_id=None, god_mode=False):
44         """Process input_ to command grammar, call command handler if found.
45
46         Command handlers that have no connectin_i argument in their
47         signature will only be called if god_mode is set.
48
49         """
50         from inspect import signature
51         from plomrogue.errors import GameError, ArgError, PlayError
52         from plomrogue.misc import quote
53
54         def answer(connection_id, msg):
55             if connection_id:
56                 self.send(msg, connection_id)
57             else:
58                 print(msg)
59
60         try:
61             command, args = self.parser.parse(input_)
62             if command is None:
63                 answer(connection_id, 'UNHANDLED_INPUT')
64             else:
65                 if 'connection_id' in list(signature(command).parameters):
66                     command(*args, connection_id=connection_id)
67                 elif god_mode:
68                     command(*args)
69                     #if store and not hasattr(command, 'dont_save'):
70                     #    with open(self.game_file_name, 'a') as f:
71                     #        f.write(input_ + '\n')
72         except ArgError as e:
73             answer(connection_id, 'ARGUMENT_ERROR ' + quote(str(e)))
74         except PlayError as e:
75             answer(connection_id, 'PLAY_ERROR ' + quote(str(e)))
76         except GameError as e:
77             answer(connection_id, 'GAME_ERROR ' + quote(str(e)))
78
79     def send(self, msg, connection_id=None):
80         """Send message msg to servers' client(s).
81
82         If a specific client is identified by connection_id, only
83         sends msg to that one. Else, sends it to all client sessions.
84
85         """
86         if connection_id:
87             for server in self.servers:
88                  if connection_id in server.clients:
89                     client = server.clients[connection_id]
90                     client.put(msg)
91         else:
92             for c_id in self.game.sessions:
93                 for server in self.servers:
94                     if c_id in server.clients:
95                         client = server.clients[c_id]
96                         client.put(msg)
97                         break