1 """GNUmed scripting listener.
2
3 This module implements threaded listening for scripting.
4 """
5
6
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
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 = 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
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:
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
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:
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
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187