Skip to content

Commit

Permalink
chat message syntax, raw message type
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Jun 28, 2021
1 parent 9ef5b87 commit b82a6af
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 18 deletions.
23 changes: 21 additions & 2 deletions apps/simplex-chat/Simplex/Chat/Protocol.hs
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
module Simplex.Chat.Protocol where

import Data.Aeson (Value)
import Data.ByteString.Char8 (ByteString)
import Data.Int (Int64)
import Data.Text (Text)
import Simplex.Messaging.Agent.Protocol
import Simplex.Store.Types

data ChatMessage = ChatMessage MsgMeta ChatMsgData
type ChatTransmission = (MsgMeta, ChatMessage)

data ChatMsgData = DirectChatMsg Contact ContentMsg
data ChatMessage = DirectChatMsg Contact ContentMsg

newtype ContentMsg = NewContentMsg ContentData

newtype ContentData = ContentText Text

data RawChatMessage = RawChatMessage
{ chatMsgId :: Maybe Int64,
chatMsgEvent :: ByteString,
chatMsgParams :: [ByteString],
chatMsgBody :: [(ContentType, MsgBodyPart)]
}

type ContentType = ByteString

data MsgBodyPart
= MBFull MsgPart
| MBPartial MsgPart Int ByteString -- MsgPart in this constructor is only used to define type, it's content can (should?) be empty
| MBEmpty

data MsgPart = MsgPartBinary ByteString | MsgPartText Text | MsgPartJSON Value
40 changes: 25 additions & 15 deletions apps/simplex-chat/Simplex/Chat/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@ The syntax of the message inside agent MSG:

```abnf
agentMessageBody = message / msgContinuation
message = msgEvent SP [parameters] SP msgBody
message = [chatMsgId] SP msgEvent SP [parameters] SP msgBody SP
chatMsgId = 1*DIGIT ; used to refer to previous message;
; in the group should only be used in messages sent to all members,
; which is the main reason not to use external agent ID -
; some messages are sent only to one member
msgEvent = protocolNamespace 1*("." msgTypeName)
protocolNamespace = 1*lowercase_letter ; "x" for all messages defined in the protocol
msgTypeName = 1*lowercase_letter
lowercase_letter = %x61-7A ; a-z
parameters = parameter 1*("," parameter)
parameter = <1+ characters without control characters, space, comma>
msgBody = msgBodyPart *(SP msgBodyPart) ; the number of parts should match the number of contentTypes
parameters = parameter *("," parameter)
parameter = 1*(%x21-2B / %x2D-7E) ; exclude control characters, space, comma (%x2C)
msgBody = partNum SP msgBodyPart *(SP msgBodyPart) ; the number of parts should match the number of contentTypes
partNum = 1*DIGIT ; number of message body parts
msgBodyPart = contentType SP encoding [totalPartSize ":"] partSize SP msgData SP
contentType = contentMainType ["/" contentSubType ["+" contentSubSubType]] ; should it be MIME media type?
contentMainType = 1*ALPHA ; e.g. "text", "image", "app", etc.
contentSubType = 1*ALPHA ; e.g. "png", "v1", etc.
contentSubSubType = 1*ALPHA
encoding = %s"b" / %s"t" / %s"j" ; binary, text or JSON
encoding = %s"b" / %s"t" / %s"j" ; binary, text or JSON ; is it needed at all?
; or should it be determined by contentType?
msgData = binMsgData / txtMsgData / jsonMsgData
binMsgData = *OCTET ; binary body
txtMsgData = <utf-8 encoded text>
Expand All @@ -31,19 +37,23 @@ msgEventParent = memberId refMsgId refMsgHash
memberId = 8*8(OCTET) ; shared member ID
refMsgId = 8*8(OCTET) ; sequential message number - external agent message ID
refMsgHash = 16*16(OCTET) ; SHA256 of agent message body
msgContinuation = "#" prevMsgId SP encoding partSize SP msgData *(SP msgBodyPart)
msgContinuation = "#" prevMsgId SP partSize SP msgData *(SP msgBodyPart)
```

### Example: text message and updates

```
"x.msg.new text text t5 hello "
"x.msg.new image image/jpg b256 abcd image/png b4096 abcd "
"x.msg.new image image/jpg b256 abcd image/url t160 https://media.example.com/asdf#abcd "
'x.msg.update 3 text t11 hello there prev b16 abcd '
'x.msg.delete 3'
'x.msg.new app/v1 text/html tNNN ... text/css tNNN ... text/js tNNN ... application/json jNNN {...} '
'x.msg.eval 4 application/json jNNN {...} '
'x.grp.mem.inv 23456 application/json jNNN {...} '
'x.grp.mem.new 23456 application/json jNNN {...} '
"3 x.msg.new text 1 text t5 hello "
"4 x.msg.new image 2 image/jpg b256 abcd image/png b4096 abcd "
"5 x.msg.new image 3 image/jpg b256 abcd image/url t160 https://media.example.com/asdf#abcd "
'6 x.msg.update 3 1 text t11 hello there prev b16 abcd '
'7 x.msg.delete 3'
'8 x.msg.new app/v1 4 text/html tNNN ... text/css tNNN ... text/js tNNN ... application/json jNNN {...} '
'8 x.msg.eval 8 1 application/json jNNN {...} '
' x.grp.mem.inv 23456,123 1 application/json jNNN {...} '
' x.grp.mem.acpt 23456 1 text tNNN invitation '
' x.grp.mem.intro 23456,234 1 application/json jNNN {...} '
' x.grp.mem.inv 23456,234 1 text tNNN invitation '
' x.grp.mem.req 23456,123 1 application/json jNNN {...} '
' x.grp.mem.direct.inv 23456,234 1 text tNNN invitation '
```
6 changes: 5 additions & 1 deletion migrations/20210612_initial.sql
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,21 @@ CREATE TABLE contact_invitations (
CREATE TABLE group_profiles ( -- shared group profiles
group_profile_id INTEGER PRIMARY KEY,
group_ref TEXT NOT NULL, -- this name must not contain spaces
display_name TEXT NOT NULL DEFAULT '',
properties TEXT NOT NULL DEFAULT '{}' -- JSON with user or contact profile
);

CREATE TABLE groups (
group_id INTEGER PRIMARY KEY, -- local group ID
invited_by INTEGER REFERENCES contacts ON DELETE RESTRICT,
external_group_id BLOB NOT NULL,
local_group_ref TEXT NOT NULL UNIQUE, -- local group name without spaces
local_properties TEXT NOT NULL, -- local JSON group properties
group_profile_id INTEGER REFERENCES group_profiles, -- shared group profile
user_group_member_details_id INTEGER NOT NULL
REFERENCES group_member_details (group_member_details_id) ON DELETE RESTRICT,
user_id INTEGER NOT NULL REFERENCES user_id
user_id INTEGER NOT NULL REFERENCES user_id,
UNIQUE (invited_by, external_group_id)
);

CREATE TABLE group_members ( -- group members, excluding the local user
Expand Down
1 change: 1 addition & 0 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ executables:
main: Main.hs
dependencies:
- simplex-chat
- aeson == 1.5.*
- async == 2.2.*
- bytestring == 0.10.*
- composition == 1.0.*
Expand Down

0 comments on commit b82a6af

Please sign in to comment.