json_socket_translator: convert to gatekeeper protocol

This commit is contained in:
Emery Hemingway 2024-06-04 10:54:21 +03:00
parent 1fd920f1c8
commit a40cdbce2c
4 changed files with 43 additions and 53 deletions

View File

@ -88,8 +88,7 @@ $http [
### JSON Socket Translator
Communicate with sockets that send and receive lines of JSON using `<send …>` and `<recv …>` messages.
Do not send messages into the dataspace configure with `<json-socket-translator …>` until `<connected @socketPath string>` is asserted.
Responds to the gatekeeper step `<json-socket-translator { socket: <unix "…"> / <tcp "…" … }> $resolver>`.
```
# MPV configuration example
@ -107,25 +106,11 @@ Do not send messages into the dataspace configure with `<json-socket-translator
protocol: none
}>
let ?mpvSpace = dataspace
? <service-state <daemon mpv-server> ready> [
<require-service <daemon syndesizer>>
? <service-object <daemon syndesizer> ?cap> [
$cap <json-socket-translator {
dataspace: $mpvSpace
socket: <unix "/run/user/1000/mpv.sock">
}>
]
]
$mpvSpace [
let ?resolver = dataspace
$resolver ? <accepted ?mpvSpace> $mpvSpace [
# announce the dataspace when the translator is connected
? <connected $socketPath> [
$config <mpv $mpvSpace>
$config <bind <ref { oid: "mpv" key: #x"" }> $mpvSpace #f>
]
$config <mpv $mpvSpace>
$config <bind <ref { oid: "mpv" key: #x"" }> $mpvSpace #f>
# translate <play-file > to an MPV command
?? <play-file ?file> [
@ -137,6 +122,15 @@ $mpvSpace [
! <send { "command": ["playlist-clear"] }>
]
]
? <service-state <daemon mpv-server> ready> [
<require-service <daemon syndesizer>>
? <service-object <daemon syndesizer> ?cap> [
$cap <resolve <json-socket-translator {
socket: <unix "/run/user/1000/mpv.sock">
}> $resolver>
]
]
```
### JSON Stdio Translator

View File

@ -19,8 +19,6 @@ JsonTranslatorArguments = <json-stdio-translator {
dataspace: #:any
}>.
JsonTranslatorConnected = <connected @address SocketAddress>.
TcpAddress = <tcp @host string @port int>.
UnixAddress = <unix @path string>.
@ -34,8 +32,7 @@ HttpDriverArguments = <http-driver {
dataspace: #:any
}>.
JsonSocketTranslatorArguments = <json-socket-translator {
dataspace: #:any
JsonSocketTranslatorStep = <json-socket-translator {
socket: SocketAddress
}>.

View File

@ -40,16 +40,6 @@ type
Base64DecoderArguments* {.preservesRecord: "base64-decoder".} = object
`field0`*: Base64DecoderArgumentsField0
JsonTranslatorConnected* {.preservesRecord: "connected".} = object
`address`*: SocketAddress
JsonSocketTranslatorArgumentsField0* {.preservesDictionary.} = object
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
`socket`*: SocketAddress
JsonSocketTranslatorArguments* {.preservesRecord: "json-socket-translator".} = object
`field0`*: JsonSocketTranslatorArgumentsField0
XsltArgumentsField0* {.preservesDictionary.} = object
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
@ -62,6 +52,12 @@ type
HttpDriverArguments* {.preservesRecord: "http-driver".} = object
`field0`*: HttpDriverArgumentsField0
JsonSocketTranslatorStepField0* {.preservesDictionary.} = object
`socket`*: SocketAddress
JsonSocketTranslatorStep* {.preservesRecord: "json-socket-translator".} = object
`field0`*: JsonSocketTranslatorStepField0
WebhooksArgumentsField0* {.preservesDictionary.} = object
`endpoints`*: Table[seq[string], EmbeddedRef]
`listen`*: Tcp
@ -131,10 +127,9 @@ type
proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments |
SocketAddress |
Base64DecoderArguments |
JsonTranslatorConnected |
JsonSocketTranslatorArguments |
XsltArguments |
HttpDriverArguments |
JsonSocketTranslatorStep |
WebhooksArguments |
FileSystemUsageArguments |
SqliteArguments |
@ -153,10 +148,9 @@ proc encode*(x: WebsocketArguments | HttpClientArguments |
JsonTranslatorArguments |
SocketAddress |
Base64DecoderArguments |
JsonTranslatorConnected |
JsonSocketTranslatorArguments |
XsltArguments |
HttpDriverArguments |
JsonSocketTranslatorStep |
WebhooksArguments |
FileSystemUsageArguments |
SqliteArguments |

View File

@ -1,11 +1,12 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[json, options]
import pkg/sys/[ioqueue, sockets]
import preserves, preserves/jsonhooks, syndicate
import ../schema/[config, json_messages]
import
std/[json, options],
pkg/sys/[ioqueue, sockets],
pkg/preserves, pkg/preserves/jsonhooks,
pkg/syndicate, pkg/syndicate/protocols/[gatekeeper, sturdy],
../schema/[config, json_messages]
template translateSocketBody {.dirty.} =
# Template workaround for CPS and parameterized types.
@ -24,7 +25,8 @@ template translateSocketBody {.dirty.} =
whelp write(socket[], $data & "\n")
else:
stderr.writeLine "dropped send of ", data
discard publish(turn, ds, initRecord("connected", sa.toPreserves))
discard publish(turn, observer, ResolvedAccepted(responderSession: ds))
# Resolve the <json-socket-translator { }> step.
onStop(facet, kill)
run(facet, setup)
while alive:
@ -45,33 +47,36 @@ template translateSocketBody {.dirty.} =
stderr.writeLine "close socket ", sa
close(socket[])
proc translateSocket(facet: Facet; ds: Cap; sa: TcpAddress) {.asyncio.} =
proc translateSocket(facet: Facet; sa: TcpAddress; ds, observer: Cap) {.asyncio.} =
var
socket = new AsyncConn[Protocol.Tcp]
conn = connectTcpAsync(sa.host, Port sa.port)
socket[] = conn
translateSocketBody()
proc translateSocket(facet: Facet; ds: Cap; sa: UnixAddress) {.asyncio.} =
proc translateSocket(facet: Facet; sa: UnixAddress; ds, observer: Cap) {.asyncio.} =
var
socket = new AsyncConn[Protocol.Unix]
conn = connectUnixAsync(sa.path)
socket[] = conn
translateSocketBody()
proc spawnJsonSocketTranslator*(turn: Turn; root: Cap): Actor {.discardable.} =
proc spawnJsonSocketTranslator*(turn: Turn; relay: Cap): Actor {.discardable.} =
let pat = Resolve?:{ 0: JsonSocketTranslatorStep.grabTypeFlat, 1: grab() }
spawnActor(turn, "json-socket-translator") do (turn: Turn):
during(turn, root, ?:JsonSocketTranslatorArguments) do (ds: Cap, sa: TcpAddress):
during(turn, relay, pat) do (sa: TcpAddress, observer: Cap):
linkActor(turn, "json-socket-translator") do (turn: Turn):
let ds = turn.newDataspace()
discard trampoline:
whelp translateSocket(turn.facet, ds, sa)
during(turn, root, ?:JsonSocketTranslatorArguments) do (ds: Cap, sa: UnixAddress):
whelp translateSocket(turn.facet, sa, ds, observer)
during(turn, relay, pat) do (sa: UnixAddress, observer: Cap):
linkActor(turn, "json-socket-translator") do (turn: Turn):
let ds = turn.newDataspace()
discard trampoline:
whelp translateSocket(turn.facet, ds, sa)
whelp translateSocket(turn.facet, sa, ds, observer)
when isMainModule:
import syndicate/relays
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnJsonSocketTranslator(turn, ds)
resolveEnvironment(turn) do (turn: Turn; relay: Cap):
spawnJsonSocketTranslator(turn, relay)