git.fiddlerwoaroof.com
Browse code

redoing some accidentally reverted changes

Ed L authored on 01/06/2011 01:52:22
Showing 1 changed files
... ...
@@ -37,6 +37,7 @@ import copy
37 37
 import time
38 38
 import itertools
39 39
 import jsonrpc.jsonutil
40
+import json
40 41
 
41 42
 # Twisted imports
42 43
 from twisted.web import server
... ...
@@ -55,8 +56,15 @@ class ServerEvents(object):
55 56
 		self.server = jsonrpc
56 57
 
57 58
 	def callmethod(self, request, method, kwargs, args, **kw):
58
-		'''Override to implement the methods the server will make available'''
59
-		return 'Test Result'
59
+		'''Finds the method and calls it with the specified args'''
60
+		method = self.findmethod(method)
61
+		if method is None: raise MethodNotFound
62
+
63
+		return method(*args, **kwargs)
64
+
65
+	def findmethod(self, method):
66
+		'''Override to allow server to define methods'''
67
+		return lambda *a, **kw: 'Test Data'
60 68
 
61 69
 	def processrequest(self, result, args):
62 70
 		'''Override to implement custom handling of the method result and request'''
... ...
@@ -66,8 +74,32 @@ class ServerEvents(object):
66 74
 		'''Override to implement custom error handling'''
67 75
 		pass
68 76
 
77
+	def processcontent(self, content, request):
78
+		'''Given the freshly decoded content of the request, return what content should be used'''
79
+		return content
80
+
81
+
82
+class ServerError(Exception):
83
+	code = 0
84
+	msg = ""
85
+	id = None
69 86
 
87
+	def json_equivalent(self):
88
+		return dict(jsonrpc="2.0", error=dict(code=self.code, message=self.msg), id=self.id)
89
+	def __str__(self):
90
+		return jsonrpc.jsonutil.encode(self)
70 91
 
92
+class InvalidRequest(ServerError):
93
+	code = -32600
94
+	msg = "Invalid Request."
95
+
96
+class MethodNotFound(ServerError):
97
+	code = -32601
98
+	msg = "Procedure not found."
99
+
100
+class ParseError(ServerError):
101
+	code = -32700
102
+	msg = "Parse error."
71 103
 
72 104
 ## Base class providing a JSON-RPC 2.0 implementation with 2 customizable hooks
73 105
 class JSON_RPC(Resource):
... ...
@@ -87,26 +119,34 @@ class JSON_RPC(Resource):
87 119
 		self.customize(self.eventhandler)
88 120
 		Resource.__init__(self,*args, **kwargs)
89 121
 
90
-	def _parse_data(self, content):
91
-		if content.get('jsonrpc') != '2.0': raise ValueError, 'wrong JSON-RPC version'
92
-		method = content.get('method')
93
-		kwargs = content.get('params', {})
94
-		args = ()
95
-		if not isinstance(kwargs, dict):
96
-			args = tuple(kwargs)
97
-			kwargs = {}
98
-		else:
99
-			args = kwargs.pop('__args', args)
100
-		kwargs = dict( (str(k), v) for k,v in kwargs.items() )
101
-		return method, kwargs, args
122
+
123
+	def render(self, request):
124
+		#move to emen2 event handler
125
+		#ctxid = request.getCookie("ctxid") or request.args.get("ctxid", [None])[0]
126
+		#host = request.getClientIP()
127
+
128
+		request.content.seek(0, 0)
129
+		try:
130
+			try:
131
+				content = jsonrpc.jsonutil.decode(request.content.read())
132
+			except ValueError: raise ParseError
133
+			content = self.eventhandler.processcontent(content, request)
134
+			d = threads.deferToThread(self._action, request, content)
135
+			d.addCallback(self._cbRender, request)
136
+			d.addErrback(self._ebRender, request, content.get('id') if hasattr(content, 'get') else None)
137
+		except BaseException, e:
138
+			self._ebRender(e, request, None)
139
+
140
+		return server.NOT_DONE_YET
102 141
 
103 142
 
104 143
 	def _cbRender(self, result, request):
