File: gmScriptingListener.py

package info (click to toggle)
gnumed-client 0.2.2a-3
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 3,448 kB
  • ctags: 3,620
  • sloc: python: 32,178; sh: 231; makefile: 97
file content (149 lines) | stat: -rw-r--r-- 4,855 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""GnuMed scripting listener.

This module implements threaded listening for scripting.
"""
#=====================================================================
# $Source: /sources/gnumed/gnumed/gnumed/client/pycommon/gmScriptingListener.py,v $
__version__ = "$Revision: 1.2 $"
__author__ = "K.Hilbert <karsten.hilbert@gmx.net>"

import sys, time, threading, SimpleXMLRPCServer, select
import gmDispatcher, gmLog, gmExceptions
_log = gmLog.gmDefLog

#=====================================================================
class cScriptingListener:
	def __init__(self, port = 9999, macro_executor = None, poll_interval = 3):
		if macro_executor is None:
			raise gmExceptions.ConstructorError, "need macro executor object parameter"
		# listener thread will regularly try to acquire
		# this lock, when it succeeds it will quit
		self._quit_lock = threading.Lock()
		if not self._quit_lock.acquire(0):
			_log.Log(gmLog.lErr, 'cannot acquire thread quit lock !?! aborting')
			raise gmExceptions.ConstructorError, "cannot acquire thread quit-lock"
		# check for data every 'poll_interval' seconds
		self._poll_interval = poll_interval
		# setup XML-RPC server
		if not self.__start_server(port, macro_executor):
			raise gmExceptions.ConstructorError, "cannot start XML-RPC server on port [%s]" % port
		# start thread
		if not self.__start_thread():
			raise gmExceptions.ConstructorError, "cannot start listener thread"
	#-------------------------------
	def __del__(self):
		# allow listener thread to acquire quit lock
		try:
			self._quit_lock.release()
			# give the thread time to terminate
			if self._thread is not None:
				self._thread.join(self._poll_interval+2)
		except:	pass
		# ???
		try:
			self._server.socket.shutdown(2)
		except: pass
		try:
			self._server.socket.close()
		except: pass
		try:
			del self._server
		except: pass
	#-------------------------------
	def __start_server(self, a_port, a_macro_executor):
		self._port = int(a_port)
		self._macro_executor = a_macro_executor
		try:
			self._server = SimpleXMLRPCServer.SimpleXMLRPCServer(addr=('127.0.0.1', self._port), logRequests=False)
			self._server.register_instance(self._macro_executor)
			self._server.allow_reuse_address = True
		except:
			_log.LogException('cannot start XML-RPC server [localhost:%s]' % a_port, sys.exc_info())
			return None
		return 1
	#-------------------------------
	# public API
	#-------------------------------
	def tell_thread_to_stop(self):
		self._quit_lock.release()
	#-------------------------------
	# internal helpers
	#-------------------------------
	def __start_thread(self):
		try:
			self._thread = threading.Thread(target = self._process_RPCs)
			self._thread.start()
		except StandardError:
			_log.LogException("cannot start thread", sys.exc_info(), verbose=1)
			return None
		return 1
	#-------------------------------
	# the actual thread code
	#-------------------------------
	def _process_RPCs(self):
		while 1:
			if self._quit_lock.acquire(0):
				break
			time.sleep(0.35)					# give others time to acquire lock
			if self._quit_lock.acquire(0):
				break
			# wait at most self.__poll_interval for new data
			ready_input_sockets = select.select([self._server.socket], [], [], self._poll_interval)[0]
			# any input available ?
			if len(ready_input_sockets) != 0:
				# we may be in __del__ so we might fail here
				try:
					self._server.handle_request()
				except:
					print "cannot serve RPC"
					break
				if self._quit_lock.acquire(0):
					break
				time.sleep(0.25)
				if self._quit_lock.acquire(0):
					break
			else:
				time.sleep(0.35)
				if self._quit_lock.acquire(0):
					break

		self._thread = None
#=====================================================================
# main
#=====================================================================
if __name__ == "__main__":
	_log.SetAllLogLevels(gmLog.lData)

_log.Log(gmLog.lData, __version__)

if __name__ == "__main__":
	import xmlrpclib
	#-------------------------------
	class runner:
		def tell_time(self):
			return time.asctime()
	#-------------------------------
	listener = cScriptingListener(macro_executor=runner(), port=9999)
	s = xmlrpclib.ServerProxy('http://localhost:9999')
	t = s.tell_time()
	print t
	listener.tell_thread_to_stop()
#=====================================================================
# $Log: gmScriptingListener.py,v $
# Revision 1.2  2004/09/13 08:51:03  ncq
# - make sure port is an integer
# - start XML RPC server with logRequests=False
# - socket allow_reuse_address
#
# Revision 1.1  2004/02/25 09:30:13  ncq
# - moved here from python-common
#
# Revision 1.3  2004/02/05 23:46:21  ncq
# - use serverproxy() instead of server() as is recommended
#
# Revision 1.2  2004/02/05 18:40:01  ncq
# - quit thread if we can't handle_request()
#
# Revision 1.1  2004/02/02 21:58:20  ncq
# - first cut
#