-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
105 additions
and
314 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from abc import ABC | ||
import logging | ||
|
||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class Base(ABC): | ||
|
||
_LOGGER = _logger.getChild("Base") | ||
|
||
def __init__(self) -> None: | ||
self._logger = logging.getLogger(__name__).getChild(self.__class__.__name__) | ||
|
||
def __del__(self): | ||
self._logger.debug(f"Destroying {self.__class__.__name__} instance") |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
File renamed without changes.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import asyncio | ||
import logging | ||
|
||
from ..base import Base | ||
from .models import JsonRPCRequest | ||
|
||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class Dispatcher(Base): | ||
|
||
def __init__(self): | ||
self._methods = {} | ||
|
||
def add_method(self, func): | ||
self._methods[func.__name__] = func | ||
_logger.debug(f"Adding method {func.__name__} to dispatcher") | ||
return func | ||
|
||
def remove_method(self, func): | ||
del self._methods[func.__name__] | ||
|
||
async def await_maybe(self, func): | ||
if asyncio.iscoroutine(func): | ||
return await func | ||
return func | ||
|
||
async def dispatch(self, request: JsonRPCRequest): | ||
method = self._methods.get(request['method']) | ||
if method is None: | ||
return {'error': 'method not found'} | ||
return await self.await_maybe(method(*request['parameters'])) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from itertools import count | ||
|
||
|
||
class ID: | ||
|
||
def __init__(self, start=1, step=1): | ||
self._counter = count(start, step) | ||
self._current = start | ||
|
||
def __next__(self): | ||
self._current = next(self._counter) | ||
return self._current | ||
|
||
def __iter__(self): | ||
return self | ||
|
||
@property | ||
def current(self): | ||
return self._current |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from typing import TypedDict | ||
|
||
|
||
class JsonRPCRequest(TypedDict): | ||
id: int | ||
jsonrpc: str | ||
method: str | ||
parameters: list | ||
|
||
|
||
class JsonRPCResponse(TypedDict): | ||
id: int | ||
jsonrpc: str | ||
result: list |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from ..base import Base | ||
from ids import ID | ||
|
||
|
||
class Server(Base): | ||
|
||
def __init__(self, id: ID): | ||
self.id = id |
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,24 @@ | ||
from __future__ import annotations | ||
|
||
import sys | ||
from functools import wraps | ||
from typing import Any, Callable, Iterable, Optional, Type, Union | ||
from pathlib import Path | ||
import json | ||
import asyncio | ||
|
||
from pyflowlauncher.shared import logger | ||
|
||
from .event import EventHandler | ||
from .jsonrpc import JsonRPCClient | ||
from .result import JsonRPCAction, ResultResponse | ||
from .manifest import PluginManifestSchema, MANIFEST_FILE | ||
|
||
Method = Callable[..., Union[ResultResponse, JsonRPCAction, None]] | ||
from jsonrpcserver import method, async_dispatch as dispatch | ||
|
||
|
||
class Plugin: | ||
|
||
def __init__(self, methods: list[Method] | None = None) -> None: | ||
self._logger = logger(self) | ||
self._client = JsonRPCClient() | ||
self._event_handler = EventHandler() | ||
self._settings: dict[str, Any] = {} | ||
if methods: | ||
self.add_methods(methods) | ||
|
||
def add_method(self, method: Method) -> str: | ||
"""Add a method to the event handler.""" | ||
return self._event_handler.add_event(method) | ||
|
||
def add_methods(self, methods: Iterable[Method]) -> None: | ||
self._event_handler.add_events(methods) | ||
|
||
def on_method(self, method: Method) -> Method: | ||
@wraps(method) | ||
def wrapper(*args, **kwargs): | ||
return method(*args, **kwargs) | ||
self._event_handler.add_event(wrapper) | ||
return wrapper | ||
|
||
def method(self, method: Method) -> Method: | ||
"""Register a method to be called when the plugin is run.""" | ||
return self.on_method(method) | ||
|
||
def add_exception_handler(self, exception: Type[Exception], handler: Callable[..., Any]) -> None: | ||
"""Add exception handler to be called when an exception is raised in a method.""" | ||
self._event_handler.add_exception_handler(exception, handler) | ||
|
||
def on_except(self, exception: Type[Exception]) -> Callable[..., Any]: | ||
@wraps(exception) | ||
def wrapper(handler: Callable[..., Any]) -> Callable[..., Any]: | ||
self.add_exception_handler(exception, handler) | ||
return handler | ||
return wrapper | ||
|
||
def action(self, method: Method, parameters: Optional[Iterable] = None) -> JsonRPCAction: | ||
"""Register a method and return a JsonRPCAction that calls it.""" | ||
method_name = self.add_method(method) | ||
return {"method": method_name, "parameters": parameters or []} | ||
def __init__(self): | ||
self.methods = {} | ||
|
||
@property | ||
def settings(self) -> dict: | ||
if self._settings is None: | ||
self._settings = {} | ||
self._settings = self._client.recieve().get('settings', {}) | ||
return self._settings | ||
def on_method(self, func): | ||
self.methods[func.__name__] = func | ||
return func | ||
|
||
def run(self) -> None: | ||
request = self._client.recieve() | ||
method = request["method"] | ||
parameters = request.get('parameters', []) | ||
if sys.version_info >= (3, 10, 0): | ||
feedback = asyncio.run(self._event_handler.trigger_event(method, *parameters)) | ||
else: | ||
loop = asyncio.get_event_loop() | ||
feedback = loop.run_until_complete(self._event_handler.trigger_event(method, *parameters)) | ||
if not feedback: | ||
return | ||
self._client.send(feedback) | ||
async def run(self): | ||
while True: | ||
request = await self.receive_request() | ||
response = await dispatch(request, methods=self.methods) | ||
await self.send_response(response) | ||
|
||
@property | ||
def run_dir(self) -> Path: | ||
"""Return the run directory of the plugin.""" | ||
return Path(sys.argv[0]).parent | ||
async def receive_request(self): | ||
pass | ||
|
||
def root_dir(self) -> Path: | ||
"""Return the root directory of the plugin.""" | ||
current_dir = self.run_dir | ||
for part in current_dir.parts: | ||
if current_dir.joinpath(MANIFEST_FILE).exists(): | ||
return current_dir | ||
current_dir = current_dir.parent | ||
raise FileNotFoundError(f"Could not find {MANIFEST_FILE} in {self.run_dir} or any parent directory.") | ||
async def send_response(self, response): | ||
pass | ||
|
||
def manifest(self) -> PluginManifestSchema: | ||
"""Return the plugin manifest.""" | ||
with open(self.root_dir() / MANIFEST_FILE, 'r', encoding='utf-8') as f: | ||
manifest = json.load(f) | ||
return manifest |
Oops, something went wrong.