#! /usr/bin/env python"""Graph server.From the command-line it's easier to use sshgraphserver.py instead of this."""importsysimportmsgstructfromcStringIOimportStringIOclassServer(object):def__init__(self,io):self.io=ioself.display=Nonedefrun(self,only_one_graph=False):# wait for the CMSG_INIT messagemsg=self.io.recvmsg()ifmsg[0]!=msgstruct.CMSG_INITormsg[1]!=msgstruct.MAGIC:raiseValueError("bad MAGIC number")# process messages until we have a pygame displaywhileself.displayisNone:self.process_next_message()# start a background thread to process further messagesifnotonly_one_graph:importthreadthread.start_new_thread(self.process_all_messages,())# give control to pygameself.display.run1()defprocess_all_messages(self):try:whileTrue:self.process_next_message()exceptEOFError:fromdrawgraphimportdisplay_async_quitdisplay_async_quit()defprocess_next_message(self):msg=self.io.recvmsg()fn=self.MESSAGES.get(msg[0])iffn:fn(self,*msg[1:])else:self.log("unknown message code %r"%(msg[0],))deflog(self,info):print>>sys.stderr,infodefsetlayout(self,layout):ifself.displayisNone:# make the initial displayfromgraphdisplayimportGraphDisplayself.display=GraphDisplay(layout)else:# send an async command to the display running the main threadfromdrawgraphimportdisplay_async_cmddisplay_async_cmd(layout=layout)defcmsg_start_graph(self,graph_id,scale,width,height,*rest):fromdrawgraphimportGraphLayoutself.newlayout=GraphLayout(float(scale),float(width),float(height))defrequest_reload():self.io.sendmsg(msgstruct.MSG_RELOAD,graph_id)defrequest_followlink(word):self.io.sendmsg(msgstruct.MSG_FOLLOW_LINK,graph_id,word)self.newlayout.request_reload=request_reloadself.newlayout.request_followlink=request_followlinkdefcmsg_add_node(self,*args):self.newlayout.add_node(*args)defcmsg_add_edge(self,*args):self.newlayout.add_edge(*args)defcmsg_add_link(self,word,*info):iflen(info)==1:info=info[0]eliflen(info)>=4:info=(info[0],info[1:4])self.newlayout.links[word]=infodefcmsg_fixed_font(self,*rest):self.newlayout.fixedfont=Truedefcmsg_stop_graph(self,*rest):self.setlayout(self.newlayout)delself.newlayoutself.io.sendmsg(msgstruct.MSG_OK)defcmsg_missing_link(self,*rest):self.setlayout(None)defcmsg_say(self,errmsg,*rest):fromdrawgraphimportdisplay_async_cmddisplay_async_cmd(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,}deflisten_server(local_address,s1=None):importsocket,graphclient,threadifisinstance(local_address,str):if':'inlocal_address:interface,port=local_address.split(':')else:interface,port='',local_addresslocal_address=interface,int(port)ifs1isNone:s1=socket.socket()s1.bind(local_address)s1.listen(5)print'listening on %r...'%(s1.getsockname(),)whileTrue:conn,addr=s1.accept()print'accepted connection from %r'%(addr,)sock_io=msgstruct.SocketIO(conn)handler_io=graphclient.spawn_local_handler()thread.start_new_thread(copy_all,(sock_io,handler_io))thread.start_new_thread(copy_all,(handler_io,sock_io))delsock_io,handler_io,conndefcopy_all(io1,io2):try:whileTrue:io2.sendall(io1.recv())exceptEOFError:io2.close_sending()if__name__=='__main__':iflen(sys.argv)!=2:print>>sys.stderr,__doc__sys.exit(2)ifsys.argv[1]=='--stdio':# a one-shot server running on stdin/stdoutio=msgstruct.FileIO(sys.stdin,sys.stdout)srv=Server(io)try:srv.run()exceptException,e:importtracebackf=StringIO()traceback.print_exc(file=f)# try to add some explanationshelp=(" | if you want to debug on a remote machine, see\n"" | instructions in dotviewer/sshgraphserver.py\n")try:importpygameexceptImportError:f.seek(0)f.truncate()print>>f,"ImportError"print>>f," | Pygame is not installed; either install it, or"print>>f,helpelse:ifisinstance(e,pygame.error):print>>f,helpio.sendmsg(msgstruct.MSG_ERROR,f.getvalue())else:listen_server(sys.argv[1])