Cleanup and document syndesizer/webhooks
This commit is contained in:
parent
da8d7ea345
commit
ad3b160e56
29
README.md
29
README.md
|
@ -1,5 +1,34 @@
|
||||||
# Syndicate utils
|
# Syndicate utils
|
||||||
|
|
||||||
|
## Syndesizer
|
||||||
|
|
||||||
|
A Syndicate multitool. Includes a number of different actors that become active via configuration.
|
||||||
|
Whether you use a single instance for many protocols or many specialized instances is up to you.
|
||||||
|
|
||||||
|
### Webooks
|
||||||
|
|
||||||
|
Listens for webhook requests and sends request data to a dataspace as messages.
|
||||||
|
Request data is formated according to the http schema [defined in syndicate-protocols](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/http.prs), with the exception that messages bodies may be **bytes**, **string**, or **any** for the `content-type`s of `application/octet-stream`, `text/*`, and `application/json` respectively.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Configuration example
|
||||||
|
<require-service <daemon syndesizer>>
|
||||||
|
? <service-object <daemon syndesizer> ?cap> [
|
||||||
|
$cap <webhooks {
|
||||||
|
listen: <tcp "0.0.0.0" 1048>
|
||||||
|
endpoints: {
|
||||||
|
|
||||||
|
# http://0.0.0.0:1048/my-endpoint
|
||||||
|
["my-endpoint"]: $target-dataspace
|
||||||
|
|
||||||
|
# http://0.0.0.0:1048/some/multi-element/path
|
||||||
|
["some", "multi-element", "path"]: $target-dataspace
|
||||||
|
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
## cache_actor
|
## cache_actor
|
||||||
|
|
||||||
An actor that observes patterns and reässerts the values they capture for a given lifetime. Takes the arguments `{ dataspace: #!any lifetime: double }`. The lifetime of a cache counts down from moment a value is asserted.
|
An actor that observes patterns and reässerts the values they capture for a given lifetime. Takes the arguments `{ dataspace: #!any lifetime: double }`. The lifetime of a cache counts down from moment a value is asserted.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
version 1 .
|
version 1 .
|
||||||
|
embeddedType EntityRef.Cap .
|
||||||
|
|
||||||
JsonTranslatorConnected = <connected @path string>.
|
JsonTranslatorConnected = <connected @path string>.
|
||||||
|
|
||||||
|
@ -6,3 +7,11 @@ JsonSocketTranslatorArguments = {
|
||||||
dataspace: #!any
|
dataspace: #!any
|
||||||
socket: string
|
socket: string
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
WebhooksArguments = <webhooks {
|
||||||
|
endpoints: {[string ...]: #!any ...:...}
|
||||||
|
listen: Tcp
|
||||||
|
}>.
|
||||||
|
|
||||||
|
# Reused from syndicate-protocols/transportAddress
|
||||||
|
Tcp = <tcp @host string @port int>.
|
||||||
|
|
|
@ -1,18 +1,32 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
preserves
|
preserves, std/tables
|
||||||
|
|
||||||
type
|
type
|
||||||
JsonTranslatorConnected* {.preservesRecord: "connected".} = object
|
JsonTranslatorConnected* {.preservesRecord: "connected".} = object
|
||||||
`path`*: string
|
`path`*: string
|
||||||
|
|
||||||
JsonSocketTranslatorArguments* {.preservesDictionary.} = object
|
JsonSocketTranslatorArguments* {.preservesDictionary.} = object
|
||||||
`dataspace`* {.preservesEmbedded.}: Value
|
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
|
||||||
`socket`*: string
|
`socket`*: string
|
||||||
|
|
||||||
proc `$`*(x: JsonTranslatorConnected | JsonSocketTranslatorArguments): string =
|
WebhooksArgumentsField0* {.preservesDictionary.} = object
|
||||||
|
`endpoints`*: Table[seq[string], EmbeddedRef]
|
||||||
|
`listen`*: Tcp
|
||||||
|
|
||||||
|
WebhooksArguments* {.preservesRecord: "webhooks".} = object
|
||||||
|
`field0`*: WebhooksArgumentsField0
|
||||||
|
|
||||||
|
Tcp* {.preservesRecord: "tcp".} = object
|
||||||
|
`host`*: string
|
||||||
|
`port`*: BiggestInt
|
||||||
|
|
||||||
|
proc `$`*(x: JsonTranslatorConnected | JsonSocketTranslatorArguments |
|
||||||
|
WebhooksArguments |
|
||||||
|
Tcp): string =
|
||||||
`$`(toPreserves(x))
|
`$`(toPreserves(x))
|
||||||
|
|
||||||
proc encode*(x: JsonTranslatorConnected | JsonSocketTranslatorArguments): seq[
|
proc encode*(x: JsonTranslatorConnected | JsonSocketTranslatorArguments |
|
||||||
byte] =
|
WebhooksArguments |
|
||||||
|
Tcp): seq[byte] =
|
||||||
encode(toPreserves(x))
|
encode(toPreserves(x))
|
||||||
|
|
|
@ -10,4 +10,4 @@ import ./syndesizer/webhooks
|
||||||
runActor("syndesizer") do (turn: var Turn; root: Cap):
|
runActor("syndesizer") do (turn: var Turn; root: Cap):
|
||||||
connectStdio(turn, root)
|
connectStdio(turn, root)
|
||||||
discard spawnTimers(turn, root)
|
discard spawnTimers(turn, root)
|
||||||
discard bootWebhookActor(turn, root)
|
discard spawnWebhookActor(turn, root)
|
||||||
|
|
|
@ -7,16 +7,13 @@ import std/[asyncdispatch, asynchttpserver, net, strutils, tables, uri]
|
||||||
|
|
||||||
import preserves, preserves/jsonhooks
|
import preserves, preserves/jsonhooks
|
||||||
import syndicate, syndicate/[bags, relays]
|
import syndicate, syndicate/[bags, relays]
|
||||||
import syndicate/protocols/[http, transportAddress]
|
import syndicate/protocols/http
|
||||||
|
|
||||||
|
import ../schema/config
|
||||||
|
|
||||||
type
|
type
|
||||||
CapBag = Bag[Cap]
|
CapBag = Bag[Cap]
|
||||||
Endpoints = Table[seq[string], Cap]
|
Endpoints = Table[seq[string], Cap]
|
||||||
WebhookArgs {.preservesDictionary.} = object
|
|
||||||
endpoints: Assertion
|
|
||||||
listen: Tcp
|
|
||||||
BootArgs {.preservesDictionary.} = object
|
|
||||||
webhook: WebhookArgs
|
|
||||||
|
|
||||||
func splitPath(s: string): seq[string] = s.strip(chars={'/'}).split('/')
|
func splitPath(s: string): seq[string] = s.strip(chars={'/'}).split('/')
|
||||||
|
|
||||||
|
@ -45,9 +42,17 @@ proc toRecord(req: Request; seqnum: BiggestInt; path: seq[string]): Value =
|
||||||
else:
|
else:
|
||||||
req.body.toPreserves
|
req.body.toPreserves
|
||||||
|
|
||||||
proc bootWebhookActor*(turn: var Turn; root: Cap): Actor =
|
proc spawnWebhookActor*(turn: var Turn; root: Cap): Actor =
|
||||||
spawn("webhooks", turn) do (turn: var Turn):
|
spawn("webhooks", turn) do (turn: var Turn):
|
||||||
during(turn, root, inject(!BootArgs, {1: grab(), 2: grab()})) do (host: string; port: Port):
|
let pat = grabRecord("webhooks", grabDictionary({ "listen": ?:config.Tcp }))
|
||||||
|
# Grab the details on listening for requests.
|
||||||
|
# Disregard endpoints so the server doesn't restart as those change.
|
||||||
|
during(turn, root, pat) do (host: string; port: Port):
|
||||||
|
let endpointsPat = grabRecord("webhooks", grabDictionary({
|
||||||
|
"listen": ?config.Tcp(host: host, port: BiggestInt port),
|
||||||
|
"endpoints": grab(),
|
||||||
|
}))
|
||||||
|
# construct a pattern for grabbing endpoints when the server is ready
|
||||||
var seqNum: BiggestInt
|
var seqNum: BiggestInt
|
||||||
let facet = turn.facet
|
let facet = turn.facet
|
||||||
let endpoints = newTable[seq[string], CapBag]()
|
let endpoints = newTable[seq[string], CapBag]()
|
||||||
|
@ -69,6 +74,7 @@ proc bootWebhookActor*(turn: var Turn; root: Cap): Actor =
|
||||||
run(facet, act)
|
run(facet, act)
|
||||||
|
|
||||||
let server = newAsyncHttpServer()
|
let server = newAsyncHttpServer()
|
||||||
|
stderr.writeLine("listening for webhooks at ", host, ":", port)
|
||||||
if host.isIpAddress:
|
if host.isIpAddress:
|
||||||
var ip = parseIpAddress host
|
var ip = parseIpAddress host
|
||||||
case ip.family
|
case ip.family
|
||||||
|
@ -80,7 +86,7 @@ proc bootWebhookActor*(turn: var Turn; root: Cap): Actor =
|
||||||
asyncCheck(turn, server.serve(port, cb, host, domain = AF_INET6))
|
asyncCheck(turn, server.serve(port, cb, host, domain = AF_INET6))
|
||||||
asyncCheck(turn, server.serve(port, cb, host, domain = AF_INET))
|
asyncCheck(turn, server.serve(port, cb, host, domain = AF_INET))
|
||||||
|
|
||||||
during(turn, root, inject(!BootArgs, {0: grab(), 1: ?host, 2: ?port})) do (eps: Endpoints):
|
during(turn, root, endpointsPat) do (eps: Endpoints):
|
||||||
for path, cap in eps:
|
for path, cap in eps:
|
||||||
if not endpoints.hasKey path:
|
if not endpoints.hasKey path:
|
||||||
endpoints[path] = CapBag()
|
endpoints[path] = CapBag()
|
||||||
|
@ -90,4 +96,10 @@ proc bootWebhookActor*(turn: var Turn; root: Cap): Actor =
|
||||||
discard endpoints[path].change(cap, -1)
|
discard endpoints[path].change(cap, -1)
|
||||||
|
|
||||||
do:
|
do:
|
||||||
|
stderr.writeLine("closing for webhook server at ", host, ":", port)
|
||||||
close(server)
|
close(server)
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
runActor("webhooks") do (turn: var Turn; root: Cap):
|
||||||
|
connectStdio(turn, root)
|
||||||
|
discard spawnWebhookActor(turn, root)
|
||||||
|
|
Loading…
Reference in New Issue