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