Compare commits

...
Author SHA1 Message Date
Evgeny Poberezkin 79e9447b73 6.2.0.7 2024-12-07 14:36:50 +00:00
spaced4ndy 9893935e7c agent: fix acceptContact inconsistent state after app restart (#1412) 2024-12-05 19:27:21 +04:00
6 changed files with 33 additions and 12 deletions
+16
View File
@@ -1,3 +1,19 @@
# 6.2.0
Version 6.2.0.7
Build:
- client_library flag to build only used modules in the clients, remove package yaml
SMP server:
- journal storage for messages (BETA).
- prevent race condition when deleting queue and to avoid "orphan" messages (#1395).
SMP agent:
- support SMP and XFTP server roles (storage/proxy) and operators (#1343).
- treat blocked STM and other critical errors that offer restart as temporary for message delivery (#1405).
- fix inconsistent state after app restart while accepting contact request (#1412).
# 6.1.3
SMP server: fix restoring notification credentials.
+1 -1
View File
@@ -1,7 +1,7 @@
cabal-version: 1.12
name: simplexmq
version: 6.2.0.6
version: 6.2.0.7
synopsis: SimpleXMQ message broker
description: This package includes <./docs/Simplex-Messaging-Server.html server>,
<./docs/Simplex-Messaging-Client.html client> and
+11 -6
View File
@@ -687,9 +687,15 @@ allowConnectionAsync' c corrId connId confId ownConnInfo =
enqueueCommand c corrId connId (Just server) $ AClientCommand $ LET confId ownConnInfo
_ -> throwE $ CMD PROHIBITED "allowConnectionAsync"
-- TODO
-- Unlike `acceptContact` (synchronous version), `acceptContactAsync` uses `unacceptInvitation` in case of error,
-- because we're not taking lock here. In practice it is less likely to fail because it doesn't involve network IO,
-- and also it can't be triggered by user concurrently several times in a row. It could be improved similarly to
-- `acceptContact` by creating a new map for invitation locks and taking lock here, and removing `unacceptInvitation`
-- while marking invitation as accepted inside "lock level transaction" after successful `joinConnAsync`.
acceptContactAsync' :: AgentClient -> ACorrId -> Bool -> InvitationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AM ConnId
acceptContactAsync' c corrId enableNtfs invId ownConnInfo pqSupport subMode = do
Invitation {contactConnId, connReq} <- withStore c (`getInvitation` invId)
Invitation {contactConnId, connReq} <- withStore c $ \db -> getInvitation db "acceptContactAsync'" invId
withStore c (`getConn` contactConnId) >>= \case
SomeConn _ (ContactConnection ConnData {userId} _) -> do
withStore' c $ \db -> acceptInvitation db invId ownConnInfo
@@ -809,7 +815,7 @@ newConnToJoin c userId connId enableNtfs cReq pqSup = case cReq of
newConnToAccept :: AgentClient -> ConnId -> Bool -> ConfirmationId -> PQSupport -> AM ConnId
newConnToAccept c connId enableNtfs invId pqSup = do
Invitation {connReq, contactConnId} <- withStore c (`getInvitation` invId)
Invitation {connReq, contactConnId} <- withStore c $ \db -> getInvitation db "newConnToAccept" invId
withStore c (`getConn` contactConnId) >>= \case
SomeConn _ (ContactConnection ConnData {userId} _) ->
newConnToJoin c userId connId enableNtfs connReq pqSup
@@ -941,13 +947,12 @@ allowConnection' c connId confId ownConnInfo = withConnLock c connId "allowConne
-- | Accept contact (ACPT command) in Reader monad
acceptContact' :: AgentClient -> ConnId -> Bool -> InvitationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AM SndQueueSecured
acceptContact' c connId enableNtfs invId ownConnInfo pqSupport subMode = withConnLock c connId "acceptContact" $ do
Invitation {contactConnId, connReq} <- withStore c (`getInvitation` invId)
Invitation {contactConnId, connReq} <- withStore c $ \db -> getInvitation db "acceptContact'" invId
withStore c (`getConn` contactConnId) >>= \case
SomeConn _ (ContactConnection ConnData {userId} _) -> do
sqSecured <- joinConn c userId connId enableNtfs connReq ownConnInfo pqSupport subMode
withStore' c $ \db -> acceptInvitation db invId ownConnInfo
joinConn c userId connId enableNtfs connReq ownConnInfo pqSupport subMode `catchAgentError` \err -> do
withStore' c (`unacceptInvitation` invId)
throwE err
pure sqSecured
_ -> throwE $ CMD PROHIBITED "acceptContact"
-- | Reject contact (RJCT command) in Reader monad
+1 -1
View File
@@ -2020,7 +2020,7 @@ storeError = \case
SEConnDuplicate -> CONN DUPLICATE
SEBadConnType CRcv -> CONN SIMPLEX
SEBadConnType CSnd -> CONN SIMPLEX
SEInvitationNotFound -> CMD PROHIBITED "SEInvitationNotFound"
SEInvitationNotFound cxt invId -> CMD PROHIBITED $ "SEInvitationNotFound " <> cxt <> ", invitationId = " <> show invId
-- this error is never reported as store error,
-- it is used to wrap agent operations when "transaction-like" store access is needed
-- NOTE: network IO should NOT be used inside AgentStoreMonad
+1 -1
View File
@@ -623,7 +623,7 @@ data StoreError
| -- | Confirmation not found.
SEConfirmationNotFound
| -- | Invitation not found
SEInvitationNotFound
SEInvitationNotFound String InvitationId
| -- | Message not found
SEMsgNotFound
| -- | Command not found
+3 -3
View File
@@ -926,9 +926,9 @@ createInvitation db gVar NewInvitation {contactConnId, connReq, recipientConnInf
|]
(invitationId, contactConnId, connReq, recipientConnInfo)
getInvitation :: DB.Connection -> InvitationId -> IO (Either StoreError Invitation)
getInvitation db invitationId =
firstRow invitation SEInvitationNotFound $
getInvitation :: DB.Connection -> String -> InvitationId -> IO (Either StoreError Invitation)
getInvitation db cxt invitationId =
firstRow invitation (SEInvitationNotFound cxt invitationId) $
DB.query
db
[sql|