70 lines
2.3 KiB
Nim
70 lines
2.3 KiB
Nim
# SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway
|
|
# SPDX-License-Identifier: Unlicense
|
|
|
|
import std/[asyncdispatch, asyncnet, json, streams, tables]
|
|
from std/nativesockets import AF_UNIX, SOCK_STREAM, Protocol
|
|
import preserves, preserves/jsonhooks
|
|
import syndicate, syndicate/capabilities
|
|
|
|
type
|
|
Controller = ref object
|
|
ds: Ref
|
|
facet: Facet
|
|
handles: Table[JsonNode, Handle]
|
|
sock: AsyncSocket
|
|
Yggdrasilctl {.preservesRecord: "yggdrasilctl".} = object
|
|
label: string
|
|
payload: JsonNode
|
|
|
|
proc dispatchReplies(ctl: Controller) =
|
|
if not ctl.sock.isClosed:
|
|
ctl.sock.recv(4096).addCallback do (fut: Future[string]):
|
|
if fut.failed:
|
|
close(ctl.sock)
|
|
raise fut.error
|
|
var str = newStringStream(fut.read)
|
|
for js in parseJsonFragments(str):
|
|
if js["status"].getStr == "success":
|
|
run(ctl.facet) do (turn: var Turn):
|
|
var req = js["request"]
|
|
for label, val in js["response"].pairs:
|
|
var resp = Yggdrasilctl(label: label, payload: val)
|
|
ctl.handles[req] =
|
|
replace(turn, ctl.ds, ctl.handles.getOrDefault(req), resp)
|
|
callSoon: dispatchReplies(ctl)
|
|
|
|
proc connectController(facet: Facet; ds: Ref; socketPath: string): Future[Controller] {.async.} =
|
|
var sock = newAsyncSocket(
|
|
domain = AF_UNIX,
|
|
sockType = SOCK_STREAM,
|
|
protocol = cast[Protocol](0),
|
|
buffered = false)
|
|
await connectUnix(sock, socketPath)
|
|
let ctl = Controller(ds: ds, facet: facet, sock: sock)
|
|
dispatchReplies(ctl)
|
|
return ctl
|
|
|
|
proc request(ctl: Controller; req: string; fields: JsonNode): Future[void] =
|
|
var js = %* { "keepalive": true, "request": req, "fields": fields }
|
|
ctl.sock.send($js)
|
|
|
|
proc mint(): SturdyRef =
|
|
var key: array[16, byte]
|
|
mint(key, "syndicate")
|
|
|
|
bootDataspace("main") do (ds: Ref; turn: var Turn):
|
|
|
|
let ctl = waitFor connectController(turn.facet, ds, "/run/yggdrasil/yggdrasil.sock")
|
|
|
|
onMessage(turn, ds, ?Yggdrasilctl) do (label: string, fields: JsonNode):
|
|
asyncCheck ctl.request(label, fields)
|
|
|
|
onPublish(turn, ds, ?Yggdrasilctl) do (label: string, resp: JsonNode):
|
|
stderr.writeLine label, ": ", resp.pretty
|
|
# yggdrasil response test
|
|
|
|
message(turn, ds, Yggdrasilctl(label: "getself", payload: newJObject()))
|
|
# yggdrasil request test
|
|
|
|
for _ in 0..7: poll()
|