commit 3b3b7b8f8f50a21a15bb49e96fae6205f018c191 Author: Emery Hemingway Date: Mon Mar 14 20:44:22 2022 -0500 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..b76cb7f --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +An example of communicating with the Yggdrasil control socket over Syndicate. diff --git a/src/yggdrasilctl.nim b/src/yggdrasilctl.nim new file mode 100644 index 0000000..48da4a1 --- /dev/null +++ b/src/yggdrasilctl.nim @@ -0,0 +1,69 @@ +# 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() diff --git a/yggdrasilctl.nimble b/yggdrasilctl.nimble new file mode 100644 index 0000000..e63b6cb --- /dev/null +++ b/yggdrasilctl.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Emery Hemingway" +description = "An example of communicating with the Yggdrasil control socket over Syndicate" +license = "Unlicense" +srcDir = "src" +bin = @["yggdrasilctl"] + + +# Dependencies + +requires "nim >= 1.6.4"