103 lines
3.3 KiB
Python
103 lines
3.3 KiB
Python
import struct
|
|
#import marshal
|
|
|
|
# ___________________________________________________________________________
|
|
#
|
|
# Messages
|
|
# ___________________________________________________________________________
|
|
# the header format
|
|
HDR_FORMAT = "!hhii"
|
|
HDR_SIZE = struct.calcsize(HDR_FORMAT)
|
|
|
|
class Message:
|
|
""" encapsulates Messages and their wire protocol. """
|
|
_types = {}
|
|
def __init__(self, channelid=0, data=''):
|
|
self.channelid = channelid
|
|
self.data = data
|
|
|
|
def writeto(self, io):
|
|
# XXX marshal.dumps doesn't work for exchanging data across Python
|
|
# version :-((( There is no sane solution, short of a custom
|
|
# pure Python marshaller
|
|
data = self.data
|
|
if isinstance(data, str):
|
|
dataformat = 1
|
|
else:
|
|
data = repr(self.data) # argh
|
|
dataformat = 2
|
|
header = struct.pack(HDR_FORMAT, self.msgtype, dataformat,
|
|
self.channelid, len(data))
|
|
io.write(header + data)
|
|
|
|
def readfrom(cls, io):
|
|
header = io.read(HDR_SIZE)
|
|
(msgtype, dataformat,
|
|
senderid, stringlen) = struct.unpack(HDR_FORMAT, header)
|
|
data = io.read(stringlen)
|
|
if dataformat == 1:
|
|
pass
|
|
elif dataformat == 2:
|
|
data = eval(data, {}) # reversed argh
|
|
else:
|
|
raise ValueError("bad data format")
|
|
msg = cls._types[msgtype](senderid, data)
|
|
return msg
|
|
readfrom = classmethod(readfrom)
|
|
|
|
def post_sent(self, gateway, excinfo=None):
|
|
pass
|
|
|
|
def __repr__(self):
|
|
r = repr(self.data)
|
|
if len(r) > 50:
|
|
return "<Message.%s channelid=%d len=%d>" %(self.__class__.__name__,
|
|
self.channelid, len(r))
|
|
else:
|
|
return "<Message.%s channelid=%d %r>" %(self.__class__.__name__,
|
|
self.channelid, self.data)
|
|
|
|
|
|
def _setupmessages():
|
|
|
|
class CHANNEL_OPEN(Message):
|
|
def received(self, gateway):
|
|
channel = gateway._channelfactory.new(self.channelid)
|
|
gateway._local_schedulexec(channel=channel, sourcetask=self.data)
|
|
|
|
class CHANNEL_NEW(Message):
|
|
def received(self, gateway):
|
|
""" receive a remotely created new (sub)channel. """
|
|
newid = self.data
|
|
newchannel = gateway._channelfactory.new(newid)
|
|
gateway._channelfactory._local_receive(self.channelid, newchannel)
|
|
|
|
class CHANNEL_DATA(Message):
|
|
def received(self, gateway):
|
|
gateway._channelfactory._local_receive(self.channelid, self.data)
|
|
|
|
class CHANNEL_CLOSE(Message):
|
|
def received(self, gateway):
|
|
gateway._channelfactory._local_close(self.channelid)
|
|
|
|
class CHANNEL_CLOSE_ERROR(Message):
|
|
def received(self, gateway):
|
|
remote_error = gateway._channelfactory.RemoteError(self.data)
|
|
gateway._channelfactory._local_close(self.channelid, remote_error)
|
|
|
|
class CHANNEL_LAST_MESSAGE(Message):
|
|
def received(self, gateway):
|
|
gateway._channelfactory._local_last_message(self.channelid)
|
|
|
|
classes = [x for x in locals().values() if hasattr(x, '__bases__')]
|
|
classes.sort(lambda x,y : cmp(x.__name__, y.__name__))
|
|
i = 0
|
|
for cls in classes:
|
|
Message._types[i] = cls
|
|
cls.msgtype = i
|
|
setattr(Message, cls.__name__, cls)
|
|
i+=1
|
|
|
|
_setupmessages()
|
|
|