/examples/jsonrpc/public/services/jsonrpc/__init__.py
Python | 241 lines | 203 code | 13 blank | 25 comment | 4 complexity | d8401018c999557644a64108fa041064 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
1""" 2 Copyright (c) 2006 Jan-Klaas Kollhof 3 4 This file is part of jsonrpc. 5 6 jsonrpc is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published by 8 the Free Software Foundation; either version 2.1 of the License, or 9 (at your option) any later version. 10 11 This software is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with this software; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19""" 20 21from threading import Event, Lock 22 23from errors import * 24 25from simplejson import JSONDecoder, JSONEncoder 26 27 28class JSONRPCEncoder(JSONEncoder): 29 def default(self, obj): 30 if isinstance(obj, JSONRPCError): 31 return obj.__class__.__name__ 32 else: 33 return JSONEncoder.default(self, obj) 34 35 36class Timeout(Exception): 37 pass 38 39class ResponseEvent: 40 """Event which is fired when the response is returned for a request. 41 42 For each request sent this event is created. 43 An application can wait for the event to create a blocking request. 44 """ 45 def __init__(self): 46 self.__evt = Event() 47 48 def waiting(self): 49 return not self.__evt.isSet() 50 51 def waitForResponse(self, timeOut=None): 52 """blocks until the response arrived or timeout is reached.""" 53 self.__evt.wait(timeOut) 54 if self.waiting(): 55 raise Timeout() 56 else: 57 if self.response["error"]: 58 raise Exception(self.response["error"]) 59 else: 60 return self.response["result"] 61 62 def handleResponse(self, resp): 63 self.response = resp 64 self.__evt.set() 65 66 67class SimpleMessageHandler: 68 def __init__(self, DecoderClass=JSONDecoder, EncoderClass=JSONRPCEncoder, messageDelimiter=""): 69 self.decoder = DecoderClass() 70 self.encoder = EncoderClass() 71 self.partialData = "" 72 self.respEvents={} 73 self.respLock = Lock() 74 self.messageDelimiter=messageDelimiter 75 76 def close(self): 77 pass 78 79 def send(self, data): 80 pass 81 82 def sendMessage(self, msg): 83 self.send(self.encoder.encode(msg) + self.messageDelimiter) 84 85 def handlePartialData(self, data): 86 data = self.partialData + data.replace("\r","").replace("\n", "") 87 msgs=[] 88 while data != "": 89 pos = data.find("{") 90 if(pos > -1): 91 data=data[pos:] 92 try: 93 (obj, pos) = self.decoder.raw_decode(data) 94 data = data[pos:] 95 msgs.append(obj) 96 except: 97 break 98 else: 99 break 100 self.partialData = data 101 102 self.handleMessages(msgs) 103 104 def sendNotify(self, name, args): 105 """sends a notification object to the peer""" 106 self.sendMessage({"method":name, "params": args}) 107 108 def sendRequest(self, name, args): 109 """sends a request to the peer""" 110 (respEvt, id) = self.newResponseEvent() 111 self.sendMessage({"id":id, "method":name, "params": args}) 112 return respEvt 113 114 def sendResponse(self, id, result, error): 115 """sends a response to the peer""" 116 self.sendMessage({"result":result, "error": error, "id":id}) 117 118 def newResponseEvent(self): 119 """creates a response event and adds it to a waiting list 120 When the reponse arrives it will be removed from the list. 121 """ 122 respEvt = ResponseEvent() 123 self.respLock.acquire() 124 eid = id(respEvt) 125 self.respEvents[eid] = respEvt 126 self.respLock.release() 127 return (respEvt,eid) 128 129 def handleMessages(self, msgs): 130 for msg in msgs: 131 if msg.has_key("method") and msg.has_key("params"): 132 if msg.has_key("id"): 133 if msg["id"]: 134 self.handleRequest(msg) 135 else: 136 self.handleNotification(msg) 137 else: 138 self.handleNotification(msg) 139 elif msg.has_key("result") and msg.has_key("error"): 140 self.handleResponse(msg) 141 else:#unknown object 142 self.sendResponse(None, InvalidJSONMessage()) 143 self.close() 144 145 def handleResponse(self, resp): 146 """handles a response by fireing the response event for the response coming in""" 147 id=resp["id"] 148 evt = self.respEvents[id] 149 del(self.respEvents[id]) 150 evt.handleResponse(resp) 151 152 def handleRequest(self, request): 153 pass 154 def handleNotification(self, notification): 155 pass 156 157 158import re 159NameAllowedRegExp=re.compile("^[a-zA-Z]\w*$") 160def nameAllowed(name): 161 """checks if a name is allowed. 162 """ 163 if NameAllowedRegExp.match(name): 164 return 1 165 else: 166 return 0 167 168def getMethodByName(obj, name): 169 170 """searches for an object with the name given inside the object given. 171 "obj.child.meth" will return the meth obj. 172 """ 173 try:#to get a method by asking the service 174 obj = obj._getMethodByName(name) 175 except: 176 #assumed a childObject is ment 177 #split the name from objName.childObjName... -> [objName, childObjName, ...] 178 #and get all objects up to the last in list with name checking from the service object 179 names = name.split(".") 180 for name in names: 181 if nameAllowed(name): 182 obj = getattr(obj, name) 183 else: 184 raise MethodNameNotAllowed() 185 186 return obj 187 188 189 190class SimpleServiceHandler(SimpleMessageHandler): 191 def __init__(self, service, DecoderClass=JSONDecoder, EncoderClass=JSONRPCEncoder, messageDelimiter=""): 192 self.service = service 193 SimpleMessageHandler.__init__(self, DecoderClass, EncoderClass, messageDelimiter) 194 try: 195 service._newConnection(self) 196 except: 197 pass 198 199 def close(self): 200 try: 201 self.service._closingConnection(self) 202 except: 203 pass 204 205 def handleRequest(self, req): 206 """handles a request by calling the appropriete method the service exposes""" 207 name = req["method"] 208 params = req["params"] 209 id=req["id"] 210 obj=None 211 try: #to get a callable obj 212 obj = getMethodByName(self.service, name) 213 except MethodNameNotAllowed,e: 214 self.sendResponse(id, None, e) 215 except: 216 self.sendResponse(id, None, MethodNotFound()) 217 if obj: 218 try: #to call the object with parameters 219 rslt = obj(*params) 220 self.sendResponse(id, rslt, None) 221 except TypeError: # wrong arguments 222 #todo what if the TypeError was not thrown directly by the callable obj 223 s=getTracebackStr() 224 self.sendResponse(id, None, InvalidMethodParameters()) 225 except: #error inside the callable object 226 s=getTracebackStr() 227 self.sendResponse(id, None, s) 228 229 def handleNotification(self, req): 230 """handles a notification request by calling the appropriete method the service exposes""" 231 name = req["method"] 232 params = req["params"] 233 try: #to get a callable obj 234 obj = getMethodByName(self.service, name) 235 rslt = obj(*params) 236 except: 237 pass 238 239 240 241