105
-		request.setHeader("content-type", 'application/json')
106
-		request.setResponseCode(200)
107
-		result = jsonrpc.jsonutil.encode(result).encode('utf-8')
108
-		request.setHeader("content-length", len(result))
109
-		request.write(result)
144
+		if result is not None:
145
+			request.setHeader("content-type", 'application/json')
146
+			request.setResponseCode(200)
147
+			result = jsonrpc.jsonutil.encode(result).encode('utf-8')
148
+			request.setHeader("content-length", len(result))
149
+			request.write(result)
110 150
 		request.finish()
111 151
 
112 152
 	def _ebRender(self, result, request, id, finish=True):
... ...
@@ -127,70 +167,69 @@ class JSON_RPC(Resource):
127 167
 		request.write(result)
128 168
 		if finish: request.finish()
129 169
 
170
+	def _parse_data(self, content):
171
+		if content.get('jsonrpc') != '2.0': raise InvalidRequest
130 172
 
131
-	def get_result(method_result, content, template):
132
-		template['error'].update(
133
-				code=0,
134
-				message=cgi.escape(' '.join(str(x) for x in method_result.value)),
135
-				data=content
136
-		)
137
-		template['id'] = content.get(id)
138
-		return template
139
-
173
+		method = content.get('method')
174
+		if not isinstance(method, (str, unicode)): raise InvalidRequest
140 175
 
176
+		kwargs = content.get('params', {})
177
+		args = ()
178
+		if not isinstance(kwargs, dict):
179
+			args = tuple(kwargs)
180
+			kwargs = {}
181
+		else:
182
+			args = kwargs.pop('__args', args)
183
+		kwargs = dict( (str(k), v) for k,v in kwargs.items() )
141 184
 
142
-	def render(self, request):
143
-		ctxid = request.getCookie("ctxid") or request.args.get("ctxid", [None])[0]
144
-		host = request.getClientIP()
185
+		return method, kwargs, args
145 186
 
146
-		request.content.seek(0, 0)
147
-		try:
148
-			content = jsonrpc.jsonutil.decode(request.content.read())
149
-			d = threads.deferToThread(self._action, request, content, ctxid=ctxid, host=host)
150
-			d.addCallback(self._cbRender, request)
151
-			d.addErrback(self._ebRender, request, content.get('id') if hasattr(content, 'get') else None)
152
-		except BaseException, e:
153
-			self._ebRender(e, request, None)
154 187
 
155
-		return server.NOT_DONE_YET
156 188
 
157 189
 	def render_error(self, e, id):
158
-		err = dict(
159
-			jsonrpc='2.0',
160
-			id = id,
161
-			error= dict(
162
-				code=0,
163
-				message=str(e),
164
-				data = e.args
165
-		))
190
+		if isinstance(e, ServerError):
191
+			e.id = id
192
+			err = e.json_equivalent()
193
+		else:
194
+			err = dict(
195
+				jsonrpc='2.0',
196
+				id = id,
197
+				error= dict(
198
+					code=0,
199
+					message=str(e),
200
+					data = e.args
201
+			))
202
+
166 203
 		return err
167 204
 
168 205
 
169 206
 
170
-	def _action(self, request, contents, **kw):
207
+	def _action(self, request, contents):
171 208
 		result = []
172 209
 		ol = (True if isinstance(contents, list) else False)
173
-		if not ol:
174
-			contents = [contents]
210
+		if not ol: contents = [contents]
211
+
212
+		if contents == []: raise InvalidRequest
175 213
 
176 214
 		for content in contents:
177 215
 			try:
178
-				res = dict(
179
-					jsonrpc = '2.0',
180
-					id = content.get('id'),
181
-					result = self.eventhandler.callmethod(request, *self._parse_data(content), **kw)
182
-				)
216
+				res = dict(jsonrpc='2.0', id=content.get('id'), result=self.eventhandler.callmethod(request, *self._parse_data(content)))
183 217
 
184 218
 				res = self.eventhandler.processrequest(res, request.args)
185 219
 
186
-				result.append(res)
220
+				if res['id'] is not None: result.append(res)
187 221
 			except Exception, e:
188 222
 				err = self.render_error(e, content.get('id'))
189
-				result.append(err)
223
+				if err['id'] is not None: result.append(err)
224
+
190 225
 
191 226
 
192 227
 		self.eventhandler.log(result, request)
193 228
 
194
-		return ( result if ol else result[0] )
229
+		if result != []:
230
+			if not ol: result = result[0]
231
+		else: result = None
232
+
233
+		return result
195 234
 
196 235