From 7651ec4447dcda2dcff4d697cbf60fd7dba77056 Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Mon, 20 Oct 2025 17:17:54 +0400
Subject: [PATCH] types, notes
---
docs/rfcs/2025-10-20-chat-relays.md | 63 +++++++++++++++++++++++++++++
src/Simplex/Chat/Protocol.hs | 10 ++++-
src/Simplex/Chat/Types.hs | 2 +-
3 files changed, 72 insertions(+), 3 deletions(-)
create mode 100644 docs/rfcs/2025-10-20-chat-relays.md
diff --git a/docs/rfcs/2025-10-20-chat-relays.md b/docs/rfcs/2025-10-20-chat-relays.md
new file mode 100644
index 0000000000..4ba7b3560a
--- /dev/null
+++ b/docs/rfcs/2025-10-20-chat-relays.md
@@ -0,0 +1,63 @@
+# Chat relays
+
+## Protocol for adding chat relays to group
+
+```mermaid
+sequenceDiagram
+ participant OSMP as Owner's
SMP server
+ participant O as Owner
+ participant R as Chat relay(s)
+ participant RSMP as Chat relays'
SMP server(s)
+ participant M as Member
+
+note over OSMP, RSMP: Owner creates new group, adds chat relays
+
+O -->> O: 1. Create new group
+O ->> OSMP: 2. Create short link
(group entry point)
+OSMP -->> O:
+O -->> O: 3. Add link to group profile
+O -->> O: 4. Choose chat relays
+par With each relay
+ O ->> R: 5. Contact request
(x.grp.relay.inv)
+ R ->> RSMP: 6. Create relay link
+ RSMP -->> R:
+ R ->> O: 7. Accept request
(x.grp.relay.acpt)
+ O ->> OSMP: 8. Update short link
(add relay link)
+ OSMP -->> O:
+ O ->> R: 9. Notify relay link added
(x.grp.info)
+ R ->> OSMP: 10. Retrieve short link data
+ OSMP -->> R:
+ R -->> R: 11. Check relay link added
+ R ->> O: 12. Confirm to owner
(x.grp.relay.ready)
+end
+O -->> O: 13. Share group short link
(social, out-of-band)
+
+note over OSMP, M: New member connects
+
+M ->> OSMP: 1. Retrieve short link data
+OSMP -->> M:
+M ->> R: 2. Connect via relay link(s)
+R -->> M:
+```
+
+Notes:
+
+- On creating group short link beforehand (step 2).
+
+ We do it for protocol simplicity - to have same logic of updating link data with each relay's link.
+
+ Alternatively owner client could create group link with first relay's link, saving a network request. This would require owner client to track state of creating the link to avoid race on receiving multiple relay links.
+
+- On adding group short link to group profile (step 3).
+
+ For protocol purposes it's only a means of informing chat relays about it in step 9 (x.grp.info).
+
+ Alternatively it could be sent as a standalone object in initial contact request to relay (step 5, x.grp.relay.inv), or in step 9 in special event.
+
+ However, there are other arguments for having group link in profile:
+
+ - Strengthening association between link and profile. Link already contains profile in attached data, but from perspective of group profile link itself is detached. All members "see" the same link they joined via in group profile. Chat relays "see" the same link they created relay links for, and can check it for presence of their relay link at any point.
+
+ - Link is recoverable from profile, e.g. for purpose of restoring connection with group via new chat relays.
+
+ Overall it just seems a natural and convenient way to store group link for all members, rather than having it separately.
diff --git a/src/Simplex/Chat/Protocol.hs b/src/Simplex/Chat/Protocol.hs
index 36764c3a57..f974ee7c9b 100644
--- a/src/Simplex/Chat/Protocol.hs
+++ b/src/Simplex/Chat/Protocol.hs
@@ -329,7 +329,7 @@ data ChatMsgEvent (e :: MsgEncoding) where
XGrpLinkMem :: Profile -> ChatMsgEvent 'Json
XGrpLinkAcpt :: GroupAcceptance -> GroupMemberRole -> MemberId -> ChatMsgEvent 'Json
XGrpRelayInv :: GroupRelayInvitation -> ChatMsgEvent 'Json
- XGrpRelayAcpt :: ConnLinkContact -> ChatMsgEvent 'Json -- TBC short/long/any
+ XGrpRelayAcpt :: ConnLinkContact -> ChatMsgEvent 'Json -- TODO [chat relays] TBC short/long/any
XGrpRelayReady :: ChatMsgEvent 'Json
XGrpMemNew :: MemberInfo -> Maybe MsgScope -> ChatMsgEvent 'Json
XGrpMemIntro :: MemberInfo -> Maybe MemberRestrictions -> ChatMsgEvent 'Json
@@ -1223,7 +1223,13 @@ data ContactShortLinkData = ContactShortLinkData
deriving (Show)
data GroupShortLinkData = GroupShortLinkData
- { groupProfile :: GroupProfile
+ { groupProfile :: GroupProfile,
+ chatRelays :: [ChatRelayInfo]
+ }
+ deriving (Show)
+
+data ChatRelayInfo = ChatRelayInfo
+ { relayLink :: ConnLinkContact
}
deriving (Show)
diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs
index a5651339ad..89aa3dd4f2 100644
--- a/src/Simplex/Chat/Types.hs
+++ b/src/Simplex/Chat/Types.hs
@@ -118,7 +118,7 @@ instance ToField AgentUserId where toField (AgentUserId uId) = toField uId
aUserId :: User -> UserId
aUserId User {agentUserId = AgentUserId uId} = uId
--- TODO [chat relay] filter out chat relay users where necessary (e.g. loading list of users for UI)
+-- TODO [chat relays] filter out chat relay users where necessary (e.g. loading list of users for UI)
data User = User
{ userId :: UserId,
agentUserId :: AgentUserId,