commit 711a7032c0902a457b5203e07e67b4f33395e947 Author: Emery Hemingway Date: Sun Apr 30 10:19:57 2023 +0100 WiP! diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..c3198c0 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +# source_env .. +use flake sigil#checks.x86_64-linux.nova-nim.nodes.machine.config.genode.init.children.test_nim.package diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ad6275 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.direnv diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..74f1fe4 --- /dev/null +++ b/Tuprules.tup @@ -0,0 +1,4 @@ +include ../syndicate-nim/depends.tup +NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src +NIM_FLAGS += --path:$(TUP_CWD)/../genode-nim/src +NIM = /nix/store/zp7f2j6lsas1rfi0v2rx51c29c00xnz9-x86_64-unknown-genode-nim-wrapper-1.6.8-x86_64-unknown-genode/bin/nim diff --git a/src/Tupfile b/src/Tupfile new file mode 100644 index 0000000..7300816 --- /dev/null +++ b/src/Tupfile @@ -0,0 +1,3 @@ +include_rules +: foreach ../*.prs |> !preserves_schema_nim |> {schema} +: syndicate_service.nim | {schema} |> !nim |> diff --git a/src/syndicate_genode/parent_facets.nim b/src/syndicate_genode/parent_facets.nim new file mode 100644 index 0000000..c163937 --- /dev/null +++ b/src/syndicate_genode/parent_facets.nim @@ -0,0 +1,129 @@ +# SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway +# SPDX-License-Identifier: AGPL-3.0-or-later + +import std/[sets, tables] +from std/sequtils import toSeq +from std/strutils import parseHexInt, parseInt, unescape +import npeg +import preserves, preserves/xmlhooks +import ../../syndicate, ./schemas/session_requests + +export Args, `$` + + +type + Value = Assertion + ArgsParser = object + dict: seq[(Value, Value)] + nextKey: Assertion + +proc push[T](parser: var ArgsParser; v: sink T) = + add(parser.dict, (move parser.nextKey, toPreserve(v, Ref))) + +const argsPeg = peg("Args", parser: ArgsParser): + # "Because friends don't let friends write parsers by hand" - Ico + + Args <- Pair * *(*(Space | {','}) * Pair) + + Pair <- Key * '=' * Value + + Key <- +{'0'..'9', 'A'..'z', '_'}: + parser.nextKey = toSymbol($0, Ref) + for (key, _) in parser.dict: + validate(key != parser.nextKey) + # check for duplicate keys + + Value <- String | Size | Hex | Natural | True | False + + String <- '"' * >(*(('\\' * {'\\', '"'}) | ({'\x20'..'\x7e'} - {'\\', '"'}))) * '"': + push(parser, unescape($0)) + + Size <- >(+Digit) * >({'K','M','G','P'}): + var i = parseInt($1) + case $2 + of "K": i = i shl 10 + of "M": i = i shl 20 + of "G": i = i shl 30 + of "P": i = i shl 40 + push(parser, i) + + Hex <- "0x" * >(+Xdigit): + push(parser, parseHexInt($1)) + + Natural <- ('1' * +Digit) | ({'2'..'9'} * *Digit): + push(parser, parseInt($0)) + + True <- "true" | "on" | "yes" | "1": + push(parser, true) + + False <- "false" | "off" | "no" | "0": + push(parser, false) + +proc argumentsToPreserves(text: Value): (bool, Value) {.gcsafe.} = + if text.isString: + var p: ArgsParser + let match = match(argsPeg, text.string, p) + if match.ok: + result[0] = true + result[1] = initDictionary[Ref]() + result[1].dict = move p.dict + else: + raiseAssert text.string[match.matchMax..text.string.high] + +type + CreateRequest* = session_requests.CreateRequest[Ref] + CloseRequest* = session_requests.CloseRequest[Ref] + CreateAttrs* = session_requests.CreateAttrs[Ref] + # TODO: schema code-generator is making these generic when they are not + +when defined(genode): + import genode, genode/roms + from std/asyncdispatch import scheduleCallbacks + + proc newConfigFacet*(env: GenodeEnv; ds: Ref; turn: var Turn): Facet {.discardable.} = + ## Create a new `Facet` that processes the "config" ROM + ## and publishes each request to `ds`. + facet(turn) do (turn: var Turn): + let facet = turn.facet + var configHandle: Handle + let configRom = env.newRomHandler("config") do (rom: RomClient): + update(rom) + run(facet) do (turn: var Turn): + var pr = rom.xml.toPreserve(Ref) + if pr.isRecord("config"): + replace(turn, ds, configHandle, pr) + scheduleCallbacks() + + proc newSessionRequestsFacet*(env: GenodeEnv; ds: Ref; turn: var Turn): Facet {.discardable.} = + ## Create a new `Facet` that processes the "session_requests" ROM + ## and publishes each request to `ds`. + facet(turn) do (turn: var Turn): + let facet = turn.facet + var requestHandles = initTable[Preserve[Ref], Handle]() + let sessionsRom = env.newRomHandler("session_requests") do (rom: RomClient): + update(rom) + run(facet) do (turn: var Turn): + var currentRequests: HashSet[Value] + for req in rom.xml.toPreserve(Ref).fields: + var req = req + if req.isRecord "create": + # best effort conversion of the arguments ad-hoc text format + var + dict: Assertion + ok: bool + try: (ok, dict) = argumentsToPreserves(req.record[1].record[0]) + except: discard + if ok: req.record[1] = move dict + else: echo "failed to parse ", req.fields[1] + incl(currentRequests, move req) + var publishedRequests = requestHandles.keys.toSeq.toHashSet + # each requests in the XML is published seperately + for req in publishedRequests: + if req notin currentRequests: + var h: Handle + discard pop(requestHandles, req, h) + retract(turn, h) + for req in currentRequests: + if req notin publishedRequests: + requestHandles[req] = publish(turn, ds, req) + scheduleCallbacks() diff --git a/src/syndicate_genode/report_service.cpp b/src/syndicate_genode/report_service.cpp new file mode 100644 index 0000000..3a0c674 --- /dev/null +++ b/src/syndicate_genode/report_service.cpp @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway +// SPDX-License-Identifier: AGPL-3.0-or-later + +/** + * A Report service component that propagates reports into Syndicate. + */ + +#include + // TODO: until the Nim standard library is liberated + // from POSIX assume that calling any Nim proc + // requires a Libc context. + +#include +#include + +extern "C" { +void syndicate_report_submit(void *state, size_t length); +} + +namespace Report { + using namespace Genode; + struct Session_component; +} + +struct Report::Session_component : Genode::Rpc_object +{ + void *_state; + + Dataspace_capability const ds_cap; + + Session_component(void *state, Dataspace_capability ds) + : _state(state), ds_cap(ds) + { } + + Dataspace_capability dataspace() override { return ds_cap; } + + void submit(size_t length) override + { + Libc::with_libc([this, &length] () { + syndicate_report_submit(_state, length); + }); + } + + void response_sigh(Genode::Signal_context_capability) override + { + Genode::warning("Report client called ", __func__); + } + + size_t obtain_response() override + { + Genode::warning("Report client called ", __func__); + return 0; + } +}; diff --git a/src/syndicate_genode/rom_service.cpp b/src/syndicate_genode/rom_service.cpp new file mode 100644 index 0000000..0420b00 --- /dev/null +++ b/src/syndicate_genode/rom_service.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway +// SPDX-License-Identifier: AGPL-3.0-or-later + +/** + * A ROM service component that propagates Syndicate assertions. + */ + +#include + // TODO: until the Nim standard library is liberated + // from POSIX assume that calling any Nim proc + // requires a Libc context. + +#include +#include + +extern "C" { +void syndicate_rom_update(void *state); +void syndicate_rom_sigh(void *state, Genode::Signal_context_capability sigh); +} + +namespace Rom { + using namespace Genode; + struct Session_component; +} + +struct Rom::Session_component : Genode::Rpc_object +{ + void *_state; + + Dataspace_capability const ds_cap; + + Session_component(void *state, Dataspace_capability ds) + : _state(state), ds_cap(ds) + { } + + Rom_dataspace_capability dataspace() override { + return static_cap_cast(ds_cap); } + + bool update() override { syndicate_rom_update(_state); } + + void sigh(Genode::Signal_context_capability sigh) override { + syndicate_rom_sigh(_state, sigh); } +}; diff --git a/src/syndicate_genode/schemas/session_requests.nim b/src/syndicate_genode/schemas/session_requests.nim new file mode 100644 index 0000000..ea527a5 --- /dev/null +++ b/src/syndicate_genode/schemas/session_requests.nim @@ -0,0 +1,76 @@ + +import + std/typetraits, preserves, std/tables + +type + Space*[E] {.preservesRecord: "space".} = ref object + `attrs`*: SpaceAttrs[E] + + LocationAttrs*[E] {.preservesDictionary.} = ref object + `width`*: BiggestInt + `height`*: BiggestInt + `xpos`*: BiggestInt + `ypos`*: BiggestInt + + Args* = Table[Symbol, string] + UpgradeAttrs*[E] {.preservesDictionary.} = ref object + `id`*: BiggestInt + `ram_quota`*: BiggestInt + `cap_quota`*: BiggestInt + + CreateAttrs*[E] {.preservesDictionary.} = ref object + `id`*: BiggestInt + `service`*: string + `label`*: string + + SpaceAttrs*[E] {.preservesDictionary.} = ref object + `width`*: BiggestInt + `height`*: BiggestInt + + UpgradeRequest*[E] {.preservesRecord: "upgrade".} = ref object + `attrs`*: UpgradeAttrs[E] + + CloseAttrs*[E] {.preservesDictionary.} = ref object + `id`*: BiggestInt + + CreateRequest*[E] {.preservesRecord: "create".} = ref object + `attrs`*: CreateAttrs[E] + `args`*: Args + `affinity`*: Affinity[E] + + Affinity*[E] {.preservesRecord: "affinity".} = ref object + `space`*: Space[E] + `location`*: Location[E] + + CloseRequest*[E] {.preservesRecord: "close".} = ref object + `attrs`*: CloseAttrs[E] + + Location*[E] {.preservesRecord: "location".} = ref object + `attrs`*: LocationAttrs[E] + +proc `$`*[E](x: Space[E] | LocationAttrs[E] | UpgradeAttrs[E] | CreateAttrs[E] | + SpaceAttrs[E] | + UpgradeRequest[E] | + CloseAttrs[E] | + CreateRequest[E] | + Affinity[E] | + CloseRequest[E] | + Location[E]): string = + `$`(toPreserve(x, E)) + +proc encode*[E](x: Space[E] | LocationAttrs[E] | UpgradeAttrs[E] | + CreateAttrs[E] | + SpaceAttrs[E] | + UpgradeRequest[E] | + CloseAttrs[E] | + CreateRequest[E] | + Affinity[E] | + CloseRequest[E] | + Location[E]): seq[byte] = + encode(toPreserve(x, E)) + +proc `$`*(x: Args): string = + `$`(toPreserve(x)) + +proc encode*(x: Args): seq[byte] = + encode(toPreserve(x)) diff --git a/src/syndicate_genode/schemas/session_requests.prs b/src/syndicate_genode/schemas/session_requests.prs new file mode 100644 index 0000000..21451ce --- /dev/null +++ b/src/syndicate_genode/schemas/session_requests.prs @@ -0,0 +1,24 @@ +; The Genode "session_requests" ROM as Preserves schema. +; See genode/repos/base/src/lib/base/session_state.cc +version 1. + +; buffer contains comma-seperated key=value pairs +Args = { symbol: string ...:... }. + +SpaceAttrs = { width:int height:int }. +Space = . + +LocationAttrs = { xpos:int ypos:int width:int height:int }. +Location = . + +Affinity = . + +CreateAttrs = { id:int service:string label:string }. + +CreateRequest = . + +UpgradeAttrs = { id:int ram_quota:int cap_quota:int }. +UpgradeRequest = . + +CloseAttrs = { id:int }. +CloseRequest = . diff --git a/src/syndicate_genode/terminal_service.cpp b/src/syndicate_genode/terminal_service.cpp new file mode 100644 index 0000000..1634c6b --- /dev/null +++ b/src/syndicate_genode/terminal_service.cpp @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway +// SPDX-License-Identifier: AGPL-3.0-or-later + +/** + * A Terminal service component for exchanging Syndicate packets. + */ + +#include + // TODO: until the Nim standard library is liberated + // from POSIX assume that calling any Nim proc + // requires a Libc context. + +#include +#include + +extern "C" { +void syndicate_terminal_read_avail_sigh(void *state, Genode::Signal_context_capability); +bool syndicate_terminal_avail(void *state); +size_t syndicate_terminal_write(void *state, size_t length); +size_t syndicate_terminal_read(void *state, size_t length); +} + +namespace Terminal { + using namespace Genode; + struct Session_component; +} + +struct Terminal::Session_component +: Rpc_object +{ + void *_state; + + Dataspace_capability const _ds_cap; + + Session_component(void *state, Dataspace_capability ds) + : _state(state), _ds_cap(ds) + { } + + Size size() override { return Size(0, 0); } + + bool avail() override + { + bool result = false; + Libc::with_libc([this, &result] () { + result = syndicate_terminal_avail(_state); + }); + return result; + } + + Genode::size_t _read(Genode::size_t length) + { + size_t result = 0; + Libc::with_libc([this, length, &result] () { + result = syndicate_terminal_write(_state, length); + }); + return result; + } + + Genode::size_t _write(Genode::size_t length) + { + size_t result = 0; + Libc::with_libc([this, length, &result] () { + result = syndicate_terminal_read(_state, length); + }); + return result; + } + + Dataspace_capability _dataspace() { return _ds_cap; } + + void read_avail_sigh(Signal_context_capability cap) override + { + Libc::with_libc([this, cap] () { + syndicate_terminal_read_avail_sigh(_state, cap); + }); + } + + void size_changed_sigh(Signal_context_capability) override { } + + void connected_sigh(Signal_context_capability sigh) override + { + /* + * Immediately reflect connection-established signal to the + * client because the session is ready to use immediately after + * creation. + */ + Genode::log("send connected signal to terminal client"); + Signal_transmitter(sigh).submit(); + } + + size_t read(void *, size_t) override { return ~0UL; } + size_t write(void const *, size_t) override { return ~0UL; } +}; diff --git a/src/syndicate_service.nim b/src/syndicate_service.nim new file mode 100644 index 0000000..e54acd7 --- /dev/null +++ b/src/syndicate_service.nim @@ -0,0 +1,316 @@ +# SPDX-FileCopyrightText: ☭ Emery Hemingway +# SPDX-License-Identifier: AGPL-3.0-or-later.txt + +import std/[asyncdispatch, deques, options, sets, streams, tables, xmlparser, xmltree] +from std/sequtils import toSeq +import genode, genode/[entrypoints, parents, roms, servers, signals] +import preserves, preserves/xmlhooks +import syndicate, syndicate/[actors, relays] +import ./parent_facets + +type + SessionLabel = seq[string] + + Report {.preservesRecord: "report".} = object + label: SessionLabel + content: Assertion + + SessionObj = object of RootObj + label: SessionLabel + dsCap: RamDataspaceCapability + streams: DataspaceStreamFactory + facet: Facet + dsRef: Ref + + ReportSessionCapability {. + importcpp: "Genode::Capability".} = object + + ReportSessionComponent = Constructible[ReportSessionComponentBase] + ReportSessionComponentBase {. + importcpp: "Report::Session_component", + header: "report_service.cpp".} = object + + ReportSession = ref ReportSessionObj + ReportSessionPtr = ptr ReportSessionObj + ReportSessionObj = object of SessionObj + component: ReportSessionComponent + reportHandle: Handle + + RomSessionCapability {. + importcpp: "Genode::Rom_session_capability", + header: "".} = object + + RomSessionComponent = Constructible[RomSessionComponentBase] + RomSessionComponentBase {. + importcpp: "Rom::Session_component", + header: "rom_service.cpp".} = object + + RomSession = ref RomSessionObj + RomSessionPtr = ptr RomSessionObj + RomSessionObj = object of SessionObj + component: RomSessionComponent + signalContext: SignalContextCapability + + TerminalSessionCapability {. + importcpp: "Genode::Capability".} = object + + TerminalSessionComponent = Constructible[TerminalSessionComponentBase] + TerminalSessionComponentBase {. + importcpp: "Terminal::Session_component", + header: "terminal_service.cpp".} = object + + TerminalSession = ref TerminalSessionObj + TerminalSessionPtr = ptr TerminalSessionObj + TerminalSessionObj = object of SessionObj + component: TerminalSessionComponent + relay: Relay + receiveBuffer: BufferedDecoder + pendingPackets: Deque[Packet] + readAvailSignal: SignalContextCapability + + SessionComponent = + ReportSessionComponent | + RomSessionComponent | + TerminalSessionComponent + Session = + ReportSession | + RomSession | + TerminalSession + +proc construct( + cpp: ReportSessionComponent; + state: pointer; + ds: RamDataspaceCapability) {.importcpp.} + +proc construct( + cpp: RomSessionComponent; + state: pointer; + ds: RamDataspaceCapability) {.importcpp.} + +proc construct( + cpp: TerminalSessionComponent; + state: pointer; + ds: RamDataspaceCapability) {.importcpp.} + +proc dissolve(ep: Entrypoint; s: SessionComponent) {.importcpp: "#.dissolve(*#)".} + +proc dissolve(env: GenodeEnv; s: Session) = + close(s.streams) + dissolve(env.ep, s.component) + freeDataspace(env.pd, s.dsCap) + destruct(s.component) + GC_unref s + +proc dissolve(env: GenodeEnv; turn: var Turn; session: ReportSession) = + retract(turn, session.reportHandle) + dissolve(env, session) + +proc dissolve(env: GenodeEnv; turn: var Turn; session: RomSession) = + dissolve(env, session) + +proc dissolve(env: GenodeEnv; turn: var Turn; session: TerminalSession) = + stop(turn, session.facet) + dissolve(env, session) + +proc manage(ep: Entrypoint; s: ReportSession): ReportSessionCapability = + proc manage(ep: Entrypoint; cpp: ReportSessionComponent + ): ReportSessionCapability {.importcpp: "#.manage(*#)".} + result = manage(ep, s.component) + GC_ref s + +proc manage(ep: Entrypoint; s: RomSession): RomSessionCapability = + proc manage(ep: Entrypoint; cpp: RomSessionComponent + ): RomSessionCapability {.importcpp: "#.manage(*#)".} + result = manage(ep, s.component) + GC_ref s + +proc manage(ep: Entrypoint; s: TerminalSession): TerminalSessionCapability = + proc manage(ep: Entrypoint; cpp: TerminalSessionComponent + ): TerminalSessionCapability {.importcpp: "#.manage(*#)".} + result = manage(ep, s.component) + GC_ref s + +proc initSession( + ses: var SessionObj; + env: GenodeEnv; + label: SessionLabel; + dsCap: RamDataspaceCapability; + facet: Facet; + dsRef: Ref) = + ses.label = label + ses.dsCap = dsCap + ses.streams = newDataspaceStreamFactory(env.rm, ses.dsCap) + ses.facet = facet + ses.dsRef = dsRef + +proc newReportSession( + env: GenodeEnv; + ds: Ref; turn: var Turn; + label: SessionLabel; size: int + ): ReportSession = + var dsCap = allocDataspace(env.pd, size) + new result + initSession(result[], env, label, dsCap, turn.facet, ds) + construct(result.component, addr(result[]), dsCap) + +proc newRomSession( + env: GenodeEnv; + ds: Ref; turn: var Turn; + label: SessionLabel; size: int + ): RomSession = + var dsCap = allocDataspace(env.pd, size) + new result + initSession(result[], env, label, dsCap, turn.facet, ds) + construct(result.component, addr(result[]), dsCap) + +proc newTerminalSession( + env: GenodeEnv; + ds: Ref; turn: var Turn; + label: SessionLabel; size: int + ): TerminalSession = + var dsCap = allocDataspace(env.pd, size) + result = TerminalSession(receiveBuffer: newBufferedDecoder()) + initSession(result[], env, label, dsCap, turn.facet, ds) + construct(result.component, addr(result[]), dsCap) + let session = result + proc queuePacket(pkt: sink Packet): Future[void] {.async.} = + session.pendingPackets.addLast(pkt) + session.readAvailSignal.submit() + # notify the client of the pending packet + var opts = RelayActorOptions( + packetWriter: queuePacket, + initialRef: session.dsRef, + initialOid: 0.Oid.some) + run(session.facet) do (turn: var Turn): + asyncCheck spawnRelay($session.label, turn, opts) do (turn: var Turn; relay: Relay): + session.facet = turn.facet + session.relay = relay + +type SessionCapability = + ReportSessionCapability | + RomSessionCapability | + TerminalSessionCapability + +proc deliverSession*(parent: Parent; id: ServerId; cap: SessionCapability) {. + importcpp: "#->deliver_session_cap(Genode::Parent::Server::Id{#}, #)".} + +proc splitLabel(joined: string): SessionLabel = + joined.labelElements.toSeq + +proc syndicate_report_submit(state: pointer; length: csize_t) {.exportc.} = + assert not state.isNil + let session = cast[ReportSessionPtr](state) + run(session.facet) do (turn: var Turn): + var stream = newStream(session.streams, int length) + try: + replace(turn, session.dsRef, session.reportHandle, Report( + label: session.label, content: parseXml(stream).toPreserve(Ref))) + except: + var raw = newSeq[byte](stream.size) + copyMem(addr raw[0], session.streams.data, raw.len) + replace(turn, session.dsRef, session.reportHandle, Report( + label: session.label, content: raw.toPreserve(Ref))) + close(stream) + scheduleCallbacks() + +proc syndicate_rom_update(state: pointer) {.exportc.} = + assert not state.isNil + let session = cast[RomSessionPtr](state) + run(session.facet) do (turn: var Turn): + var stream = newStream(session.streams) + write(stream, "syndicate_rom_update not implemented, sorry") + close(stream) + scheduleCallbacks() + +proc syndicate_rom_sigh(state: pointer; cap: SignalContextCapability) {.exportc.} = + assert not state.isNil + let session = cast[RomSessionPtr](state) + session.signalContext = cap + +proc syndicate_terminal_read_avail_sigh( + state: pointer; cap: SignalContextCapability) {.exportc.} = + let session = cast[TerminalSessionPtr](state) + session.readAvailSignal = cap + if session.pendingPackets.len > 0: + session.readAvailSignal.submit() + +proc syndicate_terminal_avail(state: pointer): bool {.exportc.} = + let sesssion = cast[TerminalSessionPtr](state) + sesssion.pendingPackets.len > 0 + +proc syndicate_terminal_write(state: pointer; length: csize_t): csize_t {.exportc.} = + let sesssion = cast[TerminalSessionPtr](state) + var stream = sesssion.streams.newStream(int length) + if sesssion.pendingPackets.len > 0: + write(stream, sesssion.pendingPackets.popFirst().toPreserve(WireRef)) + result = stream.getPosition.csize_t + close(stream) + if sesssion.pendingPackets.len > 0: + sesssion.readAvailSignal.submit() + scheduleCallbacks() + +proc syndicate_terminal_read(state: pointer; length: csize_t): csize_t {.exportc.} = + let + session = cast[TerminalSessionPtr](state) + size = min(int length, session.streams.size) + session.receiveBuffer.feed(session.streams.data, size) + var (success, pr) = decode(session.receiveBuffer, WireRef) + if success: + dispatch(session.relay, pr) + scheduleCallbacks() + length + +componentConstructHook = proc(env: GenodeEnv) = + bootDataspace("main") do (ds: Ref; turn: var Turn): + during(turn, ds, grab()) do (a: Assertion): + echo "publish: ", a + do: + echo "retract: ", a + + # newConfigFacet(env, ds, turn) + newSessionRequestsFacet(env, ds, turn) + var + reports = initTable[ServerId, ReportSession]() + roms = initTable[ServerId, RomSession]() + terminals = initTable[ServerId, TerminalSession]() + + onPublish(turn, ds, CreateRequest ? { 0: grab(), 1: ?Args }) do ( + attrs: CreateAttrs, args: Assertion): + var + label = splitLabel(attrs.label) + id = ServerId attrs.id + case attrs.service + of "Report": + var + size = getOrDefault(args, "buffer_size", 0x1000) + session = newReportSession(env, ds, turn, label, size) + deliverSession(env.parent, id, manage(env.ep, session)) + reports[id] = session + of "Rom": + const size = 0x1000 + var session = newRomSession(env, ds, turn, label, size) + deliverSession(env.parent, id, manage(env.ep, session)) + roms[id] = session + of "Terminal": + var + size = getOrDefault(args, "buffer_size", 0x1000) + session = newTerminalSession(env, ds, turn, label, size) + deliverSession(env.parent, id, manage(env.ep, session)) + terminals[id] = session + else: + env.parent.sessionResponseDeny(id) + + onPublish(turn, ds, ?CloseRequest) do (id: ServerId): + var + report: ReportSession + terminal: TerminalSession + if pop(reports, id, report): + dissolve(env, turn, report) + elif pop(terminals, id, terminal): + dissolve(env, turn, terminal) + sessionResponseClose(env.parent, id) + + announce(env.parent, "Report") + announce(env.parent, "ROM") + announce(env.parent, "Terminal") + scheduleCallbacks() diff --git a/syndicate_genode.nimble b/syndicate_genode.nimble new file mode 100644 index 0000000..f44672d --- /dev/null +++ b/syndicate_genode.nimble @@ -0,0 +1,13 @@ +# Package + +version = "20230424" +author = "Emery Hemingway" +description = "Genode Syndicate components" +license = "AGPL-3.0-or-later.txt" +srcDir = "src" +bin = @["syndicate_service"] + + +# Dependencies + +requires "nim >= 1.6.12", "genode", "syndicate"