Put TDLib messages in a dedicated local dataspace

Communicating with TDLib on a remote dataspace is wasteful.
Create and assert a local dataspace so that only messages observed
by remote actors are relayed. This also allows the TDLib interface
to be isolated from high-level actors.
This commit is contained in:
Emery Hemingway 2024-05-22 05:59:13 +02:00
parent be910a5ffa
commit 54aefcb22e
5 changed files with 33 additions and 19 deletions

View File

@ -26,13 +26,19 @@ let ?ds = dataspace
]
$ds [
?? <recv {"@type": "error", "code": ?code, "message": ?message}> [
$log ! <log "-" { error: {code: $code, message: $message } }>
? ?v [
$log ! <log "-" { |+++|: $v }>
?- $log ! <log "-" { |---|: $v }>
]
?? <send ?v> [ $log ! <log "-" { |>>>|: $v }> ]
?? <recv ?v> [ $log ! <log "-" { |<<<|: $v }> ]
? ?v [ $log ! <log "-" { assertion: $v }> ]
? <telegram-ready> [
# Raw TDLib interaction.
? <tdlib ?messages> $messages [
?? <send ?v> [ $log ! <log "-" { |>>>|: $v }> ]
?? <recv ?v> [ $log ! <log "-" { |<<<|: $v }> ]
?? <recv {"@type": "error", "code": ?code, "message": ?message}> [
$log ! <log "-" { error: {code: $code, message: $message } }>
]
! <send {"@type": "getOption", "name":"version"}>
?? <recv {"@type": "updateAuthorizationState", "authorization_state": {"@type": "authorizationStateWaitTdlibParameters"}}> [
@ -100,9 +106,7 @@ $ds [
}
}
}> [
$ds ? <user $user_id ?first_name> [
$log ! <log "-" { chat_id: $chat_id, first_name: $first_name, updateChatLastMessage: $text, date: $date, user_id: $user_id }>
]
$log ! <log "-" { updateChatLastMessage: { chat_id: $chat_id, date: $date, text: $text, user_id: $user_id } }>
]
]

View File

@ -1,8 +1,14 @@
version 1 .
# Assert to the actor to register a dataspace for interaction.
TelegramArguments = <telegram-client {
dataspace: #:any
}>.
# Assertion made when the client is ready to process messages.
# Assertion made to when the client is ready to process messages.
TelegramReady = <telegram-ready> .
# Asserted to telegram-client to expose TDLib messages.
# Messages received from and sent to TDLib are in the
# form of <recv {…}> and <sent {…}> respectively.
TDLibClient = <tdlib @messages #:any>.

View File

@ -25,21 +25,22 @@ let actor = bootActor("main") do (turn: Turn):
state.initialRef = ds
during(turn, ds, TelegramArguments.grabTypeFlat) do (ds: Cap):
# Extern actors assert themselves here and a ClientId
# is used to isolate their conversations with tdlib.
let client = td_create_client_id()
state.subscribers[client.int] = ds
let
client = td_create_client_id()
tdlib = turn.newDataspace()
state.subscribers[client.int] = tdlib
onMessage(turn, ds, grabRecord("send", grab())) do (v: Value):
onMessage(turn, tdlib, grabRecord("send", grab())) do (v: Value):
state.buffer.setPosition 0
state.buffer.writeText(v, textJson)
state.buffer.data.setLen state.buffer.getPosition
td_send(client, state.buffer.data)
# TODO: enforce that the subscriber has not set "@client_id"?
publish(turn, ds, TelegramReady())
# Assert to the subscriber that the messages
# it sends will be processed.
publish(turn, ds, TDLibClient(messages: tdlib.embed))
do:
state.subscribers.del client.int

View File

@ -3,6 +3,9 @@ import
preserves
type
TDLibClient* {.preservesRecord: "tdlib".} = object
`messages`* {.preservesEmbedded.}: Value
TelegramReady* {.preservesRecord: "telegram-ready".} = object
TelegramArgumentsField0* {.preservesDictionary.} = object
@ -11,8 +14,8 @@ type
TelegramArguments* {.preservesRecord: "telegram-client".} = object
`field0`*: TelegramArgumentsField0
proc `$`*(x: TelegramReady | TelegramArguments): string =
proc `$`*(x: TDLibClient | TelegramReady | TelegramArguments): string =
`$`(toPreserves(x))
proc encode*(x: TelegramReady | TelegramArguments): seq[byte] =
proc encode*(x: TDLibClient | TelegramReady | TelegramArguments): seq[byte] =
encode(toPreserves(x))

View File

@ -1,4 +1,4 @@
version = "20240521"
version = "20240522"
author = "Emery Hemingway"
description = "Telegram client as a Syndicated Actor"
license = "Unlicense"