From 726986c1ebdda9e87e1534ce31be1199672b6375 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 26 Oct 2018 00:19:07 +0300 Subject: [PATCH] Implemented JSON-RPC apivariant --- setup.py | 1 + src/api.py | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index a6f7844c..14a023be 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ from src.version import softwareVersion EXTRAS_REQUIRE = { 'gir': ['pygobject'], + 'json': ['jsonrpclib'], 'notify2': ['notify2'], 'opencl': ['pyopencl', 'numpy'], 'prctl': ['python_prctl'], # Named threads diff --git a/src/api.py b/src/api.py index e457a8fc..5f2c9ca6 100644 --- a/src/api.py +++ b/src/api.py @@ -54,6 +54,7 @@ except ImportError: else: monkey_patch() + str_chan = '[chan]' str_broadcast_subscribers = '[Broadcast subscribers]' @@ -64,16 +65,6 @@ class APIError(xmlrpclib.Fault): return "API Error %04i: %s" % (self.faultCode, self.faultString) -class StoppableXMLRPCServer(SimpleXMLRPCServer): - """A SimpleXMLRPCServer that honours state.shutdown""" - allow_reuse_address = True - - def serve_forever(self, poll_interval=None): - """Start the SimpleXMLRPCServer""" - while state.shutdown == 0: - self.handle_request() - - # This thread, of which there is only one, runs the API. class singleAPI(StoppableThread): """API thread""" @@ -99,17 +90,38 @@ class singleAPI(StoppableThread): getattr(errno, 'WSAEADDRINUSE') except AttributeError: errno.WSAEADDRINUSE = errno.EADDRINUSE + + RPCServerBase = SimpleXMLRPCServer + if BMConfigParser().safeGet( + 'bitmessagesettings', 'apivariant') == 'json': + try: + from jsonrpclib.SimpleJSONRPCServer import ( + SimpleJSONRPCServer as RPCServerBase) + except ImportError: + logger.warning( + 'jsonrpclib not available, failing back to XML-RPC') + + # Nested class. FIXME not found a better solution. + class StoppableRPCServer(RPCServerBase): + """A SimpleXMLRPCServer that honours state.shutdown""" + allow_reuse_address = True + + def serve_forever(self, poll_interval=None): + """Start the RPCServer""" + while state.shutdown == 0: + self.handle_request() + for attempt in range(50): try: if attempt > 0: logger.warning( 'Failed to start API listener on port %s', port) port = random.randint(32767, 65535) - se = StoppableXMLRPCServer( + se = StoppableRPCServer( (BMConfigParser().get( 'bitmessagesettings', 'apiinterface'), port), - BMXMLRPCRequestHandler, True, True) + BMXMLRPCRequestHandler, True, encoding='UTF-8') except socket.error as e: if e.errno in (errno.EADDRINUSE, errno.WSAEADDRINUSE): continue @@ -120,7 +132,8 @@ class singleAPI(StoppableThread): 'bitmessagesettings', 'apiport', str(port)) BMConfigParser().save() break - se.register_instance(BMXMLRPCDispatcher()) + + se.register_instance(BMRPCDispatcher()) se.register_introspection_functions() apiNotifyPath = BMConfigParser().safeGet( @@ -288,7 +301,7 @@ class BMXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return False -class BMXMLRPCDispatcher(object): +class BMRPCDispatcher(object): """This class is used to dispatch API commands""" __metaclass__ = CommandHandler