Module Session
[hide private]
[frames] | no frames]

Source Code for Module Session

  1  ##################################################################### 
  2  # -*- coding: iso-8859-1 -*-                                        # 
  3  #                                                                   # 
  4  # Frets on Fire                                                     # 
  5  # Copyright (C) 2006 Sami Kyöstilä                                  # 
  6  #                                                                   # 
  7  # This program is free software; you can redistribute it and/or     # 
  8  # modify it under the terms of the GNU General Public License       # 
  9  # as published by the Free Software Foundation; either version 2    # 
 10  # of the License, or (at your option) any later version.            # 
 11  #                                                                   # 
 12  # This program is distributed in the hope that it will be useful,   # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of    # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     # 
 15  # GNU General Public License for more details.                      # 
 16  #                                                                   # 
 17  # You should have received a copy of the GNU General Public License # 
 18  # along with this program; if not, write to the Free Software       # 
 19  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,        # 
 20  # MA  02110-1301, USA.                                              # 
 21  ##################################################################### 
 22   
 23  import pickle 
 24  from StringIO import StringIO 
 25   
 26  import Network 
 27  import Engine 
 28  import Log 
 29  import World 
 30  import Task 
 31   
 32  try: 
 33    reversed 
 34  except: 
35 - def reversed(seq):
36 seq = seq[:] 37 seq.reverse() 38 return seq
39
40 -class Message:
41 - def __init__(self, **args):
42 for key, value in args.items(): 43 setattr(self, key, value)
44
45 - def __repr__(self):
46 return "<Message %s %s>" % (str(self.__class__), " ".join(["%s='%s'" % (k, v) for k, v in self.__dict__.items()]))
47
48 -class MessageBroker:
49 - def __init__(self):
50 self.messageHandlers = []
51
52 - def addMessageHandler(self, handler):
53 if handler not in self.messageHandlers: 54 self.messageHandlers.append(handler)
55
56 - def removeMessageHandler(self, handler):
57 if handler in self.messageHandlers: 58 self.messageHandlers.remove(handler)
59
60 - def signalMessage(self, sender, message):
61 #if not Log.quiet and len(str(message)) < 80: 62 # Log.debug("From %s: %s" % (sender, message)) 63 # print self.messageHandlers 64 for handler in reversed(self.messageHandlers): 65 try: 66 handler.handleMessage(sender, message) 67 except Exception, e: 68 import traceback 69 traceback.print_exc()
70
71 - def signalSessionOpened(self, session):
72 for handler in self.messageHandlers: 73 handler.handleSessionOpened(session)
74
75 - def signalSessionClosed(self, session):
76 for handler in self.messageHandlers: 77 handler.handleSessionClosed(session)
78
79 -class MessageHandler:
80 - def handleMessage(self, sender, message):
81 f = None 82 try: 83 n = "handle" + str(message.__class__).split(".")[-1] 84 f = getattr(self, n) 85 except AttributeError: 86 return None 87 return f(sender, **message.__dict__)
88
89 - def handleSessionOpened(self, session):
90 pass
91
92 - def handleSessionClosed(self, session):
93 pass
94
95 -class Phrasebook:
96 - def __init__(self):
97 self.receivedClasses = {} 98 self.sentClasses = {}
99
100 - def serialize(data):
101 s = StringIO() 102 pickle.Pickler(s, protocol = 2).dump(data) 103 return s.getvalue()
104 serialize = staticmethod(serialize) 105
106 - def unserialize(data):
107 return pickle.loads(data)
108 unserialize = staticmethod(unserialize) 109
110 - def decode(self, packet):
111 data = self.unserialize(packet) 112 id = data[0] 113 if id < 0: 114 self.receivedClasses[-id] = data[1:] 115 Log.debug("Learned about %s, %d phrases now known." % (data[1], len(self.receivedClasses))) 116 elif id in self.receivedClasses: 117 message = self.receivedClasses[id][0]() 118 if len(data) > 1: 119 message.__dict__.update(dict(zip(self.receivedClasses[id][1], data[1:]))) 120 return message 121 else: 122 Log.warn("Message with unknown class received: %d" % id)
123
124 - def encode(self, message):
125 packets = [] 126 127 if not message.__class__ in self.sentClasses: 128 id = len(self.sentClasses) + 1 129 definition = [message.__class__, message.__dict__.keys()] 130 self.sentClasses[message.__class__] = [id] + definition 131 packets.append(self.serialize([-id] + definition)) 132 Log.debug("%d phrases taught." % len(self.sentClasses)) 133 else: 134 id = self.sentClasses[message.__class__][0] 135 136 data = [id] + [getattr(message, key) for key in self.sentClasses[message.__class__][2]] 137 packets.append(self.serialize(data)) 138 return packets
139
140 -class BaseSession(Network.Connection, Task.Task, MessageHandler):
141 - def __init__(self, engine, broker, sock = None):
142 Network.Connection.__init__(self, sock) 143 self.engine = engine 144 self.broker = broker 145 self.phrasebook = Phrasebook()
146
147 - def __str__(self):
148 return "<Session #%s at %s>" % (self.id, self.addr)
149
150 - def isPrimary(self):
151 return self.id == 1
152
153 - def run(self, ticks):
154 pass
155
156 - def stopped(self):
157 self.close()
158
159 - def disconnect(self):
160 return self.engine.disconnect(self)
161
162 - def sendMessage(self, message):
163 #print "Sent by %s:%s: %s" % (self.__class__, self.id, message) 164 #self.sendPacket(message.serialize()) 165 for packet in self.phrasebook.encode(message): 166 self.sendPacket(packet)
167
168 - def handleMessage(self, sender, message):
169 #print "Received by %s:%s: %s" % (self.__class__, self.id, message) 170 self.broker.signalMessage(sender, message)
171
172 - def handleRegistration(self):
173 Log.debug("Connected as session #%d." % self.id)
174
175 - def isConnected(self):
176 return self.id is not None
177
178 -class ServerSession(BaseSession):
179 - def __init__(self, engine, sock):
180 BaseSession.__init__(self, engine = engine, broker = engine.server.broker, sock = sock) 181 self.server = engine.server 182 self.world = self.server.world
183
184 - def handlePacket(self, packet):
185 message = self.phrasebook.decode(packet) 186 if message: 187 self.handleMessage(self.id, message)
188
189 - def handleRegistration(self):
190 self.broker.signalSessionOpened(self)
191
192 - def handleClose(self):
193 self.broker.signalSessionClosed(self) 194 BaseSession.handleClose(self)
195
196 -class ConnectionLost(Message): pass
197
198 -class ClientSession(BaseSession):
199 - def __init__(self, engine):
200 BaseSession.__init__(self, engine = engine, broker = MessageBroker()) 201 self.world = World.WorldClient(engine, session = self) 202 self.broker.addMessageHandler(self.world) 203 self.closed = False
204
205 - def handleClose(self):
206 if not self.closed: 207 self.closed = True 208 self.broker.signalMessage(0, ConnectionLost())
209
210 - def handlePacket(self, packet):
211 message = self.phrasebook.decode(packet) 212 if message: 213 self.handleMessage(0, message)
214
215 - def run(self, ticks):
217