/examples/jsonrpc/public/services/jsonrpc/__init__.py
http://pyjamas.googlecode.com/ · Python · 241 lines · 172 code · 19 blank · 50 comment · 15 complexity · d8401018c999557644a64108fa041064 MD5 · raw file
- """
- Copyright (c) 2006 Jan-Klaas Kollhof
- This file is part of jsonrpc.
- jsonrpc is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this software; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- """
- from threading import Event, Lock
- from errors import *
- from simplejson import JSONDecoder, JSONEncoder
-
-
- class JSONRPCEncoder(JSONEncoder):
- def default(self, obj):
- if isinstance(obj, JSONRPCError):
- return obj.__class__.__name__
- else:
- return JSONEncoder.default(self, obj)
- class Timeout(Exception):
- pass
-
- class ResponseEvent:
- """Event which is fired when the response is returned for a request.
-
- For each request sent this event is created.
- An application can wait for the event to create a blocking request.
- """
- def __init__(self):
- self.__evt = Event()
-
- def waiting(self):
- return not self.__evt.isSet()
-
- def waitForResponse(self, timeOut=None):
- """blocks until the response arrived or timeout is reached."""
- self.__evt.wait(timeOut)
- if self.waiting():
- raise Timeout()
- else:
- if self.response["error"]:
- raise Exception(self.response["error"])
- else:
- return self.response["result"]
-
- def handleResponse(self, resp):
- self.response = resp
- self.__evt.set()
-
-
- class SimpleMessageHandler:
- def __init__(self, DecoderClass=JSONDecoder, EncoderClass=JSONRPCEncoder, messageDelimiter=""):
- self.decoder = DecoderClass()
- self.encoder = EncoderClass()
- self.partialData = ""
- self.respEvents={}
- self.respLock = Lock()
- self.messageDelimiter=messageDelimiter
-
- def close(self):
- pass
-
- def send(self, data):
- pass
-
- def sendMessage(self, msg):
- self.send(self.encoder.encode(msg) + self.messageDelimiter)
-
- def handlePartialData(self, data):
- data = self.partialData + data.replace("\r","").replace("\n", "")
- msgs=[]
- while data != "":
- pos = data.find("{")
- if(pos > -1):
- data=data[pos:]
- try:
- (obj, pos) = self.decoder.raw_decode(data)
- data = data[pos:]
- msgs.append(obj)
- except:
- break
- else:
- break
- self.partialData = data
-
- self.handleMessages(msgs)
- def sendNotify(self, name, args):
- """sends a notification object to the peer"""
- self.sendMessage({"method":name, "params": args})
-
- def sendRequest(self, name, args):
- """sends a request to the peer"""
- (respEvt, id) = self.newResponseEvent()
- self.sendMessage({"id":id, "method":name, "params": args})
- return respEvt
-
- def sendResponse(self, id, result, error):
- """sends a response to the peer"""
- self.sendMessage({"result":result, "error": error, "id":id})
-
- def newResponseEvent(self):
- """creates a response event and adds it to a waiting list
- When the reponse arrives it will be removed from the list.
- """
- respEvt = ResponseEvent()
- self.respLock.acquire()
- eid = id(respEvt)
- self.respEvents[eid] = respEvt
- self.respLock.release()
- return (respEvt,eid)
-
- def handleMessages(self, msgs):
- for msg in msgs:
- if msg.has_key("method") and msg.has_key("params"):
- if msg.has_key("id"):
- if msg["id"]:
- self.handleRequest(msg)
- else:
- self.handleNotification(msg)
- else:
- self.handleNotification(msg)
- elif msg.has_key("result") and msg.has_key("error"):
- self.handleResponse(msg)
- else:#unknown object
- self.sendResponse(None, InvalidJSONMessage())
- self.close()
-
- def handleResponse(self, resp):
- """handles a response by fireing the response event for the response coming in"""
- id=resp["id"]
- evt = self.respEvents[id]
- del(self.respEvents[id])
- evt.handleResponse(resp)
-
- def handleRequest(self, request):
- pass
- def handleNotification(self, notification):
- pass
-
-
- import re
- NameAllowedRegExp=re.compile("^[a-zA-Z]\w*$")
- def nameAllowed(name):
- """checks if a name is allowed.
- """
- if NameAllowedRegExp.match(name):
- return 1
- else:
- return 0
-
- def getMethodByName(obj, name):
- """searches for an object with the name given inside the object given.
- "obj.child.meth" will return the meth obj.
- """
- try:#to get a method by asking the service
- obj = obj._getMethodByName(name)
- except:
- #assumed a childObject is ment
- #split the name from objName.childObjName... -> [objName, childObjName, ...]
- #and get all objects up to the last in list with name checking from the service object
- names = name.split(".")
- for name in names:
- if nameAllowed(name):
- obj = getattr(obj, name)
- else:
- raise MethodNameNotAllowed()
-
- return obj
-
- class SimpleServiceHandler(SimpleMessageHandler):
- def __init__(self, service, DecoderClass=JSONDecoder, EncoderClass=JSONRPCEncoder, messageDelimiter=""):
- self.service = service
- SimpleMessageHandler.__init__(self, DecoderClass, EncoderClass, messageDelimiter)
- try:
- service._newConnection(self)
- except:
- pass
-
- def close(self):
- try:
- self.service._closingConnection(self)
- except:
- pass
-
- def handleRequest(self, req):
- """handles a request by calling the appropriete method the service exposes"""
- name = req["method"]
- params = req["params"]
- id=req["id"]
- obj=None
- try: #to get a callable obj
- obj = getMethodByName(self.service, name)
- except MethodNameNotAllowed,e:
- self.sendResponse(id, None, e)
- except:
- self.sendResponse(id, None, MethodNotFound())
- if obj:
- try: #to call the object with parameters
- rslt = obj(*params)
- self.sendResponse(id, rslt, None)
- except TypeError: # wrong arguments
- #todo what if the TypeError was not thrown directly by the callable obj
- s=getTracebackStr()
- self.sendResponse(id, None, InvalidMethodParameters())
- except: #error inside the callable object
- s=getTracebackStr()
- self.sendResponse(id, None, s)
-
- def handleNotification(self, req):
- """handles a notification request by calling the appropriete method the service exposes"""
- name = req["method"]
- params = req["params"]
- try: #to get a callable obj
- obj = getMethodByName(self.service, name)
- rslt = obj(*params)
- except:
- pass