logos-chat/src/chat_sdk/inbox.nim
2025-09-26 17:26:11 -07:00

111 lines
3.1 KiB
Nim

import
chronicles,
chronos,
results,
strformat
import
conversations/convo_type,
conversations,
conversation_store,
crypto,
delivery/waku_client,
proto_types,
types,
utils
logScope:
topics = "chat inbox"
type
Inbox* = ref object of Conversation
pubkey: PublicKey
inbox_addr: string
proc `$`*(conv: Inbox): string =
fmt"Inbox: addr->{conv.inbox_addr}"
proc initInbox*(pubkey: PublicKey): Inbox =
## Initializes an Inbox object with the given address and invite callback.
return Inbox(pubkey: pubkey)
proc encrypt*(frame: InboxV1Frame): EncryptedPayload =
return encrypt_plain(frame)
proc decrypt*(inbox: Inbox, encbytes: EncryptedPayload): Result[InboxV1Frame, string] =
let res_frame = decrypt_plain(encbytes.plaintext, InboxV1Frame)
if res_frame.isErr:
error "Failed to decrypt frame: ", err = res_frame.error
return err("Failed to decrypt frame: " & res_frame.error)
result = res_frame
proc wrap_env*(payload: EncryptedPayload, convo_id: string): WapEnvelopeV1 =
let bytes = encode(payload)
let salt = generateSalt()
return WapEnvelopeV1(
payload: bytes,
salt: salt,
conversation_hint: convo_id,
)
proc conversation_id_for*(pubkey: PublicKey): string =
## Generates a conversation ID based on the public key.
return "/convo/inbox/v1/" & pubkey.get_addr()
# TODO derive this from instance of Inbox
proc topic_inbox*(client_addr: string): string =
return "/inbox/" & client_addr
method id*(convo: Inbox): string =
return conversation_id_for(convo.pubkey)
#################################################
# Conversation Creation
#################################################
proc createPrivateV1FromInvite*[T: ConversationStore](client: T,
invite: InvitePrivateV1) =
let destPubkey = loadPublicKeyFromBytes(invite.initiator).valueOr:
raise newException(ValueError, "Invalid public key in intro bundle.")
let deliveryAckCb = proc(
conversation: Conversation,
msgId: string): Future[void] {.async.} =
client.notifyDeliveryAck(conversation, msgId)
let convo = initPrivateV1(client.identity(), destPubkey, "default", deliveryAckCb)
notice "Creating PrivateV1 conversation", client = client.getId(),
topic = convo.getConvoId()
client.addConversation(convo)
proc handleFrame*[T: ConversationStore](convo: Inbox, client: T, bytes: seq[
byte]) =
## Dispatcher for Incoming `InboxV1Frames`.
## Calls further processing depending on the kind of frame.
let enc = decode(bytes, EncryptedPayload).valueOr:
raise newException(ValueError, "Failed to decode payload")
let frame = convo.decrypt(enc).valueOr:
error "Decrypt failed", client = client.getId(), error = error
raise newException(ValueError, "Failed to Decrypt MEssage: " &
error)
case getKind(frame):
of typeInvitePrivateV1:
createPrivateV1FromInvite(client, frame.invitePrivateV1)
of typeNote:
notice "Receive Note", client = client.getId(), text = frame.note.text
method sendMessage*(convo: Inbox, ds: WakuClient,
content_frame: ContentFrame) : Future[MessageId] {.async.} =
warn "Cannot send message to Inbox"
result = "program_error"