mirror of
https://github.com/logos-messaging/nim-chat-poc.git
synced 2026-01-02 14:13:10 +00:00
Wire delivery acknowledgements
This commit is contained in:
parent
f52150ba83
commit
aefacba0e4
@ -35,6 +35,8 @@ type
|
||||
sender: string
|
||||
content: string
|
||||
timestamp: DateTime
|
||||
id: string
|
||||
isAcknowledged: bool
|
||||
|
||||
ConvoInfo = object
|
||||
name: string
|
||||
@ -71,13 +73,15 @@ proc `==`(a,b: ConvoInfo):bool =
|
||||
# Data Management
|
||||
#################################################
|
||||
|
||||
proc addMessage(conv: var ConvoInfo, sender: string, content: string) =
|
||||
proc addMessage(conv: var ConvoInfo, messageId: MessageId, sender: string, content: string) =
|
||||
|
||||
let now = now()
|
||||
conv.messages.add(Message(
|
||||
sender: sender,
|
||||
id: messageId,
|
||||
content: content,
|
||||
timestamp: now
|
||||
timestamp: now,
|
||||
isAcknowledged: false
|
||||
))
|
||||
conv.lastMsgTime = now
|
||||
|
||||
@ -117,10 +121,13 @@ proc createConvo(app: ChatApp) {.async.} =
|
||||
discard await app.client.newPrivateConversation(toBundle(app.inputInviteBuffer.strip()).get())
|
||||
|
||||
proc sendMessage(app: ChatApp, convoInfo: ptr ConvoInfo, msg: string) {.async.} =
|
||||
convoInfo[].addMessage("You", app.inputBuffer)
|
||||
|
||||
var msgId = ""
|
||||
if convoInfo.convo != nil:
|
||||
await convoInfo.convo.sendMessage(app.client.ds, initTextFrame(msg).toContentFrame())
|
||||
msgId = await convoInfo.convo.sendMessage(app.client.ds, initTextFrame(msg).toContentFrame())
|
||||
|
||||
convoInfo[].addMessage(msgId, "You", app.inputBuffer)
|
||||
|
||||
|
||||
proc setupChatSdk(app: ChatApp) =
|
||||
|
||||
@ -149,6 +156,16 @@ proc setupChatSdk(app: ChatApp) =
|
||||
app.client.onDeliveryAck(proc(convo: Conversation, msgId: string) {.async.} =
|
||||
info "DeliveryAck", msgId=msgId
|
||||
app.logMsgs.add(LogEntry(level: "info",ts: now(), msg: fmt"Ack:{msgId}"))
|
||||
|
||||
var s = ""
|
||||
var msgs = addr app.conversations[convo.id()].messages
|
||||
for i in countdown(msgs[].high, 0):
|
||||
s = fmt"{s},{msgs[i].id}"
|
||||
var m = addr msgs[i]
|
||||
|
||||
if m.id == msgId:
|
||||
m.isAcknowledged = true
|
||||
break # Stop after
|
||||
)
|
||||
|
||||
|
||||
@ -265,11 +282,12 @@ proc drawMsgPane( app: ChatApp, layout: Pane) =
|
||||
|
||||
let m = convo.messages[i]
|
||||
let timeStr = m.timestamp.format("HH:mm:ss")
|
||||
|
||||
var deliveryIcon = " "
|
||||
var remainingText = m.content
|
||||
|
||||
if m.sender == "You":
|
||||
tb.setForegroundColor(fgYellow)
|
||||
deliveryIcon = if m.isAcknowledged: "✔" else: "◯"
|
||||
else:
|
||||
tb.setForegroundColor(fgGreen)
|
||||
|
||||
@ -278,7 +296,7 @@ proc drawMsgPane( app: ChatApp, layout: Pane) =
|
||||
app.logMsgs.add(LogEntry(level: "info",ts: now(), msg: fmt" TOO LONG: {convo.name}"))
|
||||
|
||||
return
|
||||
tb.write(x, y, fmt"[{timeStr}] {m.sender}")
|
||||
tb.write(x, y, fmt"[{timeStr}] {deliveryIcon} {m.sender}")
|
||||
y = y + 1
|
||||
|
||||
while remainingText.len > 0:
|
||||
@ -300,11 +318,12 @@ proc drawMsgPane( app: ChatApp, layout: Pane) =
|
||||
|
||||
let m = convo.messages[i]
|
||||
let timeStr = m.timestamp.format("HH:mm:ss")
|
||||
|
||||
var deliveryIcon = " "
|
||||
var remainingText = m.content
|
||||
|
||||
if m.sender == "You":
|
||||
tb.setForegroundColor(fgYellow)
|
||||
deliveryIcon = if m.isAcknowledged: "✔" else: "◯"
|
||||
else:
|
||||
tb.setForegroundColor(fgGreen)
|
||||
|
||||
@ -322,7 +341,7 @@ proc drawMsgPane( app: ChatApp, layout: Pane) =
|
||||
tb.write(x+3, y, line)
|
||||
y = y - 1
|
||||
|
||||
tb.write(x, y, fmt"[{timeStr}] {m.sender}")
|
||||
tb.write(x, y, fmt"[{timeStr}] {deliveryIcon} {m.sender}")
|
||||
y = y - 2
|
||||
|
||||
proc drawMsgInput( app: ChatApp, layout: Pane) =
|
||||
@ -528,59 +547,10 @@ proc initChatApp(client: Client): Future[ChatApp] {.async.} =
|
||||
|
||||
|
||||
# Add some sample conversations with messages
|
||||
var conv1 = ConvoInfo(name: "Alice", messages: @[])
|
||||
conv1.addMessage("36Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("35You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("34Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("33You", "A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("32Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("31You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("30Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("29You", "A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("28Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("27You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("26Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("25You", "A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim! A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("24Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("23You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("22Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("21You", "A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("20Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("19You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("18Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("17You", "A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("16Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("15You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("14Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("13You", "A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("12Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("11You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("10Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("9You", "The system architecture consists of three main components: the client interface, the processing engine, and the data storage layer. Each component communicates through well-defined APIs that ensure scalability and maintainability. The client interface handles user interactions and validates input data before forwarding requests to the processing engine.")
|
||||
conv1.addMessage("8Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("7You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("6Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("5You", "A terminal-based chat application in Nim!")
|
||||
conv1.addMessage("4Alice", "Hey there! How are you doing?")
|
||||
conv1.addMessage("3You", "I'm doing well, thanks! Working on a new project.")
|
||||
conv1.addMessage("2Alice", "That sounds exciting! What kind of project?")
|
||||
conv1.addMessage("1You", "A terminal-based chat application in Nim!")
|
||||
var conv1 = ConvoInfo(name: "ReadMe", messages: @[])
|
||||
conv1.addMessage("","Bob", "TODO")
|
||||
app.conversations[conv1.name] = conv1
|
||||
|
||||
var conv2 = ConvoInfo(name: "Bob", messages: @[])
|
||||
conv2.addMessage("Bob", "Did you see the game last night?")
|
||||
conv2.addMessage("You", "The system architecture consists of three main components: the client interface, the processing engine, and the data storage layer. Each component communicates through well-defined APIs that ensure scalability and maintainability. The client interface handles user interactions and validates input data before forwarding requests to the processing engine")
|
||||
conv2.addMessage("Bob", "The home team crushed it! 3-0")
|
||||
app.conversations[conv2.name] = conv2
|
||||
|
||||
var conv3 = ConvoInfo(name: "Development Team", messages: @[])
|
||||
conv3.addMessage("Sarah", "Morning standup in 10 minutes")
|
||||
conv3.addMessage("Mike", "I'll be there. Just finishing up the last bug fix.")
|
||||
conv3.addMessage("You", "On my way!")
|
||||
conv3.addMessage("Sarah", "Great! Let's review the sprint progress today.")
|
||||
app.conversations[conv3.name] = conv3
|
||||
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
||||
@ -4,11 +4,12 @@ import chat_sdk/[
|
||||
delivery/waku_client,
|
||||
identity,
|
||||
links,
|
||||
proto_types
|
||||
proto_types,
|
||||
types
|
||||
|
||||
]
|
||||
|
||||
export client, conversations, waku_client, identity, links
|
||||
|
||||
#export specific frames need by applications
|
||||
export ContentFrame
|
||||
export ContentFrame, MessageId
|
||||
|
||||
@ -231,8 +231,6 @@ proc newPrivateConversation*(client: Client,
|
||||
proc parseMessage(client: Client, msg: ChatPayload) {.raises: [ValueError,
|
||||
SerializationError].} =
|
||||
## Receives a incoming payload, decodes it, and processes it.
|
||||
info "Parse", clientId = client.getId(), msg = msg,
|
||||
contentTopic = msg.contentTopic
|
||||
|
||||
let envelope = decode(msg.bytes, WapEnvelopeV1).valueOr:
|
||||
raise newException(ValueError, "Failed to decode WapEnvelopeV1: " & error)
|
||||
|
||||
@ -5,6 +5,7 @@ import strutils
|
||||
import ../proto_types
|
||||
import ../delivery/waku_client
|
||||
import ../utils
|
||||
import ../types
|
||||
|
||||
type
|
||||
ConvoTypes* = enum
|
||||
@ -25,6 +26,6 @@ method id*(self: Conversation): string {.raises: [Defect, ValueError].} =
|
||||
panic("ProgramError: Missing concrete implementation")
|
||||
|
||||
method sendMessage*(convo: Conversation, ds: WakuClient,
|
||||
content_frame: ContentFrame) {.async, base, gcsafe.} =
|
||||
content_frame: ContentFrame) : Future[MessageId] {.async, base, gcsafe.} =
|
||||
# TODO: make this a compile time check
|
||||
panic("ProgramError: Missing concrete implementation")
|
||||
|
||||
@ -116,7 +116,7 @@ proc initPrivateV1*(owner: Identity, participant: PublicKey,
|
||||
raise newException(ValueError, "bad sds channel")
|
||||
|
||||
proc sendFrame(self: PrivateV1, ds: WakuClient,
|
||||
msg: PrivateV1Frame): Future[void]{.async.} =
|
||||
msg: PrivateV1Frame): Future[MessageId]{.async.} =
|
||||
|
||||
let frameBytes = encode(msg)
|
||||
let msgId = self.calcMsgId(frameBytes)
|
||||
@ -130,6 +130,9 @@ proc sendFrame(self: PrivateV1, ds: WakuClient,
|
||||
discard ds.sendPayload(self.getTopic(), encryptedBytes.toEnvelope(
|
||||
self.getConvoId()))
|
||||
|
||||
result = msgId
|
||||
|
||||
|
||||
method id*(self: PrivateV1): string =
|
||||
return getConvoIdRaw(self.participants, self.discriminator)
|
||||
|
||||
@ -166,13 +169,13 @@ proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T,
|
||||
|
||||
|
||||
method sendMessage*(convo: PrivateV1, ds: WakuClient,
|
||||
content_frame: ContentFrame) {.async.} =
|
||||
content_frame: ContentFrame) : Future[MessageId] {.async.} =
|
||||
|
||||
try:
|
||||
let frame = PrivateV1Frame(sender: @(convo.owner.getPubkey().bytes()),
|
||||
timestamp: getCurrentTimestamp(), content: content_frame)
|
||||
|
||||
await convo.sendFrame(ds, frame)
|
||||
result = await convo.sendFrame(ds, frame)
|
||||
except Exception as e:
|
||||
error "Unknown error in PrivateV1:SendMessage"
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import
|
||||
crypto,
|
||||
delivery/waku_client,
|
||||
proto_types,
|
||||
types,
|
||||
utils
|
||||
|
||||
logScope:
|
||||
@ -104,5 +105,6 @@ proc handleFrame*[T: ConversationStore](convo: Inbox, client: T, bytes: seq[
|
||||
|
||||
|
||||
method sendMessage*(convo: Inbox, ds: WakuClient,
|
||||
content_frame: ContentFrame) {.async.} =
|
||||
content_frame: ContentFrame) : Future[MessageId] {.async.} =
|
||||
warn "Cannot send message to Inbox"
|
||||
result = "program_error"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user