Package Gnumed :: Package pycommon :: Module gmScriptingListener
[frames] | no frames]

Source Code for Module Gnumed.pycommon.gmScriptingListener

  1  """GNUmed scripting listener. 
  2   
  3  This module implements threaded listening for scripting. 
  4  """ 
  5  #===================================================================== 
  6  # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/pycommon/gmScriptingListener.py,v $ 
  7  __version__ = "$Revision: 1.7 $" 
  8  __author__ = "K.Hilbert <karsten.hilbert@gmx.net>" 
  9   
 10  import sys, time, threading, SimpleXMLRPCServer, select, logging 
 11   
 12   
 13  _log = logging.getLogger('gm.scripting') 
 14  _log.info(__version__) 
 15  #===================================================================== 
16 -class cScriptingListener:
17 18 # FIXME: this should use /var/run/gnumed/xml-rpc-port.pid 19 # FIXME: and store the current port there 20 21 """This class handles how GNUmed listens for external requests. 22 23 It starts an XML-RPC server and forks a thread which 24 listens for incoming requests. Those requests are then 25 handed over to a macro executor and the results handed 26 back to the caller. 27 """
28 - def __init__(self, port = None, macro_executor = None, poll_interval = 3):
29 # listener thread will regularly try to acquire 30 # this lock, when it succeeds it will quit 31 self._quit_lock = threading.Lock() 32 if not self._quit_lock.acquire(0): 33 _log.error('cannot acquire thread quit lock !?! aborting') 34 import thread 35 raise thread.error("cannot acquire thread quit-lock") 36 37 # check for data every 'poll_interval' seconds 38 self._poll_interval = poll_interval 39 # localhost only for somewhat better security 40 self._listener_address = '127.0.0.1' 41 self._port = int(port) 42 self._macro_executor = macro_executor 43 44 self._server = SimpleXMLRPCServer.SimpleXMLRPCServer(addr=(self._listener_address, self._port), logRequests=False) 45 self._server.register_instance(self._macro_executor) 46 self._server.allow_reuse_address = True 47 48 self._thread = threading.Thread ( 49 target = self._process_RPCs, 50 name = self.__class__.__name__ 51 ) 52 self._thread.setDaemon(True) 53 self._thread.start() 54 55 _log.info('scripting listener started on [%s:%s]' % (self._listener_address, self._port)) 56 _log.info('macro executor: %s' % self._macro_executor) 57 _log.info('poll interval: %s seconds', self._poll_interval)
58 #------------------------------- 59 # public API 60 #-------------------------------
61 - def shutdown(self):
62 """Cleanly shut down. Complement to __init__().""" 63 64 if self._thread is None: 65 return 66 67 _log.info('stopping frontend scripting listener thread') 68 self._quit_lock.release() 69 try: 70 # give the worker thread time to terminate 71 self._thread.join(self._poll_interval+5) 72 try: 73 if self._thread.isAlive(): 74 _log.error('listener thread still alive after join()') 75 _log.debug('active threads: %s' % threading.enumerate()) 76 except: 77 pass 78 except: 79 print sys.exc_info() 80 81 self._thread = None 82 83 try: 84 self._server.socket.shutdown(2) 85 except: 86 _log.exception('cannot cleanly shutdown(5) scripting listener socket') 87 88 try: 89 self._server.socket.close() 90 except: 91 _log.exception('cannot cleanly close() scripting listener socket')
92 #------------------------------- 93 # internal helpers 94 #-------------------------------
95 - def _process_RPCs(self):
96 """The actual thread code.""" 97 while 1: 98 if self._quit_lock.acquire(0): 99 break 100 time.sleep(0.35) # give others time to acquire lock 101 if self._quit_lock.acquire(0): 102 break 103 # wait at most self.__poll_interval for new data 104 ready_input_sockets = select.select([self._server.socket], [], [], self._poll_interval)[0] 105 # any input available ? 106 if len(ready_input_sockets) != 0: 107 # we may be in __del__ so we might fail here 108 try: 109 self._server.handle_request() 110 except: 111 print "cannot serve RPC" 112 break 113 if self._quit_lock.acquire(0): 114 break 115 time.sleep(0.25) 116 if self._quit_lock.acquire(0): 117 break 118 else: 119 time.sleep(0.35) 120 if self._quit_lock.acquire(0): 121 break 122 123 # exit thread activity 124 return
125 #===================================================================== 126 # main 127 #===================================================================== 128 if __name__ == "__main__": 129 130 #-------------------------------
131 - class runner:
132 - def tell_time(self):
133 return time.asctime()
134 #------------------------------- 135 if (len(sys.argv) > 1) and (sys.argv[1] == u'test'): 136 import xmlrpclib 137 138 try: 139 listener = cScriptingListener(macro_executor=runner(), port=9999) 140 except: 141 _log.exception('cannot instantiate scripting listener') 142 sys.exit(1) 143 144 s = xmlrpclib.ServerProxy('http://localhost:9999') 145 try: 146 t = s.tell_time() 147 print t 148 except: 149 _log.exception('cannot interact with server') 150 151 listener.shutdown() 152 #===================================================================== 153 # $Log: gmScriptingListener.py,v $ 154 # Revision 1.7 2009-01-15 11:34:17 ncq 155 # - improved logging 156 # 157 # Revision 1.6 2008/06/23 21:49:58 ncq 158 # - clean up thread handling 159 # 160 # Revision 1.5 2007/12/12 16:17:16 ncq 161 # - better logger names 162 # 163 # Revision 1.4 2007/12/11 15:39:01 ncq 164 # - use std lib logging 165 # 166 # Revision 1.3 2007/12/03 20:43:53 ncq 167 # - lots of cleanup 168 # - fix/enhance test suite 169 # 170 # Revision 1.2 2004/09/13 08:51:03 ncq 171 # - make sure port is an integer 172 # - start XML RPC server with logRequests=False 173 # - socket allow_reuse_address 174 # 175 # Revision 1.1 2004/02/25 09:30:13 ncq 176 # - moved here from python-common 177 # 178 # Revision 1.3 2004/02/05 23:46:21 ncq 179 # - use serverproxy() instead of server() as is recommended 180 # 181 # Revision 1.2 2004/02/05 18:40:01 ncq 182 # - quit thread if we can't handle_request() 183 # 184 # Revision 1.1 2004/02/02 21:58:20 ncq 185 # - first cut 186 # 187