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  __version__ = "$Revision: 1.7 $" 
  7  __author__ = "K.Hilbert <karsten.hilbert@gmx.net>" 
  8   
  9  import sys, time, threading, select, logging 
 10  import xmlrpc.server 
 11   
 12   
 13  _log = logging.getLogger('gm.scripting') 
 14   
 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 = xmlrpc.server.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 Exception: 77 pass 78 except Exception: 79 print sys.exc_info() 80 81 self._thread = None 82 83 try: 84 self._server.socket.shutdown(2) 85 except Exception: 86 _log.exception('cannot cleanly shutdown(5) scripting listener socket') 87 88 try: 89 self._server.socket.close() 90 except Exception: 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 Exception: 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 import xmlrpc.client 131 132 #-------------------------------
133 - class runner:
134 - def tell_time(self):
135 return time.asctime()
136 #------------------------------- 137 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'): 138 import xmlrpclib 139 140 try: 141 listener = cScriptingListener(macro_executor=runner(), port=9999) 142 except Exception: 143 _log.exception('cannot instantiate scripting listener') 144 sys.exit(1) 145 146 s = xmlrpclib.client.ServerProxy('http://localhost:9999') 147 try: 148 t = s.tell_time() 149 print t 150 except Exception: 151 _log.exception('cannot interact with server') 152 153 listener.shutdown() 154