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]):
|
class Value:
|
||||||
__slots__ = ('data', )
|
__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
|
self.data = data
|
||||||
|
|
||||||
def __eq__(self, other: Any) -> bool:
|
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:
|
def __repr__(self) -> str:
|
||||||
return f'{self.__class__.__name__}({repr(self.data)})'
|
return f'Value(valuetype.{self.value_type.name}, {repr(self.data)})'
|
||||||
|
|
||||||
|
|
||||||
class UntypedValue(BaseValue[Any]):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BytesValue(BaseValue[bytes]):
|
|
||||||
pass
|
|
||||||
|
|||||||
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
|
import sys
|
||||||
|
|
||||||
|
from phasmplatform.common import valuetype
|
||||||
from phasmplatform.common.config import from_toml
|
from phasmplatform.common.config import from_toml
|
||||||
|
from phasmplatform.common.method import Method, MethodArgument
|
||||||
from phasmplatform.common.router import StdOutRouter
|
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
|
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:
|
def main() -> int:
|
||||||
with open('config.toml', 'rb') as fil:
|
with open('config.toml', 'rb') as fil:
|
||||||
config = from_toml(fil)
|
config = from_toml(fil)
|
||||||
@ -18,26 +31,17 @@ def main() -> int:
|
|||||||
|
|
||||||
stdout_router = StdOutRouter()
|
stdout_router = StdOutRouter()
|
||||||
|
|
||||||
foo: BaseRunner
|
|
||||||
|
|
||||||
with open('/home/johan/projects/idea/phasm/examples/platform.wasm', 'rb') as fil:
|
with open('/home/johan/projects/idea/phasm/examples/platform.wasm', 'rb') as fil:
|
||||||
foo = WasmTimeRunner(stdout_router, fil.read())
|
foo = WasmTimeRunner(stdout_router, fil.read())
|
||||||
|
|
||||||
namespace = b'test-namespace'
|
# namespace = b'test-namespace'
|
||||||
topic = b'test-topic'
|
# topic = b'test-topic'
|
||||||
kind = b'test-kind'
|
# kind = b'test-kind'
|
||||||
body = b'test-body'
|
# body = b'test-body'
|
||||||
|
|
||||||
foo.handle_message(namespace, topic, kind, body)
|
# foo.handle_message(namespace, topic, kind, body)
|
||||||
|
|
||||||
inp = BytesValue(b'Hello, world!')
|
somefunc(foo)
|
||||||
print('inp', inp)
|
|
||||||
|
|
||||||
def on_respond(out: BaseValue[Any]) -> None:
|
|
||||||
print('out', out)
|
|
||||||
assert out == inp
|
|
||||||
|
|
||||||
foo.do_call('echo', [inp], on_respond)
|
|
||||||
|
|
||||||
return 0
|
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.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', )
|
__slots__ = ('router', )
|
||||||
|
|
||||||
router: BaseRouter
|
router: BaseRouter
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
from typing import Any, Callable, List, Union
|
from typing import Callable, List, Union
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
import wasmtime
|
import wasmtime
|
||||||
|
|
||||||
|
from phasmplatform.common import valuetype
|
||||||
|
from phasmplatform.common.method import Method
|
||||||
from phasmplatform.common.router import BaseRouter
|
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
|
from .base import BaseRunner
|
||||||
|
|
||||||
|
|
||||||
@ -66,20 +69,39 @@ class WasmTimeRunner(BaseRunner):
|
|||||||
|
|
||||||
return raw[ptr + 4:ptr + 4 + length]
|
return raw[ptr + 4:ptr + 4 + length]
|
||||||
|
|
||||||
def convert_value(self, val: BaseValue[Any]) -> Union[int, float]:
|
def value_to_wasm(self, val: Value) -> Union[None, int, float]:
|
||||||
if isinstance(val, BytesValue):
|
if val.value_type is valuetype.bytes:
|
||||||
|
assert isinstance(val.data, bytes) # type hint
|
||||||
return self.alloc_bytes(val.data)
|
return self.alloc_bytes(val.data)
|
||||||
|
|
||||||
raise NotImplementedError(val)
|
raise NotImplementedError(val)
|
||||||
|
|
||||||
def do_call(self, method_name: str, args: List[BaseValue[Any]], callback: Callable[[BaseValue[Any]], None]) -> None:
|
def value_from_wasm(self, value_type: ValueType, val: Union[None, int, float]) -> Value:
|
||||||
method = self.exports[method_name]
|
if value_type is valuetype.bytes:
|
||||||
assert isinstance(method, wasmtime.Func)
|
assert isinstance(val, int) # typ hint
|
||||||
|
return Value(valuetype.bytes, self.read_bytes(val))
|
||||||
|
|
||||||
act_args = [self.convert_value(x) for x in args]
|
raise NotImplementedError(value_type, val)
|
||||||
result = method(self.store, *act_args)
|
|
||||||
|
|
||||||
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:
|
def handle_message(self, namespace: bytes, topic: bytes, kind: bytes, body: bytes) -> None:
|
||||||
namespace_ptr = self.alloc_bytes(namespace)
|
namespace_ptr = self.alloc_bytes(namespace)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user