core, ui: relay management - add, remove relays, synchronization to relay list (#6917)

This commit is contained in:
spaced4ndy
2026-05-08 07:19:16 +00:00
committed by GitHub
parent d9cfc9bd3d
commit 6f8a07e4ea
44 changed files with 1861 additions and 182 deletions
+27 -2
View File
@@ -94,6 +94,9 @@ module Simplex.Chat.Store.Groups
setGroupInProgressDone,
createRelayRequestGroup,
updateRelayOwnStatusFromTo,
updateRelayOwnStatus_,
getRelayServedGroups,
getRelayInactiveGroups,
createNewContactMemberAsync,
createJoiningMember,
getMemberJoinRequest,
@@ -188,7 +191,7 @@ import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
import Data.Ord (Down (..))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Clock (UTCTime (..), getCurrentTime)
import Data.Time.Clock (NominalDiffTime, UTCTime (..), addUTCTime, getCurrentTime)
import Data.Text.Encoding (encodeUtf8)
import Simplex.Chat.Messages
import Simplex.Chat.Operators
@@ -1585,7 +1588,29 @@ updateRelayOwnStatusFromTo db gInfo@GroupInfo {groupId} fromStatus toStatus = do
updateRelayOwnStatus_ :: DB.Connection -> GroupInfo -> RelayStatus -> IO ()
updateRelayOwnStatus_ db GroupInfo {groupId} relayStatus = do
currentTs <- getCurrentTime
DB.execute db "UPDATE groups SET relay_own_status = ?, updated_at = ? WHERE group_id = ?" (relayStatus, currentTs, groupId)
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)
getRelayServedGroups :: DB.Connection -> VersionRangeChat -> User -> IO [GroupInfo]
getRelayServedGroups db vr User {userId, userContactId} = do
map (toGroupInfo vr userContactId [])
<$> DB.query
db
( groupInfoQuery
<> " WHERE g.user_id = ? AND mu.contact_id = ? AND g.relay_own_status IN (?, ?)"
)
(userId, userContactId, RSAccepted, RSActive)
getRelayInactiveGroups :: DB.Connection -> VersionRangeChat -> User -> NominalDiffTime -> IO [GroupInfo]
getRelayInactiveGroups db vr User {userId, userContactId} ttl = do
cutoffTs <- addUTCTime (- ttl) <$> getCurrentTime
map (toGroupInfo vr userContactId [])
<$> DB.query
db
( groupInfoQuery
<> " WHERE g.user_id = ? AND mu.contact_id = ? AND g.relay_own_status = ? AND g.relay_inactive_at IS NOT NULL AND g.relay_inactive_at <= ?"
)
(userId, userContactId, RSInactive, cutoffTs)
createNewContactMemberAsync :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> (CommandId, ConnId) -> VersionChat -> VersionRangeChat -> SubscriptionMode -> ExceptT StoreError IO ()
createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile} memberRole (cmdId, agentConnId) chatV peerChatVRange subMode =
@@ -29,6 +29,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20260122_has_link
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.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Text, Maybe Text)]
@@ -57,7 +58,8 @@ schemaMigrations =
("20260122_has_link", m20260122_has_link, Just down_m20260122_has_link),
("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)
("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)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,19 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.Postgres.Migrations.M20260507_relay_inactive_at where
import Data.Text (Text)
import Text.RawString.QQ (r)
m20260507_relay_inactive_at :: Text
m20260507_relay_inactive_at =
[r|
ALTER TABLE groups ADD COLUMN relay_inactive_at TIMESTAMPTZ;
|]
down_m20260507_relay_inactive_at :: Text
down_m20260507_relay_inactive_at =
[r|
ALTER TABLE groups DROP COLUMN relay_inactive_at;
|]
@@ -962,7 +962,8 @@ CREATE TABLE test_chat_schema.groups (
public_member_count bigint,
relay_request_retries bigint DEFAULT 0 NOT NULL,
relay_request_delay bigint DEFAULT 0 NOT NULL,
relay_request_execute_at timestamp with time zone DEFAULT '1970-01-01 01:00:00+01'::timestamp with time zone NOT NULL
relay_request_execute_at timestamp with time zone DEFAULT '1970-01-01 04:00:00+04'::timestamp with time zone NOT NULL,
relay_inactive_at timestamp with time zone
);
+3 -1
View File
@@ -152,6 +152,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20260122_has_link
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.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Query, Maybe Query)]
@@ -303,7 +304,8 @@ schemaMigrations =
("20260122_has_link", m20260122_has_link, Just down_m20260122_has_link),
("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)
("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)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,18 @@
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.SQLite.Migrations.M20260507_relay_inactive_at where
import Database.SQLite.Simple (Query)
import Database.SQLite.Simple.QQ (sql)
m20260507_relay_inactive_at :: Query
m20260507_relay_inactive_at =
[sql|
ALTER TABLE groups ADD COLUMN relay_inactive_at TEXT;
|]
down_m20260507_relay_inactive_at :: Query
down_m20260507_relay_inactive_at =
[sql|
ALTER TABLE groups DROP COLUMN relay_inactive_at;
|]
@@ -273,6 +273,16 @@ Query:
Plan:
SEARCH connections USING PRIMARY KEY (conn_id=?)
Query:
SELECT user_id FROM users u
WHERE u.deleted = ?
AND NOT EXISTS (SELECT c.conn_id FROM connections c WHERE c.user_id = u.user_id)
Plan:
SCAN u
CORRELATED SCALAR SUBQUERY 1
SEARCH c USING COVERING INDEX idx_connections_user (user_id=?)
Query:
SELECT user_id FROM users u
WHERE u.user_id = ?
@@ -525,6 +535,21 @@ Query:
Plan:
SEARCH conn_confirmations USING COVERING INDEX idx_conn_confirmations_conn_id (conn_id=?)
Query:
DELETE FROM encrypted_rcv_message_hashes
WHERE encrypted_rcv_message_hash_id IN (
SELECT encrypted_rcv_message_hash_id
FROM encrypted_rcv_message_hashes
WHERE created_at < ?
ORDER BY created_at ASC
LIMIT ?
)
Plan:
SEARCH encrypted_rcv_message_hashes USING INTEGER PRIMARY KEY (rowid=?)
LIST SUBQUERY 1
SEARCH encrypted_rcv_message_hashes USING COVERING INDEX idx_encrypted_rcv_message_hashes_created_at (created_at<?)
Query:
INSERT INTO connections
(user_id, conn_id, conn_mode, smp_agent_version, enable_ntfs, pq_support, duplex_handshake) VALUES (?,?,?,?,?,?,?)
@@ -1085,6 +1110,14 @@ Query: SELECT conn_id FROM connections WHERE deleted = 0
Plan:
SCAN connections
Query: SELECT conn_id FROM connections WHERE deleted = ?
Plan:
SCAN connections
Query: SELECT conn_id FROM connections WHERE deleted_at_wait_delivery IS NOT NULL
Plan:
SCAN connections
Query: SELECT conn_id FROM connections WHERE user_id = ?
Plan:
SEARCH connections USING COVERING INDEX idx_connections_user (user_id=?)
@@ -6808,6 +6808,10 @@ Query: SELECT last_insert_rowid()
Plan:
SCAN CONSTANT ROW
Query: SELECT local_display_name FROM group_members
Plan:
SCAN group_members USING COVERING INDEX idx_group_members_user_id_local_display_name
Query: SELECT max(active_order) FROM users
Plan:
SEARCH users
@@ -176,7 +176,8 @@ CREATE TABLE groups(
public_member_count INTEGER,
relay_request_retries INTEGER NOT NULL DEFAULT 0,
relay_request_delay INTEGER NOT NULL DEFAULT 0,
relay_request_execute_at TEXT NOT NULL DEFAULT '1970-01-01 00:00:00', -- received
relay_request_execute_at TEXT NOT NULL DEFAULT '1970-01-01 00:00:00',
relay_inactive_at TEXT, -- received
FOREIGN KEY(user_id, local_display_name)
REFERENCES display_names(user_id, local_display_name)
ON DELETE CASCADE