diff --git a/src/Simplex/Messaging/Agent/Client.hs b/src/Simplex/Messaging/Agent/Client.hs index 0601628a7..227663df4 100644 --- a/src/Simplex/Messaging/Agent/Client.hs +++ b/src/Simplex/Messaging/Agent/Client.hs @@ -781,7 +781,9 @@ smpConnectClient c@AgentClient {smpClients, msgQ, proxySessTs, presetDomains} nm when current $ updateClientService service smp pure SMPConnectedClient {connectedClient = smp, proxiedRelays = prs} updateClientService service smp = case (service, smpClientServiceId smp) of - (Just (_, serviceId_), Just serviceId) -> withStore' c $ \db -> do + (Just _, Just serviceId) -> withStore' c $ \db -> do + -- the id read before the handshake can be stale - this transaction can commit after another client's + serviceId_ <- (>>= snd) <$> getClientServiceCredentials db userId srv setClientServiceId db userId srv serviceId forM_ serviceId_ $ \sId -> when (sId /= serviceId) $ removeRcvServiceAssocs db userId srv (Just _, Nothing) -> withStore' c $ \db -> deleteClientService db userId srv -- e.g., server version downgrade @@ -807,9 +809,11 @@ smpClientDisconnected c@AgentClient {active, smpClients, smpProxiedRelays} tSess (subs, serviceSub_) <- SS.setSubsPending mode tSess sessId $ currentSubs c let qs = M.elems subs cs = nubOrd $ map qConnId qs - -- this removes proxied relays that this client created sessions to - destSrvs <- M.keys <$> readTVar prs - forM_ destSrvs $ \destSrv -> TM.delete (userId, destSrv, cId) smpProxiedRelays + -- this removes proxied relays that this client created sessions to, unless another client + -- replaced this one, e.g. when the network changed - those sessions are now its sessions + unlessM (TM.member tSess smpClients) $ do + destSrvs <- M.keys <$> readTVar prs + forM_ destSrvs $ \destSrv -> TM.delete (userId, destSrv, cId) smpProxiedRelays pure (qs, cs, serviceSub_) serverDown :: ([RcvQueueSub], [ConnId], Maybe ServiceSub) -> IO () diff --git a/src/Simplex/Messaging/Agent/TSessionSubs.hs b/src/Simplex/Messaging/Agent/TSessionSubs.hs index a1db48c9e..42a3dc01a 100644 --- a/src/Simplex/Messaging/Agent/TSessionSubs.hs +++ b/src/Simplex/Messaging/Agent/TSessionSubs.hs @@ -216,7 +216,9 @@ setSubsPending mode tSess@(uId, srv, connId_) sessId tss@(TSessionSubs ss) | entitySession == isJust connId_ = TM.lookup tSess ss >>= withSessSubs (`setSubsPending_` Nothing) | otherwise = - TM.lookupDelete tSess ss >>= withSessSubs setPendingChangeMode + -- the subscriptions are removed only when the session matches - a client that is no longer + -- the one in the map never set its session id, and its disconnection must not remove them + TM.lookup tSess ss >>= withSessSubs (\s -> TM.delete tSess ss >> setPendingChangeMode s) where entitySession = mode == TSMEntity sessEntId = if entitySession then Just else const Nothing