Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions examples/pingpong.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import ../src/chat/crypto
proc getContent(content: ContentFrame): string =
# Skip type checks and assume its a TextFrame
let m = decode(content.bytes, TextFrame).valueOr:
raise newException(ValueError, fmt"Badly formed Content")
raise newException(ValueError, fmt"Badly formed ContentType")
return fmt"{m}"

proc toBytes(content: ContentFrame): seq[byte] =
encode(content)

proc fromBytes(bytes: seq[byte]): ContentFrame =
decode(bytes, ContentFrame).valueOr:
raise newException(ValueError, fmt"Badly formed Content")

proc main() {.async.} =

# Create Configurations
Expand All @@ -37,9 +44,10 @@ proc main() {.async.} =
var ri = 0
# Wire Callbacks
saro.onNewMessage(proc(convo: Conversation, msg: ReceivedMessage) {.async.} =
echo " Saro <------ :: " & getContent(msg.content)
let contentFrame = msg.content.fromBytes()
echo " Saro <------ :: " & getContent(contentFrame)
await sleepAsync(5000.milliseconds)
discard await convo.sendMessage(initTextFrame("Ping").toContentFrame())
discard await convo.sendMessage(initTextFrame("Ping").toContentFrame().toBytes())

)

Expand All @@ -51,19 +59,20 @@ proc main() {.async.} =


raya.onNewMessage(proc(convo: Conversation,msg: ReceivedMessage) {.async.} =
echo fmt" ------> Raya :: from:{msg.sender} " & getContent(msg.content)
let contentFrame = msg.content.fromBytes()
echo fmt" ------> Raya :: from:{msg.sender} " & getContent(contentFrame)
await sleepAsync(500.milliseconds)
discard await convo.sendMessage(initTextFrame("Pong" & $ri).toContentFrame())
discard await convo.sendMessage(initTextFrame("Pong" & $ri).toContentFrame().toBytes())
await sleepAsync(800.milliseconds)
discard await convo.sendMessage(initTextFrame("Pong" & $ri).toContentFrame())
discard await convo.sendMessage(initTextFrame("Pong" & $ri).toContentFrame().toBytes())
await sleepAsync(500.milliseconds)
discard await convo.sendMessage(initTextFrame("Pong" & $ri).toContentFrame())
discard await convo.sendMessage(initTextFrame("Pong" & $ri).toContentFrame().toBytes())
inc ri
)

