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
17
18
19
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
30
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
38 self._poll_interval = poll_interval
39
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
60
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
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
94
96 """The actual thread code."""
97 while 1:
98 if self._quit_lock.acquire(0):
99 break
100 time.sleep(0.35)
101 if self._quit_lock.acquire(0):
102 break
103
104 ready_input_sockets = select.select([self._server.socket], [], [], self._poll_interval)[0]
105
106 if len(ready_input_sockets) != 0:
107
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
124 return
125
126
127
128 if __name__ == "__main__":
129
130 import xmlrpc.client
131
132
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