Document
This commit is contained in:
parent
19ce50b98b
commit
8e2845a81f
|
@ -0,0 +1,3 @@
|
||||||
|
# SimpleX bot actor
|
||||||
|
|
||||||
|
A [syndicated actor](https://syndicate-lang.org/) for collecting data from the the [SimpleX](https://simplex.chat/) websocket and reformatting as Syndicate assertions.
|
|
@ -9,6 +9,7 @@ import syndicate, syndicate/relays
|
||||||
import ./schema/simple_types
|
import ./schema/simple_types
|
||||||
|
|
||||||
func step(pr: Assertion; path: varargs[string]): Option[Assertion] =
|
func step(pr: Assertion; path: varargs[string]): Option[Assertion] =
|
||||||
|
## Convenience fuction for traversing levels of JSON hell.
|
||||||
result = some(pr)
|
result = some(pr)
|
||||||
var index = "".toSymbol(Cap)
|
var index = "".toSymbol(Cap)
|
||||||
for s in path:
|
for s in path:
|
||||||
|
@ -17,6 +18,8 @@ func step(pr: Assertion; path: varargs[string]): Option[Assertion] =
|
||||||
result = step(result.get, index)
|
result = step(result.get, index)
|
||||||
|
|
||||||
proc sendCommand(turn: var Turn; ds: Cap; cmd: string) =
|
proc sendCommand(turn: var Turn; ds: Cap; cmd: string) =
|
||||||
|
## Simplex websocket only accepts command
|
||||||
|
## strings in the format of the CLI client.
|
||||||
message(turn, ds, initRecord("send", Command(cmd: cmd).toPreserve))
|
message(turn, ds, initRecord("send", Command(cmd: cmd).toPreserve))
|
||||||
|
|
||||||
proc `%`(bindings: sink openArray[(string, Pattern)]): Pattern =
|
proc `%`(bindings: sink openArray[(string, Pattern)]): Pattern =
|
||||||
|
@ -24,10 +27,13 @@ proc `%`(bindings: sink openArray[(string, Pattern)]): Pattern =
|
||||||
patterns.grabDictionary(bindings)
|
patterns.grabDictionary(bindings)
|
||||||
|
|
||||||
proc grabResp(obj: Pattern): Pattern =
|
proc grabResp(obj: Pattern): Pattern =
|
||||||
|
## Grab the "resp" out of messages received on the websocket.
|
||||||
grabRecord("recv", %{ "resp": obj })
|
grabRecord("recv", %{ "resp": obj })
|
||||||
|
|
||||||
type
|
type
|
||||||
HandleTable = Table[Assertion, Handle]
|
HandleTable = Table[Assertion, Handle]
|
||||||
|
## Table for mapping Simplex identifiers to Syndicate handles.
|
||||||
|
|
||||||
State = ref object
|
State = ref object
|
||||||
ds, websocket: Cap
|
ds, websocket: Cap
|
||||||
contacts, groups, chats: HandleTable
|
contacts, groups, chats: HandleTable
|
||||||
|
@ -37,6 +43,8 @@ proc updateTable(turn: var Turn; state: State; table: var HandleTable; id, ass:
|
||||||
table[id] = replace(turn, state.ds, table.getOrDefault(id), ass)
|
table[id] = replace(turn, state.ds, table.getOrDefault(id), ass)
|
||||||
|
|
||||||
proc extractImagePath(image: Option[Assertion]): string =
|
proc extractImagePath(image: Option[Assertion]): string =
|
||||||
|
## Decode an image and return a content-addressed file-
|
||||||
|
## system path. Otherwise "/dev/null".
|
||||||
const prefix = "data:image/jpg;base64,"
|
const prefix = "data:image/jpg;base64,"
|
||||||
if image.isNone:
|
if image.isNone:
|
||||||
result = "/dev/null"
|
result = "/dev/null"
|
||||||
|
@ -52,6 +60,7 @@ proc extractImagePath(image: Option[Assertion]): string =
|
||||||
writeFile(result, bin)
|
writeFile(result, bin)
|
||||||
|
|
||||||
proc updateContact(turn: var Turn; state: State; id, attrs: Assertion) =
|
proc updateContact(turn: var Turn; state: State; id, attrs: Assertion) =
|
||||||
|
## Update the contact assertion held in the dataspace.
|
||||||
var
|
var
|
||||||
attrs = attrs
|
attrs = attrs
|
||||||
imagePath = attrs.step("profile", "image").extractImagePath
|
imagePath = attrs.step("profile", "image").extractImagePath
|
||||||
|
@ -59,6 +68,7 @@ proc updateContact(turn: var Turn; state: State; id, attrs: Assertion) =
|
||||||
updateTable(turn, state, state.contacts, id, initRecord("contact", attrs))
|
updateTable(turn, state, state.contacts, id, initRecord("contact", attrs))
|
||||||
|
|
||||||
proc updateGroup(turn: var Turn; state: State; id, attrs: Assertion) =
|
proc updateGroup(turn: var Turn; state: State; id, attrs: Assertion) =
|
||||||
|
## Update the group assertion held in the dataspace.
|
||||||
var
|
var
|
||||||
attrs = attrs
|
attrs = attrs
|
||||||
imagePath = attrs.step("groupProfile", "image").extractImagePath
|
imagePath = attrs.step("groupProfile", "image").extractImagePath
|
||||||
|
@ -66,6 +76,7 @@ proc updateGroup(turn: var Turn; state: State; id, attrs: Assertion) =
|
||||||
updateTable(turn, state, state.groups, id, initRecord("group", attrs))
|
updateTable(turn, state, state.groups, id, initRecord("group", attrs))
|
||||||
|
|
||||||
proc updateChat(turn: var Turn; state: State; ass: Assertion) =
|
proc updateChat(turn: var Turn; state: State; ass: Assertion) =
|
||||||
|
## Update the chat assertion held in the dataspace.
|
||||||
var id: Option[Assertion]
|
var id: Option[Assertion]
|
||||||
var info = ass.step("chatInfo", "contact")
|
var info = ass.step("chatInfo", "contact")
|
||||||
if info.isSome:
|
if info.isSome:
|
||||||
|
@ -82,6 +93,7 @@ proc updateChat(turn: var Turn; state: State; ass: Assertion) =
|
||||||
updateTable(turn, state, state.chats, id.get, initRecord("chat", ass))
|
updateTable(turn, state, state.chats, id.get, initRecord("chat", ass))
|
||||||
|
|
||||||
proc bootChats(turn: var Turn; state: State) =
|
proc bootChats(turn: var Turn; state: State) =
|
||||||
|
## Install observers and seed the dataspace.
|
||||||
let
|
let
|
||||||
chatPat = grabResp(%{ "chat": grab() })
|
chatPat = grabResp(%{ "chat": grab() })
|
||||||
chatsPat = grabResp(%{ "chats": grab() })
|
chatsPat = grabResp(%{ "chats": grab() })
|
||||||
|
@ -94,8 +106,10 @@ proc bootChats(turn: var Turn; state: State) =
|
||||||
for chat in chats:
|
for chat in chats:
|
||||||
updateChat(turn, state, chat)
|
updateChat(turn, state, chat)
|
||||||
sendCommand(turn, state.websocket, "/chats")
|
sendCommand(turn, state.websocket, "/chats")
|
||||||
|
# initial chats request to populate dataspace
|
||||||
|
|
||||||
type BootArgs {.preservesDictionary.} = object
|
type BootArgs {.preservesDictionary.} = object
|
||||||
|
# Arguments passed by the Syndicate server on stdin.
|
||||||
dataspace: Cap
|
dataspace: Cap
|
||||||
websocket: Cap
|
websocket: Cap
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue