import msgstruct import sys class FakeMessageTransport: def __init__ (self): self.source=None self.sentmessages = [] self.closed = False def recvmsg (self): while self.source: return self.source.pop (0) raise EOFError() def sendmsg (self, *args): self.sentmessages.append (args) def close (self): self.closed = True class Session: def __init__ (self, transport=FakeMessageTransport()): self.history = [] self.pagecache = {} self.save_tmp_file = False self.protocol = MessageProtocol(transport) def show (self, page): self.history.append (page) self.reload (page) def getpage (self, graph_id): page = self.history[graph_id] result = None try: result = self.pagecache[page] except KeyError: result = page.content() self.pagecache.clear() # a cache of a single entry should be enough self.pagecache[page] = result return result def reload (self,page): if self.save_tmp_file: f = open(save_tmp_file, 'w') f.write(page.source) f.close() self.protocol.send_page (page) def send_error(self, e): try: errmsg = str(e) if errmsg: errmsg = '%s: %s' % (e.__class__.__name__, errmsg) else: errmsg = '%s' % (e.__class__.__name__,) self.transport.sendmsg(msgstruct.CMSG_SAY, errmsg) except Exception: pass #from dotviewer import msgstruct class MessageProtocol: INIT = []#(msgstruct.CMSG_INIT, msgstruct.MAGIC)] def __init__ (self, transport): self.transport = transport self.send_messages = self.first_message #dynamic state pattern def first_message (self, message): self._send_messages ((MessageProtocol.INIT)) self.send_messages = self._send_messages def _send_messages (self, messages): ioerror = None for msg in messages: try: self.transport.sendmsg (*msg) except IOError, ioerror: print >>sys.stderr, "Error: sending ", msg , str(ioerror) break return #XXX # wait for MSG_OK or MSG_ERROR try: while True: msg = self.transport.recvmsg() if msg[0] == msgstruct.MSG_OK: break except EOFError: ioerror = IOError("connexion unexpectedly closed " "(graphserver crash?)") if ioerror is not None: raise ioerror def send_page (self, page): import graphparse messages = graphparse.parse_dot(0, page.content(), page.links,getattr(page, 'fixedfont', False)) self.send_messages (messages) class MessageDrivenPainter: def __init__ (self,service): self.service = service def process_all (self, messages): try: for msg in messages: self.process_message (msg) except EOFError: from drawgraph import display_async_quit display_async_quit() def generate_layout (self, messages): try: for msg in messages: self.process_message (msg) except EOFError, errmsg: print "Cannot process ", msg return self.newlayout def process_message (self, msg): fn = self.MESSAGES.get(msg[0]) if fn: fn(self, *msg[1:]) else: self.log("unknown message code %r" % (msg[0],)) def log(self, info): print >> sys.stderr, info def cmsg_start_graph(self, graph_id, scale, width, height, *rest): from drawgraph import GraphLayout self.newlayout = GraphLayout(float(scale), float(width), float(height)) def cmsg_add_node(self, *args): self.newlayout.add_node(*args) def cmsg_add_edge(self, *args): self.newlayout.add_edge(*args) def cmsg_add_link(self, word, *info): if len(info) == 1: info = info[0] elif len(info) >= 4: info = (info[0], info[1:4]) self.newlayout.links[word] = info def cmsg_fixed_font(self, *rest): self.newlayout.fixedfont = True def cmsg_stop_graph(self, *rest): self.service.post_event (layout=self.newlayout) def cmsg_missing_link(self, *rest): self.setlayout(None) def cmsg_say(self, errmsg, *rest): self.service.post_event (say=errmsg) MESSAGES = { msgstruct.CMSG_START_GRAPH: cmsg_start_graph, msgstruct.CMSG_ADD_NODE: cmsg_add_node, msgstruct.CMSG_ADD_EDGE: cmsg_add_edge, msgstruct.CMSG_ADD_LINK: cmsg_add_link, msgstruct.CMSG_FIXED_FONT: cmsg_fixed_font, msgstruct.CMSG_STOP_GRAPH: cmsg_stop_graph, msgstruct.CMSG_MISSING_LINK:cmsg_missing_link, msgstruct.CMSG_SAY: cmsg_say, }