Routing ideas
This commit is contained in:
parent
2485ccba40
commit
bb9ac649bf
15
phasmplatform/common/container.py
Normal file
15
phasmplatform/common/container.py
Normal file
@ -0,0 +1,15 @@
|
||||
from typing import List
|
||||
|
||||
from .image import Image
|
||||
from .method import Method
|
||||
|
||||
|
||||
class Container:
|
||||
__slots__ = ('image', 'methods', )
|
||||
|
||||
image: Image
|
||||
methods: List[Method]
|
||||
|
||||
def __init__(self, image: Image, methods: List[Method]) -> None:
|
||||
self.image = image
|
||||
self.methods = methods
|
||||
7
phasmplatform/common/image.py
Normal file
7
phasmplatform/common/image.py
Normal file
@ -0,0 +1,7 @@
|
||||
class Image:
|
||||
__slots__ = ('hash', )
|
||||
|
||||
hash: str
|
||||
|
||||
def __init__(self, hash: str) -> None:
|
||||
self.hash = hash
|
||||
28
phasmplatform/common/method.py
Normal file
28
phasmplatform/common/method.py
Normal file
@ -0,0 +1,28 @@
|
||||
from typing import List
|
||||
|
||||
|
||||
from .valuetype import ValueType
|
||||
|
||||
|
||||
class MethodArgument:
|
||||
__slots__ = ('name', 'value_type', )
|
||||
|
||||
name: str
|
||||
value_type: ValueType
|
||||
|
||||
def __init__(self, name: str, value_type: ValueType) -> None:
|
||||
self.name = name
|
||||
self.value_type = value_type
|
||||
|
||||
|
||||
class Method:
|
||||
__slots__ = ('name', 'args', 'return_type', )
|
||||
|
||||
name: str
|
||||
args: List[MethodArgument]
|
||||
return_type: ValueType
|
||||
|
||||
def __init__(self, name: str, args: List[MethodArgument], return_type: ValueType) -> None:
|
||||
self.name = name
|
||||
self.args = args
|
||||
self.return_type = return_type
|
||||
@ -1,26 +1,22 @@
|
||||
from typing import Any, Generic, TypeVar
|
||||
from typing import Any, Union
|
||||
|
||||
T = TypeVar('T')
|
||||
from .valuetype import ValueType
|
||||
|
||||
ValueData = Union[None, bytes]
|
||||
|
||||
|
||||
class BaseValue(Generic[T]):
|
||||
__slots__ = ('data', )
|
||||
class Value:
|
||||
__slots__ = ('value_type', 'data', )
|
||||
|
||||
data: T
|
||||
value_type: ValueType
|
||||
data: ValueData
|
||||
|
||||
def __init__(self, data: T) -> None:
|
||||
def __init__(self, value_type: ValueType, data: ValueData) -> None:
|
||||
self.value_type = value_type
|
||||
self.data = data
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
return self.__class__ is other.__class__ and self.data == other.data
|
||||
return self.value_type is other.value_type and self.data == other.data
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'{self.__class__.__name__}({repr(self.data)})'
|
||||
|
||||
|
||||
class UntypedValue(BaseValue[Any]):
|
||||
pass
|
||||
|
||||
|
||||
class BytesValue(BaseValue[bytes]):
|
||||
pass
|
||||
return f'Value(valuetype.{self.value_type.name}, {repr(self.data)})'
|
||||
|
||||
12
phasmplatform/common/valuetype.py
Normal file
12
phasmplatform/common/valuetype.py
Normal file
@ -0,0 +1,12 @@
|
||||
class ValueType:
|
||||
__slots__ = ('name', )
|
||||
|
||||
name: str
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
|
||||
bytes = ValueType('bytes')
|
||||
|
||||
none = ValueType('none')
|
||||
@ -1,15 +1,28 @@
|
||||
from typing import Any
|
||||
|
||||
import sys
|
||||
|
||||
from phasmplatform.common import valuetype
|
||||
from phasmplatform.common.config import from_toml
|
||||
from phasmplatform.common.method import Method, MethodArgument
|
||||
from phasmplatform.common.router import StdOutRouter
|
||||
from phasmplatform.common.value import BaseValue, BytesValue
|
||||
from phasmplatform.common.value import Value
|
||||
|
||||
from .runners.base import BaseRunner
|
||||
from .runners.base import RunnerInterface
|
||||
from .runners.wasmtime import WasmTimeRunner
|
||||
|
||||
|
||||
def somefunc(runner: RunnerInterface) -> None:
|
||||
inp = Value(valuetype.bytes, b'Hello, world!')
|
||||
print('inp', inp)
|
||||
|
||||
def on_respond(out: Value) -> None:
|
||||
print('out', out)
|
||||
assert out == inp
|
||||
|
||||
echo = Method('echo', [MethodArgument('msg', valuetype.bytes)], valuetype.bytes)
|
||||
|
||||
runner.do_call(echo, [inp], on_respond)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with open('config.toml', 'rb') as fil:
|
||||
config = from_toml(fil)
|
||||
@ -18,26 +31,17 @@ def main() -> int:
|
||||
|
||||
stdout_router = StdOutRouter()
|
||||
|
||||
foo: BaseRunner
|
||||
|
||||
with open('/home/johan/projects/idea/phasm/examples/platform.wasm', 'rb') as fil:
|
||||
foo = WasmTimeRunner(stdout_router, fil.read())
|
||||
|
||||
namespace = b'test-namespace'
|
||||
topic = b'test-topic'
|
||||
kind = b'test-kind'
|
||||
body = b'test-body'
|
||||
# namespace = b'test-namespace'
|
||||
# topic = b'test-topic'
|
||||
# kind = b'test-kind'
|
||||
# body = b'test-body'
|
||||
|
||||
foo.handle_message(namespace, topic, kind, body)
|
||||
# foo.handle_message(namespace, topic, kind, body)
|
||||
|
||||
inp = BytesValue(b'Hello, world!')
|
||||
print('inp', inp)
|
||||
|
||||
def on_respond(out: BaseValue[Any]) -> None:
|
||||
print('out', out)
|
||||
assert out == inp
|
||||
|
||||
foo.do_call('echo', [inp], on_respond)
|
||||
somefunc(foo)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
from typing import TextIO
|
||||
from typing import Callable, List, TextIO
|
||||
|
||||
from phasmplatform.common.router import BaseRouter
|
||||
from phasmplatform.common.method import Method
|
||||
from phasmplatform.common.value import Value
|
||||
|
||||
|
||||
class BaseRunner:
|
||||
class RunnerInterface:
|
||||
__slots__ = ('router', )
|
||||
|
||||
def do_call(self, method: Method, args: List[Value], on_result: Callable[[Value], None]) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class BaseRunner(RunnerInterface):
|
||||
__slots__ = ('router', )
|
||||
|
||||
router: BaseRouter
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
from typing import Any, Callable, List, Union
|
||||
from typing import Callable, List, Union
|
||||
|
||||
import ctypes
|
||||
import struct
|
||||
|
||||
import wasmtime
|
||||
|
||||
from phasmplatform.common import valuetype
|
||||
from phasmplatform.common.method import Method
|
||||
from phasmplatform.common.router import BaseRouter
|
||||
from phasmplatform.common.value import BaseValue, BytesValue, UntypedValue
|
||||
from phasmplatform.common.value import Value
|
||||
from phasmplatform.common.valuetype import ValueType
|
||||
from .base import BaseRunner
|
||||
|
||||
|
||||
@ -66,20 +69,39 @@ class WasmTimeRunner(BaseRunner):
|
||||
|
||||
return raw[ptr + 4:ptr + 4 + length]
|
||||
|
||||
def convert_value(self, val: BaseValue[Any]) -> Union[int, float]:
|
||||
if isinstance(val, BytesValue):
|
||||
def value_to_wasm(self, val: Value) -> Union[None, int, float]:
|
||||
if val.value_type is valuetype.bytes:
|
||||
assert isinstance(val.data, bytes) # type hint
|
||||
return self.alloc_bytes(val.data)
|
||||
|
||||
raise NotImplementedError(val)
|
||||
|
||||
def do_call(self, method_name: str, args: List[BaseValue[Any]], callback: Callable[[BaseValue[Any]], None]) -> None:
|
||||
method = self.exports[method_name]
|
||||
assert isinstance(method, wasmtime.Func)
|
||||
def value_from_wasm(self, value_type: ValueType, val: Union[None, int, float]) -> Value:
|
||||
if value_type is valuetype.bytes:
|
||||
assert isinstance(val, int) # typ hint
|
||||
return Value(valuetype.bytes, self.read_bytes(val))
|
||||
|
||||
act_args = [self.convert_value(x) for x in args]
|
||||
result = method(self.store, *act_args)
|
||||
raise NotImplementedError(value_type, val)
|
||||
|
||||
callback(UntypedValue(result)) # TODO: This returns a bytes pointer, but we can't detect that in advance
|
||||
def do_call(self, method: Method, args: List[Value], on_result: Callable[[Value], None]) -> None:
|
||||
wasm_method = self.exports[method.name]
|
||||
assert isinstance(wasm_method, wasmtime.Func)
|
||||
|
||||
act_args = [self.value_to_wasm(x) for x in args]
|
||||
result = wasm_method(self.store, *act_args)
|
||||
assert result is None or isinstance(result, (int, float, )) # type hint
|
||||
on_result(self.value_from_wasm(method.return_type, result))
|
||||
|
||||
# callback(UntypedValue(result)) # TODO: This returns a bytes pointer, but we can't detect that in advance
|
||||
|
||||
# def do_call(self, method_name: str, args: List[BaseValue[Any]], callback: Callable[[BaseValue[Any]], None]) -> None:
|
||||
# method = self.exports[method_name]
|
||||
# assert isinstance(method, wasmtime.Func)
|
||||
|
||||
# act_args = [self.convert_value(x) for x in args]
|
||||
# result = method(self.store, *act_args)
|
||||
|
||||
# callback(UntypedValue(result)) # TODO: This returns a bytes pointer, but we can't detect that in advance
|
||||
|
||||
def handle_message(self, namespace: bytes, topic: bytes, kind: bytes, body: bytes) -> None:
|
||||
namespace_ptr = self.alloc_bytes(namespace)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user