State loading from toml
This commit is contained in:
parent
45cafdf327
commit
628fb775e8
13
examples/echoclient.toml
Normal file
13
examples/echoclient.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[echoclient-image]
|
||||
apiVersion = "v0"
|
||||
kind = "Image"
|
||||
|
||||
path = "examples/echoclient.wasm"
|
||||
hash = "sha256@84cb22d12dfdd6b05cb906f6db83d59f473c9df85a33822f696344af2b92b502"
|
||||
|
||||
[echoclient-container]
|
||||
apiVersion = "v0"
|
||||
kind = "Container"
|
||||
|
||||
image = "echoclient-image"
|
||||
runtime = "wasmtime"
|
||||
34
examples/echoserver.toml
Normal file
34
examples/echoserver.toml
Normal file
@ -0,0 +1,34 @@
|
||||
[echoserver-image]
|
||||
apiVersion = "v0"
|
||||
kind = "Image"
|
||||
|
||||
path = "examples/echoserver.wasm"
|
||||
hash = "sha256@dfe03b4f7ce5e921931f8715384e35a6776fdc28837e42ffa04305bbadffcfc9"
|
||||
|
||||
[echoserver-container-0]
|
||||
apiVersion = "v0"
|
||||
kind = "Container"
|
||||
|
||||
image = "echoserver-image"
|
||||
runtime = "wasmtime"
|
||||
|
||||
[echoserver-container-1]
|
||||
apiVersion = "v0"
|
||||
kind = "Container"
|
||||
|
||||
image = "echoserver-image"
|
||||
runtime = "wasmtime"
|
||||
|
||||
|
||||
[echoserver-service]
|
||||
apiVersion = "v0"
|
||||
kind = "Service"
|
||||
name = "echoserver"
|
||||
|
||||
[echoserver-service.container]
|
||||
byName = "echoserver-container-*"
|
||||
|
||||
[[echoserver-service.methods]]
|
||||
name = "echo"
|
||||
returns = "none"
|
||||
args = [ {name = "msg", type = "bytes"} ]
|
||||
@ -1,15 +1,15 @@
|
||||
from typing import List
|
||||
|
||||
from .image import Image
|
||||
from .method import Method
|
||||
|
||||
|
||||
class Container:
|
||||
__slots__ = ('image', 'methods', )
|
||||
__slots__ = ('image', 'runtime', )
|
||||
|
||||
image: Image
|
||||
methods: List[Method]
|
||||
runtime: str
|
||||
|
||||
def __init__(self, image: Image, methods: List[Method]) -> None:
|
||||
def __init__(self, image: Image, runtime: str) -> None:
|
||||
self.image = image
|
||||
self.methods = methods
|
||||
self.runtime = runtime
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Container({repr(self.image)}, {repr(self.runtime)})'
|
||||
|
||||
@ -1,7 +1,31 @@
|
||||
class Image:
|
||||
__slots__ = ('hash', )
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Image:
|
||||
__slots__ = ('path', 'hash', )
|
||||
|
||||
path: Optional[str]
|
||||
hash: str
|
||||
|
||||
def __init__(self, hash: str) -> None:
|
||||
def __init__(self, path: Optional[str], hash: str) -> None:
|
||||
self.path = path
|
||||
self.hash = hash
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Image({repr(self.path)}, {repr(self.hash)})'
|
||||
|
||||
|
||||
class ImageReference(Image):
|
||||
__slots__ = ('name', )
|
||||
|
||||
name: str
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
# Intentionally do not call super()
|
||||
# This will cause AttributeError exceptions when someone
|
||||
# tries to access an image that's only a reference
|
||||
|
||||
self.name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'ImageReference({repr(self.name)})'
|
||||
|
||||
103
phasmplatform/common/state.py
Normal file
103
phasmplatform/common/state.py
Normal file
@ -0,0 +1,103 @@
|
||||
from typing import TYPE_CHECKING, Any, BinaryIO, Dict, List
|
||||
|
||||
from .container import Container
|
||||
from .image import Image, ImageReference
|
||||
from .method import Method
|
||||
from .service import Service
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import tomli as tomllib
|
||||
else:
|
||||
try:
|
||||
import tomllib
|
||||
except ImportError:
|
||||
import tomli as tomllib
|
||||
|
||||
|
||||
class State:
|
||||
__slots__ = ('images', 'containers', 'services', )
|
||||
|
||||
images: List[Image]
|
||||
containers: List[Container]
|
||||
services: List[Service]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
images: List[Image],
|
||||
containers: List[Container],
|
||||
services: List[Service],
|
||||
) -> None:
|
||||
self.images = images
|
||||
self.containers = containers
|
||||
self.services = services
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'State({repr(self.images)}, {repr(self.containers)}, {repr(self.services)})'
|
||||
|
||||
|
||||
def image_from_toml(spec: Dict[str, Any]) -> Image:
|
||||
"""
|
||||
Loads an Image spec from toml
|
||||
"""
|
||||
return Image(str(spec['path']), str(spec['hash']))
|
||||
|
||||
|
||||
def container_from_toml(spec: Dict[str, Any]) -> Container:
|
||||
"""
|
||||
Loads a Container spec from toml
|
||||
"""
|
||||
return Container(ImageReference(str(spec['image'])), str(spec['runtime']))
|
||||
|
||||
|
||||
def service_from_toml(spec: Dict[str, Any]) -> Service:
|
||||
"""
|
||||
Loads a Service spec from toml
|
||||
"""
|
||||
methods: List[Method] = []
|
||||
|
||||
return Service(str(spec['name']), methods)
|
||||
|
||||
|
||||
def from_toml(toml: BinaryIO) -> State:
|
||||
"""
|
||||
Loads the given toml and builds a state instance out of it
|
||||
"""
|
||||
toml_dict = tomllib.load(toml)
|
||||
|
||||
images: List[Image] = []
|
||||
images_by_name: Dict[str, Image] = {}
|
||||
containers: List[Container] = []
|
||||
services: List[Service] = []
|
||||
|
||||
for name, spec in toml_dict.items():
|
||||
if spec['apiVersion'] != 'v0':
|
||||
raise NotImplementedError('apiVersion', spec['apiVersion'])
|
||||
|
||||
if spec['kind'] == 'Image':
|
||||
image = image_from_toml(spec)
|
||||
images.append(image)
|
||||
|
||||
assert name not in images_by_name, f'Duplicate image name: {name}'
|
||||
images_by_name[name] = image
|
||||
continue
|
||||
|
||||
if spec['kind'] == 'Container':
|
||||
containers.append(container_from_toml(spec))
|
||||
continue
|
||||
|
||||
if spec['kind'] == 'Service':
|
||||
services.append(service_from_toml(spec))
|
||||
continue
|
||||
|
||||
raise NotImplementedError(spec)
|
||||
|
||||
for container in containers:
|
||||
if not isinstance(container.image, ImageReference):
|
||||
continue
|
||||
|
||||
image_opt = images_by_name.get(container.image.name, None)
|
||||
assert image_opt is not None, f'Image reference not resolved: {container.image.name}'
|
||||
container.image = image_opt
|
||||
|
||||
return State(images, containers, services)
|
||||
@ -6,11 +6,12 @@ import time
|
||||
from queue import Empty, Queue
|
||||
|
||||
from phasmplatform.common import valuetype
|
||||
from phasmplatform.common.config import from_toml
|
||||
from phasmplatform.common.config import from_toml as config_from_toml
|
||||
from phasmplatform.common.method import Method, MethodArgument, MethodCall
|
||||
from phasmplatform.common.router import MethodCallRouterInterface
|
||||
from phasmplatform.common.service import Service, ServiceDiscoveryInterface
|
||||
from phasmplatform.common.value import NoneValue
|
||||
from phasmplatform.common.state import from_toml as state_from_toml
|
||||
|
||||
from .runners.base import RunnerInterface
|
||||
from .runners.wasmtime import WasmTimeRunner
|
||||
@ -23,7 +24,6 @@ def runner_thread(runner: RunnerInterface, queue: Queue[MethodCall]) -> None:
|
||||
except Empty:
|
||||
break
|
||||
|
||||
print('rt call', runner, queue, call)
|
||||
runner.do_call(call)
|
||||
|
||||
|
||||
@ -82,10 +82,14 @@ class LocalhostMethodCallRouter(MethodCallRouterInterface):
|
||||
|
||||
def main() -> int:
|
||||
with open('config.toml', 'rb') as fil:
|
||||
config = from_toml(fil)
|
||||
config = config_from_toml(fil)
|
||||
|
||||
del config
|
||||
|
||||
with open('./examples/echoserver.toml', 'rb') as fil:
|
||||
state = state_from_toml(fil)
|
||||
print(state)
|
||||
|
||||
localhost_queue: Queue[MethodCall] = Queue()
|
||||
echo_client_queue: Queue[MethodCall] = Queue()
|
||||
echo_server_queue: Queue[MethodCall] = Queue()
|
||||
@ -96,7 +100,7 @@ def main() -> int:
|
||||
localhost = LocalhostRunner()
|
||||
service_discovery.register_service(make_prelude(), localhost_queue)
|
||||
|
||||
with open('/home/johan/projects/idea/phasm/examples/echoserver.wasm', 'rb') as fil:
|
||||
with open('./examples/echoserver.wasm', 'rb') as fil:
|
||||
echo_server = WasmTimeRunner(service_discovery, method_call_router, fil.read())
|
||||
service_discovery.register_service(Service('echoserver', [
|
||||
Method('echo', [
|
||||
@ -104,7 +108,7 @@ def main() -> int:
|
||||
], valuetype.bytes)
|
||||
]), echo_server_queue)
|
||||
|
||||
with open('/home/johan/projects/idea/phasm/examples/echoclient.wasm', 'rb') as fil:
|
||||
with open('./examples/echoclient.wasm', 'rb') as fil:
|
||||
echo_client = WasmTimeRunner(service_discovery, method_call_router, fil.read())
|
||||
|
||||
# service_discovery.register_service(echo_client, echo_client_queue)
|
||||
|
||||
@ -67,9 +67,6 @@ class BaseRunner(RunnerInterface):
|
||||
|
||||
raise NotImplementedError(value_type, val)
|
||||
|
||||
def log_bytes(self, msg_ptr: int) -> None:
|
||||
print('LOG: ' + self.read_bytes(msg_ptr).decode())
|
||||
|
||||
|
||||
def dump_memory(textio: TextIO, mem: bytes) -> None:
|
||||
line_width = 16
|
||||
|
||||
@ -32,12 +32,6 @@ class WasmTimeRunner(BaseRunner):
|
||||
self.store = wasmtime.Store()
|
||||
self.module = wasmtime.Module(self.store.engine, wasm_bin)
|
||||
|
||||
from typing import Any
|
||||
|
||||
def dump_args(*args: Any, **kwargs: Any) -> None:
|
||||
print('args', args)
|
||||
print('kwargs', kwargs)
|
||||
|
||||
imports: List[wasmtime.Func] = []
|
||||
for imprt in self.module.imports:
|
||||
service = service_discovery.find_service(imprt.module)
|
||||
@ -125,13 +119,11 @@ class WasmTimeRunner(BaseRunner):
|
||||
queue: Queue[Value] = Queue(maxsize=1)
|
||||
|
||||
def on_success(val: Value) -> None:
|
||||
print('hi mom')
|
||||
queue.put(val)
|
||||
|
||||
def on_error(err: MethodCallError) -> None:
|
||||
print('Error while calling', service, method, args)
|
||||
|
||||
print('on_success', on_success)
|
||||
call = MethodCall(method, call_args, on_success, on_error)
|
||||
|
||||
print(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user