Migrate to Async JSON-RPC package

This commit is contained in:
Ivan Kravets
2021-02-27 19:43:43 +02:00
parent 7c271c8207
commit 0b8bd6d4fc
7 changed files with 27 additions and 50 deletions

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from platformio.clients.account import AccountClient from platformio.clients.account import AccountClient
@ -24,6 +24,6 @@ class AccountRPC:
client = AccountClient() client = AccountClient()
return getattr(client, method)(*args, **kwargs) return getattr(client, method)(*args, **kwargs)
except Exception as e: # pylint: disable=bare-except except Exception as e: # pylint: disable=bare-except
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4003, message="PIO Account Call Error", data=str(e) code=4003, message="PIO Account Call Error", data=str(e)
) )

View File

@ -14,7 +14,7 @@
import time import time
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from platformio.compat import get_running_loop from platformio.compat import get_running_loop
@ -25,7 +25,7 @@ class IDERPC:
def send_command(self, sid, command, params): def send_command(self, sid, command, params):
if not self._queue.get(sid): if not self._queue.get(sid):
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4005, message="PIO Home IDE agent is not started" code=4005, message="PIO Home IDE agent is not started"
) )
while self._queue[sid]: while self._queue[sid]:

View File

@ -20,7 +20,7 @@ import sys
from io import StringIO from io import StringIO
import click import click
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from starlette.concurrency import run_in_threadpool from starlette.concurrency import run_in_threadpool
from platformio import __main__, __version__, fs, proc from platformio import __main__, __version__, fs, proc
@ -99,7 +99,7 @@ class PIOCoreRPC:
result = await PIOCoreRPC._call_subprocess(args, options) result = await PIOCoreRPC._call_subprocess(args, options)
return PIOCoreRPC._process_result(result, to_json) return PIOCoreRPC._process_result(result, to_json)
except Exception as e: # pylint: disable=bare-except except Exception as e: # pylint: disable=bare-except
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4003, message="PIO Core Call Error", data=str(e) code=4003, message="PIO Core Call Error", data=str(e)
) )

View File

@ -18,7 +18,7 @@ import os
import shutil import shutil
import time import time
import jsonrpc from ajsonrpc.core import JSONRPC20DispatchException
from platformio import exception, fs from platformio import exception, fs
from platformio.commands.home.rpc.handlers.app import AppRPC from platformio.commands.home.rpc.handlers.app import AppRPC
@ -266,7 +266,7 @@ class ProjectRPC:
for ext in ("ino", "pde") for ext in ("ino", "pde")
) )
if not is_arduino_project: if not is_arduino_project:
raise jsonrpc.exceptions.JSONRPCDispatchException( raise JSONRPC20DispatchException(
code=4000, message="Not an Arduino project: %s" % arduino_project_dir code=4000, message="Not an Arduino project: %s" % arduino_project_dir
) )
@ -301,7 +301,7 @@ class ProjectRPC:
@staticmethod @staticmethod
async def import_pio(project_dir): async def import_pio(project_dir):
if not project_dir or not is_platformio_project(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 code=4001, message="Not an PlatformIO project: %s" % project_dir
) )
new_project_dir = os.path.join( new_project_dir = os.path.join(

View File

@ -12,14 +12,12 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import inspect
import json
import click import click
import jsonrpc from ajsonrpc.dispatcher import Dispatcher
from ajsonrpc.manager import AsyncJSONRPCResponseManager
from starlette.endpoints import WebSocketEndpoint 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 from platformio.proc import force_exit
@ -30,13 +28,13 @@ class JSONRPCServerFactoryBase:
def __init__(self, shutdown_timeout=0): def __init__(self, shutdown_timeout=0):
self.shutdown_timeout = shutdown_timeout self.shutdown_timeout = shutdown_timeout
self.dispatcher = jsonrpc.Dispatcher() self.manager = AsyncJSONRPCResponseManager(Dispatcher())
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
raise NotImplementedError raise NotImplementedError
def addHandler(self, handler, namespace): def addObjectHandler(self, handler, namespace):
self.dispatcher.build_method_map(handler, prefix="%s." % namespace) self.manager.dispatcher.add_object(handler, prefix="%s." % namespace)
def on_client_connect(self): def on_client_connect(self):
self.connection_nums += 1 self.connection_nums += 1
@ -90,29 +88,8 @@ class WebSocketJSONRPCServer(WebSocketEndpoint):
self.factory.on_client_disconnect() # pylint: disable=no-member self.factory.on_client_disconnect() # pylint: disable=no-member
async def _handle_rpc(self, websocket, data): async def _handle_rpc(self, websocket, data):
response = jsonrpc.JSONRPCResponseManager.handle( # pylint: disable=no-member
data, self.factory.dispatcher # pylint: disable=no-member response = await self.factory.manager.get_response_for_payload(data)
)
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
if response.error: if response.error:
click.secho("Error: %s" % response.error, fg="red", err=True) click.secho("Error: %s" % response.error.message, fg="red", err=True)
if "result" in response.data and is_bytes(response.data["result"]): await websocket.send_text(self.factory.manager.serialize(response.body))
response.data["result"] = response.data["result"].decode("utf-8")
await websocket.send_text(json.dumps(response.data))

View File

@ -65,13 +65,13 @@ def run_server(host, port, no_open, shutdown_timeout, home_url):
raise PlatformioException("Invalid path to PIO Home Contrib") raise PlatformioException("Invalid path to PIO Home Contrib")
ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout) ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout)
ws_rpc_factory.addHandler(AccountRPC(), namespace="account") ws_rpc_factory.addObjectHandler(AccountRPC(), namespace="account")
ws_rpc_factory.addHandler(AppRPC(), namespace="app") ws_rpc_factory.addObjectHandler(AppRPC(), namespace="app")
ws_rpc_factory.addHandler(IDERPC(), namespace="ide") ws_rpc_factory.addObjectHandler(IDERPC(), namespace="ide")
ws_rpc_factory.addHandler(MiscRPC(), namespace="misc") ws_rpc_factory.addObjectHandler(MiscRPC(), namespace="misc")
ws_rpc_factory.addHandler(OSRPC(), namespace="os") ws_rpc_factory.addObjectHandler(OSRPC(), namespace="os")
ws_rpc_factory.addHandler(PIOCoreRPC(), namespace="core") ws_rpc_factory.addObjectHandler(PIOCoreRPC(), namespace="core")
ws_rpc_factory.addHandler(ProjectRPC(), namespace="project") ws_rpc_factory.addObjectHandler(ProjectRPC(), namespace="project")
path = urlparse(home_url).path path = urlparse(home_url).path
routes = [ routes = [

View File

@ -43,7 +43,7 @@ if not PY2:
home_requirements = [ home_requirements = [
"aiofiles==0.6.*", "aiofiles==0.6.*",
"json-rpc==1.13.*", "ajsonrpc==1.0.*",
"starlette==0.14.*", "starlette==0.14.*",
"uvicorn==0.13.*", "uvicorn==0.13.*",
"wsproto==1.0.*", "wsproto==1.0.*",