From 0b8bd6d4fc3570bb3711dbfe35ecedffb8a5ca4e Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 27 Feb 2021 19:43:43 +0200 Subject: [PATCH] Migrate to Async JSON-RPC package --- .../commands/home/rpc/handlers/account.py | 4 +- platformio/commands/home/rpc/handlers/ide.py | 4 +- .../commands/home/rpc/handlers/piocore.py | 4 +- .../commands/home/rpc/handlers/project.py | 6 +-- platformio/commands/home/rpc/server.py | 43 +++++-------------- platformio/commands/home/run.py | 14 +++--- setup.py | 2 +- 7 files changed, 27 insertions(+), 50 deletions(-) diff --git a/platformio/commands/home/rpc/handlers/account.py b/platformio/commands/home/rpc/handlers/account.py index 337d780a..5336d600 100644 --- a/platformio/commands/home/rpc/handlers/account.py +++ b/platformio/commands/home/rpc/handlers/account.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from platformio.clients.account import AccountClient @@ -24,6 +24,6 @@ class AccountRPC: client = AccountClient() return getattr(client, method)(*args, **kwargs) except Exception as e: # pylint: disable=bare-except - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4003, message="PIO Account Call Error", data=str(e) ) diff --git a/platformio/commands/home/rpc/handlers/ide.py b/platformio/commands/home/rpc/handlers/ide.py index ed95b738..3bf8e00f 100644 --- a/platformio/commands/home/rpc/handlers/ide.py +++ b/platformio/commands/home/rpc/handlers/ide.py @@ -14,7 +14,7 @@ import time -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from platformio.compat import get_running_loop @@ -25,7 +25,7 @@ class IDERPC: def send_command(self, sid, command, params): if not self._queue.get(sid): - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4005, message="PIO Home IDE agent is not started" ) while self._queue[sid]: diff --git a/platformio/commands/home/rpc/handlers/piocore.py b/platformio/commands/home/rpc/handlers/piocore.py index d74095ab..52a1b126 100644 --- a/platformio/commands/home/rpc/handlers/piocore.py +++ b/platformio/commands/home/rpc/handlers/piocore.py @@ -20,7 +20,7 @@ import sys from io import StringIO import click -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from starlette.concurrency import run_in_threadpool from platformio import __main__, __version__, fs, proc @@ -99,7 +99,7 @@ class PIOCoreRPC: result = await PIOCoreRPC._call_subprocess(args, options) return PIOCoreRPC._process_result(result, to_json) except Exception as e: # pylint: disable=bare-except - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4003, message="PIO Core Call Error", data=str(e) ) diff --git a/platformio/commands/home/rpc/handlers/project.py b/platformio/commands/home/rpc/handlers/project.py index 39fa6c12..cb8eda5a 100644 --- a/platformio/commands/home/rpc/handlers/project.py +++ b/platformio/commands/home/rpc/handlers/project.py @@ -18,7 +18,7 @@ import os import shutil import time -import jsonrpc +from ajsonrpc.core import JSONRPC20DispatchException from platformio import exception, fs from platformio.commands.home.rpc.handlers.app import AppRPC @@ -266,7 +266,7 @@ class ProjectRPC: for ext in ("ino", "pde") ) if not is_arduino_project: - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4000, message="Not an Arduino project: %s" % arduino_project_dir ) @@ -301,7 +301,7 @@ class ProjectRPC: @staticmethod async def import_pio(project_dir): if not project_dir or not is_platformio_project(project_dir): - raise jsonrpc.exceptions.JSONRPCDispatchException( + raise JSONRPC20DispatchException( code=4001, message="Not an PlatformIO project: %s" % project_dir ) new_project_dir = os.path.join( diff --git a/platformio/commands/home/rpc/server.py b/platformio/commands/home/rpc/server.py index 8ba41da9..f68f39f8 100644 --- a/platformio/commands/home/rpc/server.py +++ b/platformio/commands/home/rpc/server.py @@ -12,14 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import inspect -import json - import click -import jsonrpc +from ajsonrpc.dispatcher import Dispatcher +from ajsonrpc.manager import AsyncJSONRPCResponseManager from starlette.endpoints import WebSocketEndpoint -from platformio.compat import create_task, get_running_loop, is_bytes +from platformio.compat import create_task, get_running_loop from platformio.proc import force_exit @@ -30,13 +28,13 @@ class JSONRPCServerFactoryBase: def __init__(self, shutdown_timeout=0): self.shutdown_timeout = shutdown_timeout - self.dispatcher = jsonrpc.Dispatcher() + self.manager = AsyncJSONRPCResponseManager(Dispatcher()) def __call__(self, *args, **kwargs): raise NotImplementedError - def addHandler(self, handler, namespace): - self.dispatcher.build_method_map(handler, prefix="%s." % namespace) + def addObjectHandler(self, handler, namespace): + self.manager.dispatcher.add_object(handler, prefix="%s." % namespace) def on_client_connect(self): self.connection_nums += 1 @@ -90,29 +88,8 @@ class WebSocketJSONRPCServer(WebSocketEndpoint): self.factory.on_client_disconnect() # pylint: disable=no-member async def _handle_rpc(self, websocket, data): - response = jsonrpc.JSONRPCResponseManager.handle( - data, self.factory.dispatcher # pylint: disable=no-member - ) - if response.result and inspect.isawaitable(response.result): - try: - response.result = await response.result - response.data["result"] = response.result - response.error = None - except Exception as exc: # pylint: disable=broad-except - if not isinstance(exc, jsonrpc.exceptions.JSONRPCDispatchException): - exc = jsonrpc.exceptions.JSONRPCDispatchException( - code=4999, message=str(exc) - ) - response.result = None - response.error = exc.error._data # pylint: disable=protected-access - new_data = response.data.copy() - new_data["error"] = response.error - del new_data["result"] - response.data = new_data - + # pylint: disable=no-member + response = await self.factory.manager.get_response_for_payload(data) if response.error: - click.secho("Error: %s" % response.error, fg="red", err=True) - if "result" in response.data and is_bytes(response.data["result"]): - response.data["result"] = response.data["result"].decode("utf-8") - - await websocket.send_text(json.dumps(response.data)) + click.secho("Error: %s" % response.error.message, fg="red", err=True) + await websocket.send_text(self.factory.manager.serialize(response.body)) diff --git a/platformio/commands/home/run.py b/platformio/commands/home/run.py index 6e93cc2b..4e225720 100644 --- a/platformio/commands/home/run.py +++ b/platformio/commands/home/run.py @@ -65,13 +65,13 @@ def run_server(host, port, no_open, shutdown_timeout, home_url): raise PlatformioException("Invalid path to PIO Home Contrib") ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout) - ws_rpc_factory.addHandler(AccountRPC(), namespace="account") - ws_rpc_factory.addHandler(AppRPC(), namespace="app") - ws_rpc_factory.addHandler(IDERPC(), namespace="ide") - ws_rpc_factory.addHandler(MiscRPC(), namespace="misc") - ws_rpc_factory.addHandler(OSRPC(), namespace="os") - ws_rpc_factory.addHandler(PIOCoreRPC(), namespace="core") - ws_rpc_factory.addHandler(ProjectRPC(), namespace="project") + ws_rpc_factory.addObjectHandler(AccountRPC(), namespace="account") + ws_rpc_factory.addObjectHandler(AppRPC(), namespace="app") + ws_rpc_factory.addObjectHandler(IDERPC(), namespace="ide") + ws_rpc_factory.addObjectHandler(MiscRPC(), namespace="misc") + ws_rpc_factory.addObjectHandler(OSRPC(), namespace="os") + ws_rpc_factory.addObjectHandler(PIOCoreRPC(), namespace="core") + ws_rpc_factory.addObjectHandler(ProjectRPC(), namespace="project") path = urlparse(home_url).path routes = [ diff --git a/setup.py b/setup.py index ad251a89..7abea9e9 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ if not PY2: home_requirements = [ "aiofiles==0.6.*", - "json-rpc==1.13.*", + "ajsonrpc==1.0.*", "starlette==0.14.*", "uvicorn==0.13.*", "wsproto==1.0.*",