WiP!
This commit is contained in:
commit
711a7032c0
|
@ -0,0 +1,2 @@
|
|||
# source_env ..
|
||||
use flake sigil#checks.x86_64-linux.nova-nim.nodes.machine.config.genode.init.children.test_nim.package
|
|
@ -0,0 +1 @@
|
|||
/.direnv
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
include_rules
|
||||
: foreach ../*.prs |> !preserves_schema_nim |> {schema}
|
||||
: syndicate_service.nim | {schema} |> !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()
|
|
@ -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 <libc/component.h>
|
||||
// TODO: until the Nim standard library is liberated
|
||||
// from POSIX assume that calling any Nim proc
|
||||
// requires a Libc context.
|
||||
|
||||
#include <report_session/report_session.h>
|
||||
#include <base/rpc_server.h>
|
||||
|
||||
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<Report::Session>
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
|
@ -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 <libc/component.h>
|
||||
// TODO: until the Nim standard library is liberated
|
||||
// from POSIX assume that calling any Nim proc
|
||||
// requires a Libc context.
|
||||
|
||||
#include <rom_session/rom_session.h>
|
||||
#include <base/rpc_server.h>
|
||||
|
||||
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<Genode::Rom_session>
|
||||
{
|
||||
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<Rom_dataspace>(ds_cap); }
|
||||
|
||||
bool update() override { syndicate_rom_update(_state); }
|
||||
|
||||
void sigh(Genode::Signal_context_capability sigh) override {
|
||||
syndicate_rom_sigh(_state, sigh); }
|
||||
};
|
|
@ -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))
|
|
@ -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 = <space @attrs SpaceAttrs>.
|
||||
|
||||
LocationAttrs = { xpos:int ypos:int width:int height:int }.
|
||||
Location = <location @attrs LocationAttrs>.
|
||||
|
||||
Affinity = <affinity @space Space @location Location>.
|
||||
|
||||
CreateAttrs = { id:int service:string label:string }.
|
||||
|
||||
CreateRequest = <create @attrs CreateAttrs @args Args @affinity Affinity>.
|
||||
|
||||
UpgradeAttrs = { id:int ram_quota:int cap_quota:int }.
|
||||
UpgradeRequest = <upgrade @attrs UpgradeAttrs>.
|
||||
|
||||
CloseAttrs = { id:int }.
|
||||
CloseRequest = <close @attrs CloseAttrs>.
|
|
@ -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 <libc/component.h>
|
||||
// TODO: until the Nim standard library is liberated
|
||||
// from POSIX assume that calling any Nim proc
|
||||
// requires a Libc context.
|
||||
|
||||
#include <terminal_session/terminal_session.h>
|
||||
#include <base/rpc_server.h>
|
||||
|
||||
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<Terminal::Session, Session_component>
|
||||
{
|
||||
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; }
|
||||
};
|
|
@ -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<Report::Session>".} = 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: "<rom_session/capability.h>".} = 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<Terminal::Session>".} = 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()
|
|
@ -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"
|
Loading…
Reference in New Issue