Created
February 27, 2014 11:25
-
-
Save lvh/9248425 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from json import dumps, loads | |
from twisted.internet.defer import inlineCallbacks | |
from twisted.protocols.basic import NetstringReceiver | |
from twisted.python import log | |
class JSONRPCReceiver(NetstringReceiver): | |
def stringReceived(self, string): | |
try: | |
request = loads(string) | |
except ValueError: | |
err = self._formatError(-32700, "Parse error") | |
self._sendResponse(None, error=err) | |
self._requestReceived(request) | |
def _requestReceived(self, request): | |
"""Validate and respond to the request. | |
""" | |
if request.get("jsonrpc") != "2.0": | |
err = self._formatError(-32600, "Invalid Request") | |
self._sendResponse(request.get("id"), error=err) | |
return | |
try: | |
requestId = request["id"] | |
except KeyError: | |
err = self._formatError(-32600, "Invalid Request") | |
self._sendResponse(None, error=err) | |
return | |
try: | |
method = self._getMethod(request["method"]) | |
except KeyError: | |
err = self._formatError(-32601, "Method not found") | |
self._sendResponse(requestId, error=err) | |
return | |
kwargs = request.get("params", {}) | |
self._call(requestId, method, kwargs) | |
@inlineCallbacks | |
def _call(self, requestId, method, kwargs): | |
log.msg("JSONRPC call {} for {!r}: {}, {}" | |
.format(requestId, self.transport.getPeer(), method, kwargs)) | |
try: | |
result = yield method(**kwargs) | |
except TypeError as e: # Can also catch spurious TypeErrors... | |
log.err(e) | |
err = self._formatError(-32602, "Invalid params") | |
self._sendResponse(requestId, error=err) | |
else: | |
self._sendResponse(requestId, result=result) | |
def _getMethod(self, methodName): | |
"""Gets a method. | |
""" | |
return getattr(self, "jsonrpc_" + methodName) | |
def _formatError(self, code, message, data=None): | |
log.msg("JSONRPC error for {!r}: {}, {}, {}" | |
.format(self.transport.getPeer(), code, message, data)) | |
return {"code": code, "message": message, "data": data} | |
def _sendResponse(self, requestId, result=None, error=None): | |
response = {"jsonrpc": "2.0", "id": requestId} | |
if result is not None: | |
response["result"] = result | |
elif error is not None: | |
response["error"] = error | |
else: | |
raise RuntimeError("Must pass exactly one of [result, error]") | |
encoded = dumps(response) | |
self.sendString(encoded) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment