core: delete connections asynchronously (#1151)

This commit is contained in:
JRoberts
2022-09-30 16:18:43 +04:00
committed by GitHub
parent dd5e99ea42
commit 428d3cdba5
6 changed files with 120 additions and 46 deletions

View File

@@ -468,8 +468,7 @@ processChatCommand = \case
forM_ filesInfo $ \fileInfo -> do
cancelFile user fileInfo `catchError` \_ -> pure ()
withFilesFolder $ \filesFolder -> deleteFile filesFolder fileInfo
withAgent $ \a -> forM_ conns $ \conn ->
deleteConnection a (aConnId conn) `catchError` \(_ :: AgentErrorType) -> pure ()
forM_ conns $ \conn -> deleteAgentConnectionAsync user conn `catchError` \_ -> pure ()
-- functions below are called in separate transactions to prevent crashes on android
-- (possibly, race condition on integrity check?)
withStore' $ \db -> deleteContactConnectionsAndFiles db userId ct
@@ -478,8 +477,8 @@ processChatCommand = \case
pure $ CRContactDeleted ct
gs -> throwChatError $ CEContactGroups ct gs
CTContactConnection -> withChatLock . procCmd $ do
conn <- withStore $ \db -> getPendingContactConnection db userId chatId
withAgent $ \a -> deleteConnection a $ aConnId' conn
conn@PendingContactConnection {pccConnId, pccAgentConnId} <- withStore $ \db -> getPendingContactConnection db userId chatId
deleteAgentConnectionAsync' user pccConnId pccAgentConnId
withStore' $ \db -> deletePendingContactConnection db userId chatId
pure $ CRContactConnectionDeleted conn
CTGroup -> do
@@ -489,7 +488,7 @@ processChatCommand = \case
void $ clearGroupContent user gInfo
withChatLock . procCmd $ do
when (memberActive membership) . void $ sendGroupMessage gInfo members XGrpDel
mapM_ deleteMemberConnection members
forM_ members $ deleteMemberConnection user
-- functions below are called in separate transactions to prevent crashes on android
-- (possibly, race condition on integrity check?)
withStore' $ \db -> deleteGroupConnectionsAndFiles db user gInfo members
@@ -737,8 +736,7 @@ processChatCommand = \case
DeleteMyAddress -> withUser $ \user -> withChatLock $ do
conns <- withStore (`getUserContactLinkConnections` user)
procCmd $ do
withAgent $ \a -> forM_ conns $ \conn ->
deleteConnection a (aConnId conn) `catchError` \(_ :: AgentErrorType) -> pure ()
forM_ conns $ \conn -> deleteAgentConnectionAsync user conn `catchError` \_ -> pure ()
withStore' (`deleteUserContactLink` user)
pure CRUserContactLinkDeleted
ShowMyAddress -> withUser $ \User {userId} ->
@@ -849,13 +847,13 @@ processChatCommand = \case
withChatLock . procCmd $ do
case mStatus of
GSMemInvited -> do
deleteMemberConnection m
deleteMemberConnection user m
withStore' $ \db -> deleteGroupMember db user m
_ -> do
msg <- sendGroupMessage gInfo members $ XGrpMemDel mId
ci <- saveSndChatItem user (CDGroupSnd gInfo) msg (CISndGroupEvent $ SGEMemberDeleted memberId (fromLocalProfile memberProfile)) Nothing Nothing
toView . CRNewChatItem $ AChatItem SCTGroup SMDSnd (GroupChat gInfo) ci
deleteMemberConnection m
deleteMemberConnection user m
withStore' $ \db -> updateGroupMemberStatus db userId m GSMemRemoved
pure $ CRUserDeletedMember gInfo m {memberStatus = GSMemRemoved}
APILeaveGroup groupId -> withUser $ \user@User {userId} -> do
@@ -865,7 +863,7 @@ processChatCommand = \case
ci <- saveSndChatItem user (CDGroupSnd gInfo) msg (CISndGroupEvent SGEUserLeft) Nothing Nothing
toView . CRNewChatItem $ AChatItem SCTGroup SMDSnd (GroupChat gInfo) ci
-- TODO delete direct connections that were unused
mapM_ deleteMemberConnection members
forM_ members $ deleteMemberConnection user
withStore' $ \db -> updateGroupMemberStatus db userId membership GSMemLeft
pure $ CRLeftMemberUser gInfo {membership = membership {memberStatus = GSMemLeft}}
APIListMembers groupId -> CRGroupMembers <$> withUser (\user -> withStore (\db -> getGroup db user groupId))
@@ -1744,7 +1742,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
withStore' $ \db -> updateSndFileChunkSent db ft msgId
unless (fileStatus == FSCancelled) $ sendFileChunk user ft
MERR _ err -> do
cancelSndFileTransfer ft
cancelSndFileTransfer user ft
case err of
SMP SMP.AUTH -> unless (fileStatus == FSCancelled) $ do
ci <- withStore $ \db -> getChatItemByFileId db user fileId
@@ -1811,7 +1809,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
getChatItemByFileId db user fileId
toView $ CRRcvFileComplete ci
closeFileHandle fileId rcvFiles
withAgent (`deleteConnection` agentConnId)
deleteAgentConnectionAsync user conn
RcvChunkDuplicate -> pure ()
RcvChunkError -> badRcvFileChunk ft $ "incorrect chunk number " <> show chunkNo
OK ->
@@ -2350,7 +2348,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
members <- withStore' $ \db -> getGroupMembers db user gInfo
if memberId (membership :: GroupMember) == memId
then do
mapM_ deleteMemberConnection members
forM_ members $ deleteMemberConnection user
withStore' $ \db -> updateGroupMemberStatus db userId membership GSMemRemoved
ci <- saveRcvChatItem user (CDGroupRcv gInfo m) msg msgMeta (CIRcvGroupEvent RGEUserDeleted) Nothing
groupMsgToView gInfo m ci msgMeta
@@ -2362,7 +2360,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
if mRole < GRAdmin || mRole < memberRole (member :: GroupMember)
then messageError "x.grp.mem.del with insufficient member permissions"
else do
deleteMemberConnection member
deleteMemberConnection user member
withStore' $ \db -> updateGroupMemberStatus db userId member GSMemRemoved
ci <- saveRcvChatItem user (CDGroupRcv gInfo m) msg msgMeta (CIRcvGroupEvent $ RGEMemberDeleted groupMemberId (fromLocalProfile memberProfile)) Nothing
groupMsgToView gInfo m ci msgMeta
@@ -2373,7 +2371,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
xGrpLeave :: GroupInfo -> GroupMember -> RcvMessage -> MsgMeta -> m ()
xGrpLeave gInfo m msg msgMeta = do
deleteMemberConnection m
deleteMemberConnection user m
withStore' $ \db -> updateGroupMemberStatus db userId m GSMemLeft
ci <- saveRcvChatItem user (CDGroupRcv gInfo m) msg msgMeta (CIRcvGroupEvent RGEMemberLeft) Nothing
groupMsgToView gInfo m ci msgMeta
@@ -2386,7 +2384,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
members <- getGroupMembers db user gInfo
updateGroupMemberStatus db userId membership GSMemGroupDeleted
pure members
mapM_ deleteMemberConnection ms
forM_ ms $ deleteMemberConnection user
ci <- saveRcvChatItem user (CDGroupRcv gInfo m) msg msgMeta (CIRcvGroupEvent RGEGroupDeleted) Nothing
groupMsgToView gInfo m ci msgMeta
toView $ CRGroupDeleted gInfo {membership = membership {memberStatus = GSMemGroupDeleted}} m
@@ -2404,7 +2402,7 @@ parseChatMessage :: ByteString -> Either ChatError ChatMessage
parseChatMessage = first (ChatError . CEInvalidChatMessage) . strDecode
sendFileChunk :: ChatMonad m => User -> SndFileTransfer -> m ()
sendFileChunk user ft@SndFileTransfer {fileId, fileStatus, agentConnId = AgentConnId acId} =
sendFileChunk user ft@SndFileTransfer {fileId, fileStatus, connId, agentConnId} =
unless (fileStatus == FSComplete || fileStatus == FSCancelled) $
withStore' (`createSndFileChunk` ft) >>= \case
Just chunkNo -> sendFileChunkNo ft chunkNo
@@ -2415,7 +2413,7 @@ sendFileChunk user ft@SndFileTransfer {fileId, fileStatus, agentConnId = AgentCo
updateDirectCIFileStatus db user fileId CIFSSndComplete
toView $ CRSndFileComplete ci ft
closeFileHandle fileId sndFiles
withAgent (`deleteConnection` acId)
deleteAgentConnectionAsync' user connId agentConnId
sendFileChunkNo :: ChatMonad m => SndFileTransfer -> Integer -> m ()
sendFileChunkNo ft@SndFileTransfer {agentConnId = AgentConnId acId} chunkNo = do
@@ -2496,26 +2494,25 @@ cancelRcvFileTransfer user ft@RcvFileTransfer {fileId, fileStatus} = do
updateRcvFileStatus db ft FSCancelled
deleteRcvFileChunks db ft
case fileStatus of
RFSAccepted RcvFileInfo {agentConnId = AgentConnId acId} ->
withAgent (`deleteConnection` acId)
RFSConnected RcvFileInfo {agentConnId = AgentConnId acId} ->
withAgent (`deleteConnection` acId)
RFSAccepted RcvFileInfo {connId, agentConnId} ->
deleteAgentConnectionAsync' user connId agentConnId
RFSConnected RcvFileInfo {connId, agentConnId} ->
deleteAgentConnectionAsync' user connId agentConnId
_ -> pure ()
cancelSndFile :: ChatMonad m => User -> FileTransferMeta -> [SndFileTransfer] -> m ()
cancelSndFile user FileTransferMeta {fileId} fts = do
withStore' $ \db -> updateFileCancelled db user fileId CIFSSndCancelled
forM_ fts $ \ft' -> cancelSndFileTransfer ft'
forM_ fts $ \ft' -> cancelSndFileTransfer user ft'
cancelSndFileTransfer :: ChatMonad m => SndFileTransfer -> m ()
cancelSndFileTransfer ft@SndFileTransfer {agentConnId = AgentConnId acId, fileStatus} =
cancelSndFileTransfer :: ChatMonad m => User -> SndFileTransfer -> m ()
cancelSndFileTransfer user ft@SndFileTransfer {connId, agentConnId = agentConnId@(AgentConnId acId), fileStatus} =
unless (fileStatus == FSCancelled || fileStatus == FSComplete) $ do
withStore' $ \db -> do
updateSndFileStatus db ft FSCancelled
deleteSndFileChunks db ft
withAgent $ \a -> do
void (sendMessage a acId SMP.noMsgFlags $ smpEncode FileChunkCancel) `catchError` \_ -> pure ()
deleteConnection a acId
withAgent $ \a -> void (sendMessage a acId SMP.noMsgFlags $ smpEncode FileChunkCancel) `catchError` \_ -> pure ()
deleteAgentConnectionAsync' user connId agentConnId
closeFileHandle :: ChatMonad m => Int64 -> (ChatController -> TVar (Map Int64 Handle)) -> m ()
closeFileHandle fileId files = do
@@ -2526,12 +2523,12 @@ closeFileHandle fileId files = do
throwChatError :: ChatMonad m => ChatErrorType -> m a
throwChatError = throwError . ChatError
deleteMemberConnection :: ChatMonad m => GroupMember -> m ()
deleteMemberConnection m@GroupMember {activeConn} = do
-- User {userId} <- asks currentUser
withAgent (forM_ (memberConnId m) . deleteConnection) `catchError` const (pure ())
deleteMemberConnection :: ChatMonad m => User -> GroupMember -> m ()
deleteMemberConnection user GroupMember {activeConn} = do
forM_ activeConn $ \conn -> do
deleteAgentConnectionAsync user conn `catchError` \_ -> pure ()
withStore' $ \db -> updateConnectionStatus db conn ConnDeleted
-- withStore $ \db -> deleteGroupMemberConnection db userId m
forM_ activeConn $ \conn -> withStore' $ \db -> updateConnectionStatus db conn ConnDeleted
sendDirectContactMessage :: ChatMonad m => Contact -> ChatMsgEvent -> m SndMessage
sendDirectContactMessage ct@Contact {activeConn = conn@Connection {connId, connStatus}} chatMsgEvent = do
@@ -2647,6 +2644,15 @@ allowAgentConnectionAsync user conn@Connection {connId} confId msg = do
withAgent $ \a -> allowConnectionAsync a (aCorrId cmdId) (aConnId conn) confId $ directMessage msg
withStore' $ \db -> updateConnectionStatus db conn ConnAccepted
deleteAgentConnectionAsync :: ChatMonad m => User -> Connection -> m ()
deleteAgentConnectionAsync user Connection {agentConnId, connId} =
deleteAgentConnectionAsync' user connId agentConnId
deleteAgentConnectionAsync' :: ChatMonad m => User -> Int64 -> AgentConnId -> m ()
deleteAgentConnectionAsync' user connId (AgentConnId acId) = do
cmdId <- withStore' $ \db -> createCommand db user (Just connId) CFDeleteConn
withAgent $ \a -> deleteConnectionAsync a (aCorrId cmdId) acId
getCreateActiveUser :: SQLiteStore -> IO User
getCreateActiveUser st = do
user <-

View File

@@ -957,6 +957,7 @@ data CommandFunction
| CFJoinConn
| CFAllowConn
| CFAckMessage
| CFDeleteConn
deriving (Eq, Show, Generic)
instance FromField CommandFunction where fromField = fromTextField_ textDecode
@@ -969,12 +970,14 @@ instance TextEncoding CommandFunction where
"join_conn" -> Just CFJoinConn
"allow_conn" -> Just CFAllowConn
"ack_message" -> Just CFAckMessage
"delete_conn" -> Just CFDeleteConn
_ -> Nothing
textEncode = \case
CFCreateConn -> "create_conn"
CFJoinConn -> "join_conn"
CFAllowConn -> "allow_conn"
CFAckMessage -> "ack_message"
CFDeleteConn -> "delete_conn"
commandExpectedResponse :: CommandFunction -> ACommandTag 'Agent
commandExpectedResponse = \case
@@ -982,6 +985,7 @@ commandExpectedResponse = \case
CFJoinConn -> OK_
CFAllowConn -> OK_
CFAckMessage -> OK_
CFDeleteConn -> OK_
data CommandData = CommandData
{ cmdId :: CommandId,