diff --git a/src/simplex_bot_actor.nim b/src/simplex_bot_actor.nim index 2f4e6ea..dd7a41e 100644 --- a/src/simplex_bot_actor.nim +++ b/src/simplex_bot_actor.nim @@ -9,80 +9,55 @@ import ./simplex_bot_actor/[message_types, simple_types, websockets] type Value = Preserve[void] - Args {.preservesDictionary.} = object - dataspace: Cap - url: string - - ContactSubscription {.preservesDictionary.} = object - contact: Attributes - - Internal* {.preservesRecord: "internal".} = object - dataspace: Cap - - Contact = ref object - # TODO: does a Contact get its own facet - dataspace: Cap - capHandle, summaryHandle, profileHandle, chatItemHandle: Handle - - Group = ref object - dataspace: Cap - capHandle, infoHandle: Handle - - # ContactAssertion = simple_types.ContactAssertion[Cap] ContactAssertion {.preservesRecord: "contact".} = object id: int - cap: Cap + info: Attributes GroupAssertion {.preservesRecord: "group".} = object id: int - cap: Cap + info: Attributes -proc updateAttrs(contact: Contact; turn: var Turn; attrs: Attributes) = - replace(turn, contact.dataspace, contact.summaryHandle, attrs) - var profile = attrs.getOrDefault(Symbol"profile") - if not profile.isFalse: - replace(turn, contact.dataspace, contact.profileHandle, profile) + ChatItemAssertion {.preservesRecord: "chat-item".} = object + id: int + info: Attributes -proc updateAttrs(group: Group; turn: var Turn; info: Attributes) = - replace(turn, group.dataspace, group.infoHandle, info) + ContactSubscription {.preservesDictionary.} = object + contact: Attributes + ChatItemMeta {.preservesDictionary.} = object + itemId: int proc `%`(bindings: sink openArray[(string, Pattern)]): Pattern = ## Sugar for creating dictionary patterns. patterns.grabDictionary(bindings) -proc bootContact(turn: var Turn; intern: Cap; contactId: int): Contact = - let contact = Contact(dataspace: newDataspace(turn)) - block: - let pat = grabRecord("recv", %{"resp": %{"contactUpdated": %{ - "fromContact": %{"contactId": grab(contactId)}, - "toContact": grab(), - }}}) - onMessage(turn, intern, pat) do (attrs: Attributes): - updateAttrs(contact, turn, attrs) +proc grabResp(obj: Pattern): Pattern = + grabRecord("recv", %{ "resp": obj }) - block: - let pat = grabRecord("recv", %{"resp": %{"chatItem": %{ - "chatInfo": %{"contact": %{"contactId": grab(contactId)}}, - "chatItem": grab(), - }}}) # TODO: could update contact profiles from these messages - onMessage(turn, intern, pat) do (attrs: Attributes): - var - msgId = cast[seq[byte]](base64.decode(attrs[Symbol"meta"]["itemSharedMsgId".toSymbol].string)) - msg = initRecord("message", Preserve[void](), msgId.toPreserve, attrs[Symbol"content"]) - debugEcho "publish message ", msg - contact.chatItemHandle = publish(turn, contact.dataspace, msg) +proc bootClient(turn: var Turn; extern, intern: Cap) = - contact + var contacts = initTable[int, Handle]() + proc updateContact(turn: var Turn; attrs: Attributes) = + var ass: ContactAssertion + if ass.id.fromPreserve(attrs.getOrDefault(Symbol"contactId")): + ass.info = attrs + contacts[ass.id] = replace(turn, extern, contacts.getOrDefault(ass.id), ass) -proc bootGroup(turn: var Turn; intern: Cap; groupId: int): Group = - let group = Group(dataspace: newDataspace(turn)) - group + var groups = newTable[int, Handle]() + proc updateGroup(turn: var Turn; attrs: Attributes) = + var ass: GroupAssertion + if ass.id.fromPreserve(attrs.getOrDefault(Symbol"groupId")): + ass.info = attrs + groups[ass.id] = replace(turn, extern, groups.getOrDefault(ass.id), ass) -proc bootClient(turn: var Turn; ds, intern: Cap) = - var - contacts = initTable[int, Contact]() - groups = initTable[int, Group]() - # mapping of contactId to Contact data + var chatItems = newTable[int, Handle]() + proc updateChatItem(turn: var Turn; attrs: Attributes) = + var + ass: ChatItemAssertion + meta: ChatItemMeta + if meta.fromPreserve(attrs.getOrDefault(Symbol"meta")): + ass.id = meta.itemId + ass.info = attrs + chatItems[ass.id] = replace(turn, extern, chatItems.getOrDefault(ass.id), ass) block: let dumpStream = openFileStream("/tmp/simplex_bot_actor.log", fmWrite) @@ -92,40 +67,38 @@ proc bootClient(turn: var Turn; ds, intern: Cap) = write(dumpStream, '\n') flush(dumpStream) - block: # concats - let pat = grabRecord("recv", %{"resp": %{ + block: # contacts + let pat = grabResp(%{ "contactSubscriptions": grab(), "type": grab"contactSubSummary", - }}) + }) + debugEcho "grab contacts with ", pat onMessage(turn, intern, pat) do (subs: seq[ContactSubscription]): - for e in subs: - var id: int - if id.fromPreserve(e.contact[Symbol"contactId"]): - var contact = contacts.getOrDefault(id) - if contact.isNil: - contact = bootContact(turn, intern, id) - contacts[id] = contact - contact.capHandle = publish(turn, ds, - ContactAssertion(id: id, cap: contact.dataspace)) - updateAttrs(contact, turn, e.contact) + for sub in subs: updateContact(turn, sub.contact) block: # groups - let pat = grabRecord("recv", %{"resp": %{"groupInfo": grab()}}) - onMessage(turn, intern, pat) do (info: Attributes): - var id: int - if id.fromPreserve(info[Symbol"groupId"]): - var group = groups.getOrDefault(id) - if group.isNil: - group = bootGroup(turn, intern, id) - groups[id] = group - group.capHandle = publish(turn, ds, - GroupAssertion(id: id, cap: group.dataspace)) - updateAttrs(group, turn, info) + let pat = grabResp(%{ "groupInfo": grab() }) + onMessage(turn, intern, pat) do (groupInfo: Attributes): + updateGroup(turn, groupInfo) + block: + let pat = grabResp(%{ "chatItem": %{ "chatInfo": + %{ "groupInfo": grab() }}}) + onMessage(turn, intern, pat) do (groupInfo: Attributes): + updateGroup(turn, groupInfo) - onPublish(turn, ds, ?ContactAssertion) do (contactId: int; cap: Cap): - onPublish(turn, cap, %{"localDisplayName": grab()}) do (name: string): - onPublish(turn, cap, %{"image": ?MIMEData}) do (typ: Symbol, data: seq[byte]): - debugEcho "contact ", name, " has an image of ", data.len, " bytes" + block: # messages + let pat = grabResp(%{ "chatItem": %{ "chatInfo": %{ "chatItem": grab() }}}) + onMessage(turn, intern, pat) do (chatItem: Attributes): + updateChatItem(turn, chatItem) + + onPublish(turn, extern, ContactAssertion ? {0: grab()}) do (contactId: int): + onPublish(turn, extern, ContactAssertion ? { + 0: grab(contactId), 1: %{ "localDisplayName": grab() }}) do (name: string): + debugEcho "contact ", contactId, " is ", name + +type Args {.preservesDictionary.} = object + dataspace: Cap + url: string runActor("eris_actor") do (root: Cap; turn: var Turn): # connectStdio(root, turn) diff --git a/src/simplex_bot_actor/websockets.nim b/src/simplex_bot_actor/websockets.nim index 81b04e0..355237f 100644 --- a/src/simplex_bot_actor/websockets.nim +++ b/src/simplex_bot_actor/websockets.nim @@ -50,6 +50,7 @@ proc spawnWebsocketJsonActor*(turn: var Turn; ds: Cap): Actor {.discardable.} = of Pong, Cont: discard of Close: + stderr.writeLine "closed connection with ", url retract(turn, handle) stop(turn) return