SF.net SVN: fclient:[818] trunk/fclient/src/fclient/impl/lib/qt4ex/ singleapp.py
Status: Pre-Alpha
Brought to you by:
jurner
From: <jU...@us...> - 2008-07-30 10:47:12
|
Revision: 818 http://fclient.svn.sourceforge.net/fclient/?rev=818&view=rev Author: jUrner Date: 2008-07-30 10:47:21 +0000 (Wed, 30 Jul 2008) Log Message: ----------- add a module to control single application stuff Added Paths: ----------- trunk/fclient/src/fclient/impl/lib/qt4ex/singleapp.py Added: trunk/fclient/src/fclient/impl/lib/qt4ex/singleapp.py =================================================================== --- trunk/fclient/src/fclient/impl/lib/qt4ex/singleapp.py (rev 0) +++ trunk/fclient/src/fclient/impl/lib/qt4ex/singleapp.py 2008-07-30 10:47:21 UTC (rev 818) @@ -0,0 +1,106 @@ +"""making resonably shure only one appliaction is running at a time""" + + +import socket +import thread +#********************************************************************** +# +#********************************************************************** +class ErrorCanNotConnect(Exception): + """exception raised in cace SignleApp can not connect to the socket or something unexpected happens in the communication""" + +class ErrorOtherAppIsRunning(Exception): + """exception raised when SingleApp detects another application is already running""" + + +class SingleApp(object): + """Class doing its best to enshure only one instance of an application + is running at the same time + + @note: the class uses a socket to exchange data in between applications. firewalls + (...) may not like this. + @note: a carefuly chosen magic string to exchange may help to reduce the chance + of accidential collisions with other applications + @note: race conditions? yes + """ + + def __init__(self, host=None, port=None, magicToSend=None, magicToRespond=None, userData=None): + """ + @param host: host to establish the connection to + @param port: port to use for the connection + @param magicToSend: magic string a client should send to the server + @param magicToRespond: magic string the server should send in response + @param userData: any data you want to associate to the SignleApp object + """ + + if host is None or port is None or magicToSend is None or magicToRespond is None: + raise ValueError('All keyword arguments except userData are mandatory. This is just for better looks') + self.host = host + self.port = port + self.magicToSend = magicToSend + self.magicToRespond = magicToRespond + self.isServerRunning = False + self.socket = None + self.userData = userData + + + def _runServer(self): + # start server and listen to incoming connections + while True: + self.socket.listen(1) + conn, addr = self.socket.accept() + # NOTE: my best guess here is that we can not loop here to make shure we + # get some data. mybe the other end of the pipe plays dead + data = conn.recv(len(self.magicToSend)) + if data == self.magicToSend: + self.onOtherAppIsStarting() + conn.send(self.magicToRespond) + conn.close() + self.socket.close() + self.socket = None + self.isServerRunning = False + + + def start(self): + """starts SingleApp + + @raise ErrorCanNotConnect: + @raise ErrorOtherAppIsRunning: + """ + # try to bind socket as server + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + self.socket.bind((self.host, self.port)) + except socket.error, details: + # assume address is already in use, try to connect to it + try: + self.socket.connect((self.host, self.port)) + except socket.error, details: + # ups, neither way works. we give up here + raise ErrorCanNotConnect(details) + try: + # try to find out who is serving + self.socket.settimeout(0.5) + self.socket.sendall(self.magicToSend) + # NOTE: my best guess here is that we can not loop here to make shure we + # get some data. mybe the other end of the pipe plays dead + data = self.socket.recv(len(self.magicToRespond)) + if data == self.magicToRespond: + raise ErrorOtherAppIsRunning() + except socket.timeout: + raise ErrorCanNotConnect(details) + finally: + self.socket.close() + self.socket = None + else: + self.isServerRunning = True + thread.start_new_thread(self._runServer, ()) + + def onOtherAppIsStarting(self): + """called when another application using the same magic string is conncting to our server""" + print 'another app of the same kind is connecting to us' + + + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |