This commit is contained in:
spaced4ndy
2026-06-30 13:11:03 +04:00
parent e0bafebd2d
commit 051fd16f21
2 changed files with 15 additions and 15 deletions
+6 -7
View File
@@ -1186,11 +1186,8 @@ serveRoster :: User -> GroupInfo -> GroupMember -> CM ()
serveRoster user gInfo member =
when (member `supportsVersion` groupRosterVersion) $ do
cxt <- chatStoreCxt
-- read the stored blob's own version, not roster_version: roster_version is the acceptance gate (highest
-- version accepted), which a delta can advance past the stored blob when the owner's blob send failed -
-- recording it would over-claim what this member was actually served
withStore' (\db -> (,) <$> getGroupRoster db gInfo <*> getStoredRosterVersion db gInfo) >>= \case
(Just (ownerGMId, brokerTs, sm@SignedMsg {signedBody}, blob_), storedVer_) ->
withStore' (\db -> getStoredGroupRoster db gInfo) >>= \case
Just (ownerGMId, brokerTs, sm@SignedMsg {signedBody}, blob_, storedVer_) ->
case J.eitherDecodeStrict' signedBody :: Either String (ChatMessage 'Json) of
Left e -> logError $ "serveRoster: cannot decode saved roster message: " <> tshow e
Right chatMsg@ChatMessage {msgId} ->
@@ -1200,10 +1197,12 @@ serveRoster user gInfo member =
sendFwdMemberMessage member fwd (VMSigned MSSVerified sm chatMsg)
forM_ ((,) <$> msgId <*> blob_) $ \(sid, blob) ->
sendInlineBlobChunks user gInfo [member] sid blob
-- record the served (stored) version so a member can't re-trigger a full serve at a version it already got
-- record the blob's own stored version as served, not roster_version (the gate): a delta can
-- advance the gate past the stored blob on a failed blob send, and recording the gate would
-- over-claim what this member was actually served, suppressing legitimate catch-up
forM_ storedVer_ $ \v -> withStore' $ \db -> setMemberRosterServedVersion db member v
Left e -> logError $ "serveRoster: roster owner not found: " <> tshow e
(Nothing, _) -> pure ()
Nothing -> pure ()
-- Used in groups with relays to introduce moderators and above to a new member,
-- and to announce the new member to moderators and above.
+9 -8
View File
@@ -93,7 +93,7 @@ module Simplex.Chat.Store.Groups
getStoredRosterVersion,
setMemberRosterServedVersion,
getMemberRosterServedVersion,
getGroupRoster,
getStoredGroupRoster,
RcvRosterTransfer (..),
createRosterTransfer,
getRosterTransferVersion,
@@ -1501,21 +1501,22 @@ getMemberRosterServedVersion db GroupMember {groupMemberId} =
fmap join . maybeFirstRow fromOnly $
DB.query db "SELECT roster_served_version FROM group_members WHERE group_member_id = ?" (Only groupMemberId)
-- The live roster header a relay re-serves to joiners, with the completed blob served alongside it
-- (both are written together at completion, so the blob is present whenever the header is).
getGroupRoster :: DB.Connection -> GroupInfo -> IO (Maybe (GroupMemberId, UTCTime, SignedMsg, Maybe ByteString))
getGroupRoster db GroupInfo {groupId} =
-- The live roster header a relay re-serves to joiners, with the completed blob and its stored version
-- (all written together at completion, so the blob and version are present whenever the header is).
-- Returns the stored version, not roster_version (the gate), so callers serve/record exactly what they hold.
getStoredGroupRoster :: DB.Connection -> GroupInfo -> IO (Maybe (GroupMemberId, UTCTime, SignedMsg, Maybe ByteString, Maybe VersionRoster))
getStoredGroupRoster db GroupInfo {groupId} =
(>>= toRoster)
<$> maybeFirstRow
id
( DB.query
db
"SELECT roster_sending_owner_gm_id, roster_broker_ts, roster_msg_chat_binding, roster_msg_signatures, roster_msg_body, roster_blob FROM groups WHERE group_id = ?"
"SELECT roster_sending_owner_gm_id, roster_broker_ts, roster_msg_chat_binding, roster_msg_signatures, roster_msg_body, roster_blob, stored_roster_version FROM groups WHERE group_id = ?"
(Only groupId)
)
where
toRoster (Just ownerGMId, Just brokerTs, Just cb, Just (Binary sigsBs), Just (Binary body), blob_) =
(\sigs -> (ownerGMId, brokerTs, SignedMsg cb sigs body, (\(Binary b) -> b) <$> blob_)) <$> eitherToMaybe (smpDecode sigsBs)
toRoster (Just ownerGMId, Just brokerTs, Just cb, Just (Binary sigsBs), Just (Binary body), blob_, storedVer_) =
(\sigs -> (ownerGMId, brokerTs, SignedMsg cb sigs body, (\(Binary b) -> b) <$> blob_, storedVer_)) <$> eitherToMaybe (smpDecode sigsBs)
toRoster _ = Nothing
-- A per-source in-flight roster transfer, keyed (group_id, from_member_id): replaces the single