Initial commit
This commit is contained in:
commit
f93d36911c
|
@ -0,0 +1,37 @@
|
||||||
|
# websocket_actor
|
||||||
|
|
||||||
|
A [syndicated actor](https://syndicate-lang.org/) for communicating JSON to websocket servers.
|
||||||
|
|
||||||
|
The actor observes `{dataspace: #!any url: string }` assertions and connects to a websocket endpoint. During the lifetime of the connection a `<connected $URL>` assertion is made. Messages recieved from the server are sent to the dataspace wrapped in `<recv …>` records and messages observed as `<send …>` are sent to the server.
|
||||||
|
|
||||||
|
Unfortunately this utility is only as useful and reasonable as the websocket server it is connected to.
|
||||||
|
|
||||||
|
## Example:
|
||||||
|
|
||||||
|
### Syndicate server configuration:
|
||||||
|
```
|
||||||
|
<require-service <daemon websocket_actor>>
|
||||||
|
<daemon websocket_actor {
|
||||||
|
argv: ["/bin/websocket_actor"]
|
||||||
|
protocol: application/syndicate
|
||||||
|
env: { BUILD_SUM: $sum }
|
||||||
|
}>
|
||||||
|
|
||||||
|
let ?exported-dataspace = dataspace
|
||||||
|
<service-object <daemon websocket_actor> ?cap> [
|
||||||
|
$cap { dataspace: $exported-dataspace url: "ws://127.0.0.1:5225/" }
|
||||||
|
]
|
||||||
|
|
||||||
|
<bind <ref { oid: "syndicate" key: #x"" }> $exported-dataspace #f>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shell
|
||||||
|
```
|
||||||
|
# Use the "syndump" utility to log '<recv …>' records from the background.
|
||||||
|
syndump '<recv ?>' &
|
||||||
|
|
||||||
|
# Use the "msg" utilite to send '<send …>' records.
|
||||||
|
# The message command wraps its arguments in a record with a label set to argv[0].
|
||||||
|
cp $(which msg) send
|
||||||
|
send '{ type: "command" body: { type: "body" text: "fuck off webdevs"} }'
|
||||||
|
```
|
|
@ -0,0 +1,3 @@
|
||||||
|
include ../syndicate-nim/depends.tup
|
||||||
|
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
|
||||||
|
NIM_FLAGS += --path:$(TUP_CWD)/../nimble/ws/src
|
|
@ -0,0 +1,5 @@
|
||||||
|
let
|
||||||
|
syndicate = builtins.getFlake "syndicate";
|
||||||
|
pkgs =
|
||||||
|
import <nixpkgs> { overlays = builtins.attrValues syndicate.overlays; };
|
||||||
|
in pkgs.nim2Packages.syndicate_utils
|
|
@ -0,0 +1,3 @@
|
||||||
|
include_rules
|
||||||
|
: websocket_actor.nim | $(SYNDICATE_PROTOCOL) ../<schema> |> !nim_bin |> {bin}
|
||||||
|
: {bin} |> !assert_built |>
|
|
@ -0,0 +1,55 @@
|
||||||
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
|
import std/[asyncdispatch, json]
|
||||||
|
import preserves, preserves/jsonhooks
|
||||||
|
import syndicate
|
||||||
|
import ws
|
||||||
|
|
||||||
|
type
|
||||||
|
Args* {.preservesDictionary.} = object
|
||||||
|
dataspace: Cap
|
||||||
|
url: string
|
||||||
|
|
||||||
|
SendJson* {.preservesRecord: "send".} = object
|
||||||
|
data: JsonNode
|
||||||
|
RecvJson* {.preservesRecord: "recv".} = object
|
||||||
|
data: JsonNode
|
||||||
|
|
||||||
|
runActor("websocket-json-actor") do (root: Cap; turn: var Turn):
|
||||||
|
connectStdio(root, turn)
|
||||||
|
during(turn, root, ?Args) do (ds: Cap, url: string):
|
||||||
|
let facet = turn.facet
|
||||||
|
var
|
||||||
|
ws: WebSocket
|
||||||
|
connectedHandle: Handle
|
||||||
|
newWebSocket(url).addCallback(turn) do (turn: var Turn; sock: WebSocket):
|
||||||
|
ws = sock
|
||||||
|
let connectedHandle = publish(turn, ds, initRecord("connected", url.toPreserve))
|
||||||
|
var fut: Future[(Opcode, string)]
|
||||||
|
proc recvMessage() {.gcsafe.} =
|
||||||
|
fut = receivePacket ws
|
||||||
|
addCallback(fut, facet) do (turn: var Turn):
|
||||||
|
let (opcode, data) = read fut
|
||||||
|
case opcode
|
||||||
|
of Text:
|
||||||
|
message(turn, ds,
|
||||||
|
RecvJson(data: data.parseJson))
|
||||||
|
of Binary:
|
||||||
|
message(turn, ds,
|
||||||
|
initRecord("recv", cast[seq[byte]](data).toPreserve))
|
||||||
|
of Ping:
|
||||||
|
asyncCheck(turn, ws.send(data, Pong))
|
||||||
|
of Pong, Cont:
|
||||||
|
discard
|
||||||
|
of Close:
|
||||||
|
retract(turn, connectedHandle)
|
||||||
|
stderr.writeLine "closed connection with ", url
|
||||||
|
stop(turn)
|
||||||
|
return
|
||||||
|
recvMessage()
|
||||||
|
recvMessage()
|
||||||
|
onMessage(turn, ds, ?SendJson) do (data: JsonNode):
|
||||||
|
asyncCheck(turn, ws.send($data, Text))
|
||||||
|
do:
|
||||||
|
close(ws)
|
|
@ -0,0 +1,6 @@
|
||||||
|
bin = @["websocket_actor"]
|
||||||
|
license = "Unlicense"
|
||||||
|
srcDir = "src"
|
||||||
|
version = "20230913"
|
||||||
|
|
||||||
|
requires: "nim", "syndicate", ws
|
Loading…
Reference in New Issue