raya.onNewConversation(proc(convo: Conversation) {.async.} =
echo " ------> Raya :: New Conversation: " & convo.id()
discard await convo.sendMessage(initTextFrame("Hello").toContentFrame())
discard await convo.sendMessage(initTextFrame("Hello").toContentFrame().toBytes())
)
raya.onDeliveryAck(proc(convo: Conversation, msgId: string) {.async.} =
echo " raya -- Read Receipt for " & msgId
Expand Down
6 changes: 1 addition & 5 deletions protos/private_v1.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ syntax = "proto3";

package wap.convos.private_v1;

import "common_frames.proto";




message Placeholder {
uint32 counter = 1;
Expand All @@ -16,7 +12,7 @@ message PrivateV1Frame {
bytes sender = 2;
int64 timestamp = 3; // Sender reported timestamp
oneof frame_type {
common_frames.ContentFrame content = 10;
bytes content = 10;
Placeholder placeholder = 11;
// ....
}
Expand Down
3 changes: 1 addition & 2 deletions src/chat.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import chat/[
delivery/waku_client,
identity,
links,
proto_types,
types
]

export client, conversations, identity, links, waku_client

#export specific frames need by applications
export ContentFrame, MessageId
export MessageId

export toHex
2 changes: 1 addition & 1 deletion src/chat/conversations/convo_type.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ method id*(self: Conversation): string {.raises: [Defect, ValueError].} =
# TODO: make this a compile time check
panic("ProgramError: Missing concrete implementation")

method sendMessage*(convo: Conversation, content_frame: ContentFrame) : Future[MessageId] {.async, base, gcsafe.} =
method sendMessage*(convo: Conversation, content_frame: Content) : Future[MessageId] {.async, base, gcsafe.} =
# TODO: make this a compile time check
panic("ProgramError: Missing concrete implementation")
3 changes: 1 addition & 2 deletions src/chat/conversations/message.nim
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import ../crypto
import ../proto_types

# How to surface different verifability of properties across conversation types


type ReceivedMessage* = ref object of RootObj
sender*: PublicKey
timestamp*: int64
content*: ContentFrame
content*: seq[byte]


6 changes: 3 additions & 3 deletions src/chat/conversations/private_v1.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import ../../naxolotl as nax
type
ReceivedPrivateV1Message* = ref object of ReceivedMessage

proc initReceivedMessage(sender: PublicKey, timestamp: int64, content: ContentFrame) : ReceivedPrivateV1Message =
proc initReceivedMessage(sender: PublicKey, timestamp: int64, content: Content) : ReceivedPrivateV1Message =
ReceivedPrivateV1Message(sender:sender, timestamp:timestamp, content:content)


Expand Down Expand Up @@ -209,15 +209,15 @@ proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T,
return

case frame.getKind():
of typeContentFrame:
of typeContent:
# TODO: Using client.getId() results in an error in this context
client.notifyNewMessage(convo, initReceivedMessage(convo.participant, frame.timestamp, frame.content))

of typePlaceholder:
notice "Got Placeholder", text = frame.placeholder.counter


method sendMessage*(convo: PrivateV1, content_frame: ContentFrame) : Future[MessageId] {.async.} =
method sendMessage*(convo: PrivateV1, content_frame: Content) : Future[MessageId] {.async.} =

try:
let frame = PrivateV1Frame(sender: @(convo.owner.getPubkey().bytes()),
Expand Down
3 changes: 1 addition & 2 deletions src/chat/inbox.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import
conversations,
conversation_store,
crypto,
delivery/waku_client,
proto_types,
types

Expand Down Expand Up @@ -107,6 +106,6 @@ proc handleFrame*[T: ConversationStore](convo: Inbox, client: T, bytes: seq[
notice "Receive Note", client = client.getId(), text = frame.note.text


method sendMessage*(convo: Inbox, content_frame: ContentFrame) : Future[MessageId] {.async.} =
method sendMessage*(convo: Inbox, content_frame: Content) : Future[MessageId] {.async.} =
warn "Cannot send message to Inbox"
result = "program_error"
8 changes: 3 additions & 5 deletions src/chat/proto_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ import_proto3 "../../protos/inbox.proto"
# import_proto3 "../protos/invite.proto" // Import3 follows protobuf includes so this will result in a redefinition error
import_proto3 "../../protos/encryption.proto"
import_proto3 "../../protos/envelope.proto"
# import_proto3 "../protos/common_frames.proto"

import_proto3 "../../protos/private_v1.proto"

type EncryptableTypes = InboxV1Frame | EncryptedPayload

export ContentFrame
export EncryptedPayload
export InboxV1Frame
export PrivateV1Frame
Expand Down Expand Up @@ -94,12 +92,12 @@ proc getKind*(obj: InboxV1Frame): InboxV1FrameType =

type
PrivateV1FrameType* = enum
type_ContentFrame, type_Placeholder
type_Content, type_Placeholder

proc getKind*(obj: PrivateV1Frame): PrivateV1FrameType =

if obj.content != ContentFrame():
return type_ContentFrame
if obj.content != @[]:
return type_Content

if obj.placeholder != Placeholder():
return type_Placeholder
Expand Down
1 change: 1 addition & 0 deletions src/chat/types.nim
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
type MessageId* = string
type Content* = seq[byte]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The content may introduce broken changes, should we add version to facilitate the upgrades?
Also the app may choose different ways to encode the content, for example, with or without sds.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The content may introduce broken changes, should we add version to facilitate the upgrades?

Ultimately Applications should be using an interop protocol such as ContentFrames, which handles versioning and type discrimination.

Also the app may choose different ways to encode the content, for example, with or without sds.

  1. Whether SDS is used is determined by the conversation type. Developers ought to not even know it exists.
  2. The proposed solution does not assume anything about the content. If developers want to wrap their content in another protocol, they are free to do so - It just has to be converted to seq[bytes]

Copy link
Collaborator Author

@jazzz jazzz Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR relaxes the requirements and allows developers to choose any format.

If we think versioning and other features should be mandatory(which I could support) then we should close this PR and leave it as is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think versioning is a MUST feature to deliver chat-sdk to 3rd party devs.
Without it, we need a lot of effort to communicate the broken changes, and could be hard to make any major release.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether SDS is used is determined by the conversation type. Developers ought to not even know it exists.

SDS brings some level of reliability, but also introduce burden like increased message size. There maybe other solutions that have different tradeoffs. I think it's better to leave space to devs to decide which reliability protocol to use in the future.

2 changes: 1 addition & 1 deletion src/content_types/all.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import ../chat/proto_types
export protobuf_serialization

import_proto3 "protos/text_frame.proto"
# import_proto3 "../../protos/common_frames.proto"
import_proto3 "protos/common_frames.proto"

export ContentFrame, TextFrame

Expand Down