core, ui: relay reject rejoin (#6978)

This commit is contained in:
spaced4ndy
2026-05-18 09:06:25 +00:00
committed by GitHub
parent c165663555
commit 92e9640e4f
53 changed files with 1169 additions and 112 deletions
+42 -5
View File
@@ -95,6 +95,8 @@ module Simplex.Chat.Store.Groups
createRelayRequestGroup,
updateRelayOwnStatusFromTo,
updateRelayOwnStatus_,
isRelayGroupRejected,
allowRelayGroup,
getRelayServedGroups,
getRelayInactiveGroups,
createNewContactMemberAsync,
@@ -1523,8 +1525,8 @@ setGroupInProgressDone db GroupInfo {groupId} = do
"UPDATE groups SET creating_in_progress = 0, updated_at = ? WHERE group_id = ?"
(currentTs, groupId)
createRelayRequestGroup :: DB.Connection -> VersionRangeChat -> User -> GroupRelayInvitation -> InvitationId -> VersionRangeChat -> Int64 -> ExceptT StoreError IO (GroupInfo, GroupMember)
createRelayRequestGroup db vr user@User {userId} GroupRelayInvitation {fromMember, fromMemberProfile, relayMemberId, groupLink} invId reqChatVRange initialDelay = do
createRelayRequestGroup :: DB.Connection -> VersionRangeChat -> User -> GroupRelayInvitation -> InvitationId -> VersionRangeChat -> Int64 -> GroupMemberStatus -> RelayStatus -> ExceptT StoreError IO (GroupInfo, GroupMember)
createRelayRequestGroup db vr user@User {userId} GroupRelayInvitation {fromMember, fromMemberProfile, relayMemberId, groupLink} invId reqChatVRange initialDelay memberStatus relayStatus = do
currentTs <- liftIO getCurrentTime
-- Create group with placeholder profile
let Profile {displayName = fromMemberLDN} = fromMemberProfile
@@ -1538,13 +1540,13 @@ createRelayRequestGroup db vr user@User {userId} GroupRelayInvitation {fromMembe
groupPreferences = Nothing,
memberAdmission = Nothing
}
(groupId, _groupLDN) <- createGroup_ db userId placeholderProfile Nothing Nothing True (Just RSInvited) Nothing currentTs
(groupId, _groupLDN) <- createGroup_ db userId placeholderProfile Nothing Nothing True (Just relayStatus) Nothing currentTs
-- Store relay request data for recovery
liftIO $ setRelayRequestData_ groupId currentTs
ownerMemberId <- insertOwner_ currentTs groupId
let relayMember = MemberIdRole relayMemberId GRRelay
-- TODO [member keys] should relays use member keys?
_membership <- createContactMemberInv_ db user groupId (Just ownerMemberId) user relayMember GCUserMember GSMemAccepted IBUnknown Nothing Nothing currentTs vr
_membership <- createContactMemberInv_ db user groupId (Just ownerMemberId) user relayMember GCUserMember memberStatus IBUnknown Nothing Nothing currentTs vr
ownerMember <- getGroupMember db vr user groupId ownerMemberId
g <- getGroupInfo db vr user groupId
pure (g, ownerMember)
@@ -1578,7 +1580,7 @@ createRelayRequestGroup db vr user@User {userId} GroupRelayInvitation {fromMembe
peer_chat_min_version, peer_chat_max_version)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|]
( (groupId, indexInGroup, memberId, memberRole, GCHostMember, GSMemAccepted)
( (groupId, indexInGroup, memberId, memberRole, GCHostMember, memberStatus)
:. (userId, localDisplayName, Nothing :: (Maybe Int64), profileId, currentTs, currentTs)
:. (minV, maxV)
)
@@ -1596,6 +1598,41 @@ updateRelayOwnStatus_ db GroupInfo {groupId} relayStatus = do
let inactiveAt_ = if relayStatus == RSInactive then Just currentTs else Nothing
DB.execute db "UPDATE groups SET relay_own_status = ?, relay_inactive_at = ?, updated_at = ? WHERE group_id = ?" (relayStatus, inactiveAt_, currentTs, groupId)
-- Flip every RSRejected row sharing the targeted group's relay_request_group_link
-- to RSInactive in one statement; returns the refreshed GroupInfo for the targeted groupId.
allowRelayGroup :: DB.Connection -> VersionRangeChat -> User -> GroupId -> ExceptT StoreError IO GroupInfo
allowRelayGroup db vr user@User {userId} groupId = do
currentTs <- liftIO getCurrentTime
liftIO $
DB.execute
db
[sql|
UPDATE groups
SET relay_own_status = ?, relay_inactive_at = ?, updated_at = ?
WHERE user_id = ?
AND relay_request_group_link = (SELECT relay_request_group_link FROM groups WHERE group_id = ?)
AND relay_own_status = ?
|]
(RSInactive, currentTs, currentTs, userId, groupId, RSRejected)
getGroupInfo db vr user groupId
isRelayGroupRejected :: DB.Connection -> User -> ShortLinkContact -> IO Bool
isRelayGroupRejected db User {userId} groupLink =
fromMaybe False <$> maybeFirstRow fromOnly (
DB.query
db
[sql|
SELECT EXISTS (
SELECT 1 FROM groups
WHERE user_id = ?
AND relay_request_group_link = ?
AND relay_own_status = ?
LIMIT 1
)
|]
(userId, groupLink, RSRejected)
)
getRelayServedGroups :: DB.Connection -> VersionRangeChat -> User -> IO [GroupInfo]
getRelayServedGroups db vr User {userId, userContactId} = do
map (toGroupInfo vr userContactId [])
@@ -30,6 +30,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20260222_chat_relays
import Simplex.Chat.Store.Postgres.Migrations.M20260403_item_viewed
import Simplex.Chat.Store.Postgres.Migrations.M20260429_relay_request_retries
import Simplex.Chat.Store.Postgres.Migrations.M20260507_relay_inactive_at
import Simplex.Chat.Store.Postgres.Migrations.M20260514_relay_request_group_link_index
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Text, Maybe Text)]
@@ -59,7 +60,8 @@ schemaMigrations =
("20260222_chat_relays", m20260222_chat_relays, Just down_m20260222_chat_relays),
("20260403_item_viewed", m20260403_item_viewed, Just down_m20260403_item_viewed),
("20260429_relay_request_retries", m20260429_relay_request_retries, Just down_m20260429_relay_request_retries),
("20260507_relay_inactive_at", m20260507_relay_inactive_at, Just down_m20260507_relay_inactive_at)
("20260507_relay_inactive_at", m20260507_relay_inactive_at, Just down_m20260507_relay_inactive_at),
("20260514_relay_request_group_link_index", m20260514_relay_request_group_link_index, Just down_m20260514_relay_request_group_link_index)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,21 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.Postgres.Migrations.M20260514_relay_request_group_link_index where
import Data.Text (Text)
import Text.RawString.QQ (r)
m20260514_relay_request_group_link_index :: Text
m20260514_relay_request_group_link_index =
[r|
CREATE INDEX idx_groups_relay_request_group_link
ON groups(user_id, relay_request_group_link)
WHERE relay_request_group_link IS NOT NULL;
|]
down_m20260514_relay_request_group_link_index :: Text
down_m20260514_relay_request_group_link_index =
[r|
DROP INDEX idx_groups_relay_request_group_link;
|]
@@ -2359,6 +2359,10 @@ CREATE INDEX idx_groups_inv_queue_info ON test_chat_schema.groups USING btree (i
CREATE INDEX idx_groups_relay_request_group_link ON test_chat_schema.groups USING btree (user_id, relay_request_group_link) WHERE (relay_request_group_link IS NOT NULL);
CREATE INDEX idx_groups_summary_current_members_count ON test_chat_schema.groups USING btree (summary_current_members_count);
+3 -1
View File
@@ -153,6 +153,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20260222_chat_relays
import Simplex.Chat.Store.SQLite.Migrations.M20260403_item_viewed
import Simplex.Chat.Store.SQLite.Migrations.M20260429_relay_request_retries
import Simplex.Chat.Store.SQLite.Migrations.M20260507_relay_inactive_at
import Simplex.Chat.Store.SQLite.Migrations.M20260514_relay_request_group_link_index
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Query, Maybe Query)]
@@ -305,7 +306,8 @@ schemaMigrations =
("20260222_chat_relays", m20260222_chat_relays, Just down_m20260222_chat_relays),
("20260403_item_viewed", m20260403_item_viewed, Just down_m20260403_item_viewed),
("20260429_relay_request_retries", m20260429_relay_request_retries, Just down_m20260429_relay_request_retries),
("20260507_relay_inactive_at", m20260507_relay_inactive_at, Just down_m20260507_relay_inactive_at)
("20260507_relay_inactive_at", m20260507_relay_inactive_at, Just down_m20260507_relay_inactive_at),
("20260514_relay_request_group_link_index", m20260514_relay_request_group_link_index, Just down_m20260514_relay_request_group_link_index)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,20 @@
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.SQLite.Migrations.M20260514_relay_request_group_link_index where
import Database.SQLite.Simple (Query)
import Database.SQLite.Simple.QQ (sql)
m20260514_relay_request_group_link_index :: Query
m20260514_relay_request_group_link_index =
[sql|
CREATE INDEX idx_groups_relay_request_group_link
ON groups(user_id, relay_request_group_link)
WHERE relay_request_group_link IS NOT NULL;
|]
down_m20260514_relay_request_group_link_index :: Query
down_m20260514_relay_request_group_link_index =
[sql|
DROP INDEX idx_groups_relay_request_group_link;
|]
@@ -3338,6 +3338,20 @@ SCAN CONSTANT ROW
SCALAR SUBQUERY 1
SCAN groups
Query:
SELECT EXISTS (
SELECT 1 FROM groups
WHERE user_id = ?
AND relay_request_group_link = ?
AND relay_own_status = ?
LIMIT 1
)
Plan:
SCAN CONSTANT ROW
SCALAR SUBQUERY 1
SEARCH groups USING INDEX idx_groups_relay_request_group_link (user_id=? AND relay_request_group_link=?)
Query:
SELECT agent_conn_id
FROM connections
@@ -3955,15 +3969,6 @@ Query:
Plan:
SEARCH chat_items USING INDEX idx_chat_items_group_shared_msg_id (user_id=? AND group_id=? AND group_member_id=?)
Query:
UPDATE chat_items
SET item_deleted = ?, item_deleted_ts = ?, item_deleted_by_group_member_id = ?, updated_at = ?
WHERE user_id = ? AND group_id = ? AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0
RETURNING chat_item_id
Plan:
SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id=? AND msg_content_tag=? AND item_deleted=? AND item_sent=?)
Query:
UPDATE chat_items
SET item_deleted = ?, item_deleted_ts = ?, item_deleted_by_group_member_id = ?, updated_at = ?
@@ -4044,6 +4049,18 @@ Query:
Plan:
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
Query:
UPDATE groups
SET relay_own_status = ?, relay_inactive_at = ?, updated_at = ?
WHERE user_id = ?
AND relay_request_group_link = (SELECT relay_request_group_link FROM groups WHERE group_id = ?)
AND relay_own_status = ?
Plan:
SEARCH groups USING INDEX idx_groups_relay_request_group_link (user_id=? AND relay_request_group_link=?)
SCALAR SUBQUERY 1
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
Query:
UPDATE groups
SET via_group_link_uri = ?, via_group_link_uri_hash = ?
@@ -6586,6 +6603,10 @@ Query: SELECT 1 FROM settings WHERE user_id = ? LIMIT 1
Plan:
SEARCH settings USING COVERING INDEX idx_settings_user_id (user_id=?)
Query: SELECT COUNT(*) FROM groups WHERE relay_own_status IS NOT NULL
Plan:
SCAN groups
Query: SELECT COUNT(1) FROM chat_item_versions WHERE chat_item_id = ?
Plan:
SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_id (chat_item_id=?)
@@ -6801,6 +6822,10 @@ Query: SELECT group_id, conn_full_link_to_connect FROM groups WHERE user_id = ?
Plan:
SEARCH groups USING INDEX sqlite_autoindex_groups_2 (user_id=?)
Query: SELECT group_id, relay_own_status FROM groups WHERE relay_own_status IS NOT NULL ORDER BY group_id
Plan:
SCAN groups
Query: SELECT group_member_id FROM group_members WHERE user_id = ? AND contact_profile_id = ? AND group_member_id != ? LIMIT 1
Plan:
SEARCH group_members USING INDEX idx_group_members_user_id (user_id=?)
@@ -6865,6 +6890,10 @@ Query: SELECT relay_own_status FROM groups WHERE group_id = ?
Plan:
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
Query: SELECT relay_status FROM group_relays
Plan:
SCAN group_relays
Query: SELECT relay_status FROM group_relays WHERE group_relay_id = ?
Plan:
SEARCH group_relays USING INTEGER PRIMARY KEY (rowid=?)
@@ -1295,6 +1295,12 @@ CREATE INDEX idx_chat_items_groups_item_viewed ON chat_items(
item_viewed,
item_ts
);
CREATE INDEX idx_groups_relay_request_group_link
ON groups(
user_id,
relay_request_group_link
)
WHERE relay_request_group_link IS NOT NULL;
CREATE TRIGGER on_group_members_insert_update_summary
AFTER INSERT ON group_members
FOR EACH ROW