|
13 | 13 | {-# LANGUAGE PatternSynonyms #-} |
14 | 14 | {-# LANGUAGE RankNTypes #-} |
15 | 15 | {-# LANGUAGE ScopedTypeVariables #-} |
| 16 | +{-# LANGUAGE TemplateHaskell #-} |
16 | 17 | {-# LANGUAGE TupleSections #-} |
17 | 18 | {-# LANGUAGE TypeApplications #-} |
18 | 19 | {-# OPTIONS_GHC -fno-warn-ambiguous-fields #-} |
@@ -67,6 +68,9 @@ module Simplex.Messaging.Agent |
67 | 68 | allowConnection, |
68 | 69 | acceptContact, |
69 | 70 | rejectContact, |
| 71 | + DatabaseDiff (..), |
| 72 | + compareConnections, |
| 73 | + syncConnections, |
70 | 74 | subscribeConnection, |
71 | 75 | subscribeConnections, |
72 | 76 | subscribeAllConnections, |
@@ -140,7 +144,9 @@ import Control.Monad.Except |
140 | 144 | import Control.Monad.Reader |
141 | 145 | import Control.Monad.Trans.Except |
142 | 146 | import Crypto.Random (ChaChaDRG) |
| 147 | +import Data.Aeson (FromJSON (..), ToJSON (..)) |
143 | 148 | import qualified Data.Aeson as J |
| 149 | +import qualified Data.Aeson.TH as JQ |
144 | 150 | import Data.Bifunctor (bimap, first) |
145 | 151 | import Data.ByteString.Char8 (ByteString) |
146 | 152 | import qualified Data.ByteString.Char8 as B |
@@ -195,7 +201,7 @@ import Simplex.Messaging.Encoding |
195 | 201 | import Simplex.Messaging.Encoding.String |
196 | 202 | import Simplex.Messaging.Notifications.Protocol (DeviceToken, NtfRegCode (NtfRegCode), NtfTknStatus (..), NtfTokenId, PNMessageData (..), pnMessagesP) |
197 | 203 | import Simplex.Messaging.Notifications.Types |
198 | | -import Simplex.Messaging.Parsers (parse) |
| 204 | +import Simplex.Messaging.Parsers (defaultJSON, parse) |
199 | 205 | import Simplex.Messaging.Protocol |
200 | 206 | ( BrokerMsg, |
201 | 207 | Cmd (..), |
@@ -434,6 +440,24 @@ rejectContact :: AgentClient -> ConfirmationId -> AE () |
434 | 440 | rejectContact c = withAgentEnv c . rejectContact' c |
435 | 441 | {-# INLINE rejectContact #-} |
436 | 442 |
|
| 443 | +data DatabaseDiff a = DatabaseDiff |
| 444 | + { missingIds :: [a], |
| 445 | + extraIds :: [a] |
| 446 | + } |
| 447 | + deriving (Show) |
| 448 | + |
| 449 | +instance Functor DatabaseDiff where |
| 450 | + fmap f DatabaseDiff {missingIds, extraIds} = |
| 451 | + DatabaseDiff {missingIds = map f missingIds, extraIds = map f extraIds} |
| 452 | + |
| 453 | +compareConnections :: AgentClient -> [UserId] -> [ConnId] -> AE (DatabaseDiff UserId, DatabaseDiff ConnId) |
| 454 | +compareConnections c = withAgentEnv c .: compareConnections' c |
| 455 | +{-# INLINE compareConnections #-} |
| 456 | + |
| 457 | +syncConnections :: AgentClient -> [UserId] -> [ConnId] -> AE (DatabaseDiff UserId, DatabaseDiff ConnId) |
| 458 | +syncConnections c = withAgentEnv c .: syncConnections' c |
| 459 | +{-# INLINE syncConnections #-} |
| 460 | + |
437 | 461 | -- | Subscribe to receive connection messages (SUB command) |
438 | 462 | subscribeConnection :: AgentClient -> ConnId -> AE (Maybe ClientServiceId) |
439 | 463 | subscribeConnection c = withAgentEnv c . subscribeConnection' c |
@@ -1253,6 +1277,27 @@ rejectContact' c invId = |
1253 | 1277 | withStore' c $ \db -> deleteInvitation db invId |
1254 | 1278 | {-# INLINE rejectContact' #-} |
1255 | 1279 |
|
| 1280 | +syncConnections' :: AgentClient -> [UserId] -> [ConnId] -> AM (DatabaseDiff UserId, DatabaseDiff ConnId) |
| 1281 | +syncConnections' c userIds connIds = do |
| 1282 | + r@(DatabaseDiff {extraIds = uIds}, DatabaseDiff {extraIds = cIds}) <- compareConnections' c userIds connIds |
| 1283 | + forM_ uIds $ \uid -> deleteUser' c uid False |
| 1284 | + deleteConnectionsAsync' c False cIds |
| 1285 | + pure r |
| 1286 | + |
| 1287 | +compareConnections' :: AgentClient -> [UserId] -> [ConnId] -> AM (DatabaseDiff UserId, DatabaseDiff ConnId) |
| 1288 | +compareConnections' c userIds connIds = do |
| 1289 | + knownUserIds <- withStore' c getUserIds |
| 1290 | + knownConnIds <- withStore' c getConnIds |
| 1291 | + pure (databaseDiff userIds knownUserIds, databaseDiff connIds knownConnIds) |
| 1292 | + |
| 1293 | +databaseDiff :: Ord a => [a] -> [a] -> DatabaseDiff a |
| 1294 | +databaseDiff passed known = |
| 1295 | + let passedSet = S.fromList passed |
| 1296 | + knownSet = S.fromList known |
| 1297 | + missingIds = S.toList $ passedSet `S.difference` knownSet |
| 1298 | + extraIds = S.toList $ knownSet `S.difference` passedSet |
| 1299 | + in DatabaseDiff {missingIds, extraIds} |
| 1300 | + |
1256 | 1301 | -- | Subscribe to receive connection messages (SUB command) in Reader monad |
1257 | 1302 | subscribeConnection' :: AgentClient -> ConnId -> AM (Maybe ClientServiceId) |
1258 | 1303 | subscribeConnection' c connId = toConnResult connId =<< subscribeConnections' c [connId] |
@@ -3478,3 +3523,12 @@ newSndQueue userId connId (Compatible (SMPQueueInfo smpClientVersion SMPQueueAdd |
3478 | 3523 | smpClientVersion |
3479 | 3524 | } |
3480 | 3525 | pure (sq, e2ePubKey) |
| 3526 | + |
| 3527 | +$(pure []) |
| 3528 | + |
| 3529 | +instance FromJSON a => FromJSON (DatabaseDiff a) where |
| 3530 | + parseJSON = $(JQ.mkParseJSON defaultJSON ''DatabaseDiff) |
| 3531 | + |
| 3532 | +instance ToJSON a => ToJSON (DatabaseDiff a) where |
| 3533 | + toEncoding = $(JQ.mkToEncoding defaultJSON ''DatabaseDiff) |
| 3534 | + toJSON = $(JQ.mkToJSON defaultJSON ''DatabaseDiff) |
0 commit comments