Skip to content

Commit 9710498

Browse files
authored
server: support server roles and operators (#1343)
* server: support server roles and operators * make server operator optional * allRoles * fix test * different server host in tests * remove ServerCfg fields used only in UI * comments * choose different server for invitation when connecting via address * fix test in ghc8107 * simplify
1 parent 45333bd commit 9710498

File tree

11 files changed

+230
-64
lines changed

11 files changed

+230
-64
lines changed

simplexmq.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ test-suite simplexmq-test
384384
AgentTests.MigrationTests
385385
AgentTests.NotificationTests
386386
AgentTests.SchemaDump
387+
AgentTests.ServerChoice
387388
AgentTests.SQLiteTests
388389
CLITests
389390
CoreTests.BatchingTests

src/Simplex/FileTransfer/Agent.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,14 +461,14 @@ runXFTPSndPrepareWorker c Worker {doWork} = do
461461
pure srv
462462
where
463463
tryCreate = do
464-
usedSrvs <- newTVarIO ([] :: [XFTPServer])
464+
triedHosts <- newTVarIO S.empty
465465
let AgentClient {xftpServers} = c
466466
userSrvCount <- liftIO $ length <$> TM.lookupIO userId xftpServers
467467
withRetryIntervalCount (riFast ri) $ \n _ loop -> do
468468
liftIO $ waitWhileSuspended c
469469
liftIO $ waitForUserNetwork c
470470
let triedAllSrvs = n > userSrvCount
471-
createWithNextSrv usedSrvs
471+
createWithNextSrv triedHosts
472472
`catchAgentError` \e -> retryOnError "XFTP prepare worker" (retryLoop loop triedAllSrvs e) (throwE e) e
473473
where
474474
-- we don't do closeXFTPServerClient here to not risk closing connection for concurrent chunk upload
@@ -477,10 +477,10 @@ runXFTPSndPrepareWorker c Worker {doWork} = do
477477
when (triedAllSrvs && serverHostError e) $ notify c sndFileEntityId $ SFWARN e
478478
liftIO $ assertAgentForeground c
479479
loop
480-
createWithNextSrv usedSrvs = do
480+
createWithNextSrv triedHosts = do
481481
deleted <- withStore' c $ \db -> getSndFileDeleted db sndFileId
482482
when deleted $ throwE $ FILE NO_FILE
483-
withNextSrv c userId usedSrvs [] $ \srvAuth -> do
483+
withNextSrv c userId storageSrvs triedHosts [] $ \srvAuth -> do
484484
replica <- agentXFTPNewChunk c ch numRecipients' srvAuth
485485
pure (replica, srvAuth)
486486

src/Simplex/Messaging/Agent.hs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ module Simplex.Messaging.Agent
120120
debugAgentLocks,
121121
getAgentSubscriptions,
122122
logConnection,
123+
-- for tests
124+
withAgentEnv,
123125
)
124126
where
125127

@@ -815,11 +817,13 @@ newConnToAccept c connId enableNtfs invId pqSup = do
815817

816818
joinConn :: AgentClient -> UserId -> ConnId -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> AM SndQueueSecured
817819
joinConn c userId connId enableNtfs cReq cInfo pqSupport subMode = do
818-
srv <- case cReq of
819-
CRInvitationUri ConnReqUriData {crSmpQueues = q :| _} _ ->
820-
getNextServer c userId [qServer q]
821-
_ -> getSMPServer c userId
820+
srv <- getNextSMPServer c userId [qServer cReqQueue]
822821
joinConnSrv c userId connId enableNtfs cReq cInfo pqSupport subMode srv
822+
where
823+
cReqQueue :: SMPQueueUri
824+
cReqQueue = case cReq of
825+
CRInvitationUri ConnReqUriData {crSmpQueues = q :| _} _ -> q
826+
CRContactUri ConnReqUriData {crSmpQueues = q :| _} -> q
823827

824828
startJoinInvitation :: AgentClient -> UserId -> ConnId -> Maybe SndQueue -> Bool -> ConnectionRequestUri 'CMInvitation -> PQSupport -> AM (ConnData, SndQueue, CR.SndE2ERatchetParams 'C.X448)
825829
startJoinInvitation c userId connId sq_ enableNtfs cReqUri pqSup =
@@ -1194,14 +1198,13 @@ runCommandProcessing c@AgentClient {subQ} connId server_ Worker {doWork} = do
11941198
processCmd ri PendingCommand {cmdId, corrId, userId, command} pendingCmds = case command of
11951199
AClientCommand cmd -> case cmd of
11961200
NEW enableNtfs (ACM cMode) pqEnc subMode -> noServer $ do
1197-
usedSrvs <- newTVarIO ([] :: [SMPServer])
1198-
tryCommand . withNextSrv c userId usedSrvs [] $ \srv -> do
1201+
triedHosts <- newTVarIO S.empty
1202+
tryCommand . withNextSrv c userId storageSrvs triedHosts [] $ \srv -> do
11991203
cReq <- newRcvConnSrv c userId connId enableNtfs cMode Nothing pqEnc subMode srv
12001204
notify $ INV (ACR cMode cReq)
12011205
JOIN enableNtfs (ACR _ cReq@(CRInvitationUri ConnReqUriData {crSmpQueues = q :| _} _)) pqEnc subMode connInfo -> noServer $ do
1202-
let initUsed = [qServer q]
1203-
usedSrvs <- newTVarIO initUsed
1204-
tryCommand . withNextSrv c userId usedSrvs initUsed $ \srv -> do
1206+
triedHosts <- newTVarIO S.empty
1207+
tryCommand . withNextSrv c userId storageSrvs triedHosts [qServer q] $ \srv -> do
12051208
sqSecured <- joinConnSrvAsync c userId connId enableNtfs cReq connInfo pqEnc subMode srv
12061209
notify $ JOINED sqSecured
12071210
LET confId ownCInfo -> withServer' . tryCommand $ allowConnection' c connId confId ownCInfo >> notify OK
@@ -1649,8 +1652,8 @@ switchDuplexConnection c (DuplexConnection cData@ConnData {connId, userId} rqs s
16491652
checkRQSwchStatus rq RSSwitchStarted
16501653
clientVRange <- asks $ smpClientVRange . config
16511654
-- try to get the server that is different from all queues, or at least from the primary rcv queue
1652-
srvAuth@(ProtoServerWithAuth srv _) <- getNextServer c userId $ map qServer (L.toList rqs) <> map qServer (L.toList sqs)
1653-
srv' <- if srv == server then getNextServer c userId [server] else pure srvAuth
1655+
srvAuth@(ProtoServerWithAuth srv _) <- getNextSMPServer c userId $ map qServer (L.toList rqs) <> map qServer (L.toList sqs)
1656+
srv' <- if srv == server then getNextSMPServer c userId [server] else pure srvAuth
16541657
(q, qUri, tSess, sessId) <- newRcvQueue c userId connId srv' clientVRange SMSubscribe False
16551658
let rq' = (q :: NewRcvQueue) {primary = True, dbReplaceQueueId = Just dbQueueId}
16561659
rq'' <- withStore c $ \db -> addConnRcvQueue db connId rq'
@@ -2158,9 +2161,13 @@ debugAgentLocks AgentClient {connLocks = cs, invLocks = is, deleteLock = d} = do
21582161
getLocks ls = atomically $ M.mapKeys (B.unpack . strEncode) . M.mapMaybe id <$> (mapM tryReadTMVar =<< readTVar ls)
21592162

21602163
getSMPServer :: AgentClient -> UserId -> AM SMPServerWithAuth
2161-
getSMPServer c userId = withUserServers c userId pickServer
2164+
getSMPServer c userId = getNextSMPServer c userId []
21622165
{-# INLINE getSMPServer #-}
21632166

2167+
getNextSMPServer :: AgentClient -> UserId -> [SMPServer] -> AM SMPServerWithAuth
2168+
getNextSMPServer c userId = getNextServer c userId storageSrvs
2169+
{-# INLINE getNextSMPServer #-}
2170+
21642171
subscriber :: AgentClient -> AM' ()
21652172
subscriber c@AgentClient {msgQ} = forever $ do
21662173
t <- atomically $ readTBQueue msgQ

src/Simplex/Messaging/Agent/Client.hs

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ module Simplex.Messaging.Agent.Client
149149
userServers,
150150
pickServer,
151151
getNextServer,
152-
withUserServers,
153152
withNextSrv,
154153
incSMPServerStat,
155154
incSMPServerStat',
@@ -193,12 +192,12 @@ import qualified Data.ByteString.Char8 as B
193192
import Data.Either (isRight, partitionEithers)
194193
import Data.Functor (($>))
195194
import Data.Int (Int64)
196-
import Data.List (deleteFirstsBy, find, foldl', partition, (\\))
195+
import Data.List (find, foldl', partition)
197196
import Data.List.NonEmpty (NonEmpty (..), (<|))
198197
import qualified Data.List.NonEmpty as L
199198
import Data.Map.Strict (Map)
200199
import qualified Data.Map.Strict as M
201-
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, listToMaybe)
200+
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, listToMaybe, mapMaybe)
202201
import Data.Set (Set)
203202
import qualified Data.Set as S
204203
import Data.Text (Text)
@@ -264,7 +263,6 @@ import Simplex.Messaging.Protocol
264263
VersionSMPC,
265264
XFTPServer,
266265
XFTPServerWithAuth,
267-
sameSrvAddr',
268266
pattern NoEntity,
269267
)
270268
import qualified Simplex.Messaging.Protocol as SMP
@@ -619,7 +617,7 @@ getSMPServerClient c@AgentClient {active, smpClients, workerSeq} tSess = do
619617
getSMPProxyClient :: AgentClient -> Maybe SMPServerWithAuth -> SMPTransportSession -> AM (SMPConnectedClient, Either AgentErrorType ProxiedRelay)
620618
getSMPProxyClient c@AgentClient {active, smpClients, smpProxiedRelays, workerSeq} proxySrv_ destSess@(userId, destSrv, qId) = do
621619
unlessM (readTVarIO active) $ throwE INACTIVE
622-
proxySrv <- maybe (getNextServer c userId [destSrv]) pure proxySrv_
620+
proxySrv <- maybe (getNextServer c userId proxySrvs [destSrv]) pure proxySrv_
623621
ts <- liftIO getCurrentTime
624622
atomically (getClientVar proxySrv ts) >>= \(tSess, auth, v) ->
625623
either (newProxyClient tSess auth ts) (waitForProxyClient tSess auth) v
@@ -1074,7 +1072,7 @@ sendOrProxySMPCommand ::
10741072
(SMPClient -> ProxiedRelay -> ExceptT SMPClientError IO (Either ProxyClientError ())) ->
10751073
(SMPClient -> ExceptT SMPClientError IO ()) ->
10761074
AM (Maybe SMPServer)
1077-
sendOrProxySMPCommand c userId destSrv connId cmdStr senderId sendCmdViaProxy sendCmdDirectly = do
1075+
sendOrProxySMPCommand c userId destSrv@ProtocolServer {host = destHosts} connId cmdStr senderId sendCmdViaProxy sendCmdDirectly = do
10781076
tSess <- mkTransportSession c userId destSrv connId
10791077
ifM shouldUseProxy (sendViaProxy Nothing tSess) (sendDirectly tSess $> Nothing)
10801078
where
@@ -1093,7 +1091,7 @@ sendOrProxySMPCommand c userId destSrv connId cmdStr senderId sendCmdViaProxy se
10931091
SPFAllow -> True
10941092
SPFAllowProtected -> ipAddressProtected cfg destSrv
10951093
SPFProhibit -> False
1096-
unknownServer = liftIO $ maybe True (notElem destSrv . knownSrvs) <$> TM.lookupIO userId (smpServers c)
1094+
unknownServer = liftIO $ maybe True (\srvs -> all (`S.notMember` knownHosts srvs) destHosts) <$> TM.lookupIO userId (smpServers c)
10971095
sendViaProxy :: Maybe SMPServerWithAuth -> SMPTransportSession -> AM (Maybe SMPServer)
10981096
sendViaProxy proxySrv_ destSess@(_, _, connId_) = do
10991097
r <- tryAgentError . withProxySession c proxySrv_ destSess senderId ("PFWD " <> cmdStr) $ \(SMPConnectedClient smp _, proxySess@ProxiedRelay {prBasicAuth}) -> do
@@ -2036,33 +2034,82 @@ userServers c = case protocolTypeI @p of
20362034
SPXFTP -> xftpServers c
20372035
{-# INLINE userServers #-}
20382036

2039-
pickServer :: forall p. NonEmpty (ProtoServerWithAuth p) -> AM (ProtoServerWithAuth p)
2037+
pickServer :: NonEmpty (Maybe OperatorId, ProtoServerWithAuth p) -> AM (ProtoServerWithAuth p)
20402038
pickServer = \case
2041-
srv :| [] -> pure srv
2039+
(_, srv) :| [] -> pure srv
20422040
servers -> do
20432041
gen <- asks randomServer
2044-
atomically $ (servers L.!!) <$> stateTVar gen (randomR (0, L.length servers - 1))
2042+
atomically $ snd . (servers L.!!) <$> stateTVar gen (randomR (0, L.length servers - 1))
20452043

2046-
getNextServer :: forall p. (ProtocolTypeI p, UserProtocol p) => AgentClient -> UserId -> [ProtocolServer p] -> AM (ProtoServerWithAuth p)
2047-
getNextServer c userId usedSrvs = withUserServers c userId $ \srvs ->
2048-
case L.nonEmpty $ deleteFirstsBy sameSrvAddr' (L.toList srvs) (map noAuthSrv usedSrvs) of
2049-
Just srvs' -> pickServer srvs'
2050-
_ -> pickServer srvs
2044+
getNextServer ::
2045+
(ProtocolTypeI p, UserProtocol p) =>
2046+
AgentClient ->
2047+
UserId ->
2048+
(UserServers p -> NonEmpty (Maybe OperatorId, ProtoServerWithAuth p)) ->
2049+
[ProtocolServer p] ->
2050+
AM (ProtoServerWithAuth p)
2051+
getNextServer c userId srvsSel usedSrvs = do
2052+
srvs <- getUserServers_ c userId srvsSel
2053+
snd <$> getNextServer_ srvs (usedOperatorsHosts srvs usedSrvs)
2054+
2055+
usedOperatorsHosts :: NonEmpty (Maybe OperatorId, ProtoServerWithAuth p) -> [ProtocolServer p] -> (Set (Maybe OperatorId), Set TransportHost)
2056+
usedOperatorsHosts srvs usedSrvs = (usedOperators, usedHosts)
2057+
where
2058+
usedHosts = S.unions $ map serverHosts usedSrvs
2059+
usedOperators = S.fromList $ mapMaybe usedOp $ L.toList srvs
2060+
usedOp (op, srv) = if hasUsedHost srv then Just op else Nothing
2061+
hasUsedHost (ProtoServerWithAuth srv _) = any (`S.member` usedHosts) $ serverHosts srv
2062+
2063+
getNextServer_ ::
2064+
(ProtocolTypeI p, UserProtocol p) =>
2065+
NonEmpty (Maybe OperatorId, ProtoServerWithAuth p) ->
2066+
(Set (Maybe OperatorId), Set TransportHost) ->
2067+
AM (NonEmpty (Maybe OperatorId, ProtoServerWithAuth p), ProtoServerWithAuth p)
2068+
getNextServer_ servers (usedOperators, usedHosts) = do
2069+
-- choose from servers of unused operators, when possible
2070+
let otherOpsSrvs = filterOrAll ((`S.notMember` usedOperators) . fst) servers
2071+
-- choose from servers with unused hosts when possible
2072+
unusedSrvs = filterOrAll (isUnusedServer usedHosts) otherOpsSrvs
2073+
(otherOpsSrvs,) <$> pickServer unusedSrvs
2074+
where
2075+
filterOrAll p srvs = fromMaybe srvs $ L.nonEmpty $ L.filter p srvs
2076+
2077+
isUnusedServer :: Set TransportHost -> (Maybe OperatorId, ProtoServerWithAuth p) -> Bool
2078+
isUnusedServer usedHosts (_, ProtoServerWithAuth ProtocolServer {host} _) = all (`S.notMember` usedHosts) host
20512079

2052-
withUserServers :: forall p a. (ProtocolTypeI p, UserProtocol p) => AgentClient -> UserId -> (NonEmpty (ProtoServerWithAuth p) -> AM a) -> AM a
2053-
withUserServers c userId action =
2080+
getUserServers_ ::
2081+
(ProtocolTypeI p, UserProtocol p) =>
2082+
AgentClient ->
2083+
UserId ->
2084+
(UserServers p -> NonEmpty (Maybe OperatorId, ProtoServerWithAuth p)) ->
2085+
AM (NonEmpty (Maybe OperatorId, ProtoServerWithAuth p))
2086+
getUserServers_ c userId srvsSel =
20542087
liftIO (TM.lookupIO userId $ userServers c) >>= \case
2055-
Just srvs -> action $ enabledSrvs srvs
2088+
Just srvs -> pure $ srvsSel srvs
20562089
_ -> throwE $ INTERNAL "unknown userId - no user servers"
20572090

2058-
withNextSrv :: forall p a. (ProtocolTypeI p, UserProtocol p) => AgentClient -> UserId -> TVar [ProtocolServer p] -> [ProtocolServer p] -> (ProtoServerWithAuth p -> AM a) -> AM a
2059-
withNextSrv c userId usedSrvs initUsed action = do
2060-
used <- readTVarIO usedSrvs
2061-
srvAuth@(ProtoServerWithAuth srv _) <- getNextServer c userId used
2062-
srvs_ <- liftIO $ TM.lookupIO userId $ userServers c
2063-
let unused = maybe [] ((\\ used) . map protoServer . L.toList . enabledSrvs) srvs_
2064-
used' = if null unused then initUsed else srv : used
2065-
atomically $ writeTVar usedSrvs $! used'
2091+
-- This function checks used servers and operators every time to allow
2092+
-- changing configuration while retry look is executing.
2093+
-- This function is not thread safe.
2094+
withNextSrv ::
2095+
(ProtocolTypeI p, UserProtocol p) =>
2096+
AgentClient ->
2097+
UserId ->
2098+
(UserServers p -> NonEmpty (Maybe OperatorId, ProtoServerWithAuth p)) ->
2099+
TVar (Set TransportHost) ->
2100+
[ProtocolServer p] ->
2101+
(ProtoServerWithAuth p -> AM a) ->
2102+
AM a
2103+
withNextSrv c userId srvsSel triedHosts usedSrvs action = do
2104+
srvs <- getUserServers_ c userId srvsSel
2105+
let (usedOperators, usedHosts) = usedOperatorsHosts srvs usedSrvs
2106+
tried <- readTVarIO triedHosts
2107+
let triedOrUsed = S.union tried usedHosts
2108+
(otherOpsSrvs, srvAuth@(ProtoServerWithAuth srv _)) <- getNextServer_ srvs (usedOperators, triedOrUsed)
2109+
let newHosts = serverHosts srv
2110+
unusedSrvs = L.filter (isUnusedServer $ S.union triedOrUsed newHosts) otherOpsSrvs
2111+
!tried' = if null unusedSrvs then S.empty else S.union tried newHosts
2112+
atomically $ writeTVar triedHosts tried'
20662113
action srvAuth
20672114

20682115
incSMPServerStat :: AgentClient -> UserId -> SMPServer -> (AgentSMPServerStats -> TVar Int) -> STM ()

src/Simplex/Messaging/Agent/Env/SQLite.hs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ module Simplex.Messaging.Agent.Env.SQLite
1717
AgentConfig (..),
1818
InitialAgentServers (..),
1919
ServerCfg (..),
20+
ServerRoles (..),
21+
OperatorId,
2022
UserServers (..),
2123
NetworkConfig (..),
2224
presetServerCfg,
23-
enabledServerCfg,
25+
allRoles,
2426
mkUserServers,
27+
serverHosts,
2528
defaultAgentConfig,
2629
defaultReconnectInterval,
2730
tryAgentError,
@@ -55,6 +58,8 @@ import Data.List.NonEmpty (NonEmpty)
5558
import qualified Data.List.NonEmpty as L
5659
import Data.Map.Strict (Map)
5760
import Data.Maybe (fromMaybe)
61+
import Data.Set (Set)
62+
import qualified Data.Set as S
5863
import Data.Time.Clock (NominalDiffTime, nominalDay)
5964
import Data.Time.Clock.System (SystemTime (..))
6065
import Data.Word (Word16)
@@ -72,10 +77,11 @@ import Simplex.Messaging.Notifications.Client (defaultNTFClientConfig)
7277
import Simplex.Messaging.Notifications.Transport (NTFVersion)
7378
import Simplex.Messaging.Notifications.Types
7479
import Simplex.Messaging.Parsers (defaultJSON)
75-
import Simplex.Messaging.Protocol (NtfServer, ProtoServerWithAuth, ProtocolServer, ProtocolType (..), ProtocolTypeI, VersionRangeSMPC, XFTPServer, supportedSMPClientVRange)
80+
import Simplex.Messaging.Protocol (NtfServer, ProtoServerWithAuth (..), ProtocolServer (..), ProtocolType (..), ProtocolTypeI, VersionRangeSMPC, XFTPServer, supportedSMPClientVRange)
7681
import Simplex.Messaging.TMap (TMap)
7782
import qualified Simplex.Messaging.TMap as TM
7883
import Simplex.Messaging.Transport (SMPVersion)
84+
import Simplex.Messaging.Transport.Client (TransportHost)
7985
import Simplex.Messaging.Util (allFinally, catchAllErrors, catchAllErrors', tryAllErrors, tryAllErrors')
8086
import System.Mem.Weak (Weak)
8187
import System.Random (StdGen, newStdGen)
@@ -94,29 +100,42 @@ data InitialAgentServers = InitialAgentServers
94100

95101
data ServerCfg p = ServerCfg
96102
{ server :: ProtoServerWithAuth p,
97-
preset :: Bool,
98-
tested :: Maybe Bool,
99-
enabled :: Bool
103+
operator :: Maybe OperatorId,
104+
enabled :: Bool,
105+
roles :: ServerRoles
100106
}
101107
deriving (Show)
102108

103-
enabledServerCfg :: ProtoServerWithAuth p -> ServerCfg p
104-
enabledServerCfg server = ServerCfg {server, preset = False, tested = Nothing, enabled = True}
109+
data ServerRoles = ServerRoles
110+
{ storage :: Bool,
111+
proxy :: Bool
112+
}
113+
deriving (Show)
114+
115+
allRoles :: ServerRoles
116+
allRoles = ServerRoles True True
105117

106-
presetServerCfg :: Bool -> ProtoServerWithAuth p -> ServerCfg p
107-
presetServerCfg enabled server = ServerCfg {server, preset = True, tested = Nothing, enabled}
118+
presetServerCfg :: Bool -> ServerRoles -> Maybe OperatorId -> ProtoServerWithAuth p -> ServerCfg p
119+
presetServerCfg enabled roles operator server =
120+
ServerCfg {server, operator, enabled, roles}
108121

109122
data UserServers p = UserServers
110-
{ enabledSrvs :: NonEmpty (ProtoServerWithAuth p),
111-
knownSrvs :: NonEmpty (ProtocolServer p)
123+
{ storageSrvs :: NonEmpty (Maybe OperatorId, ProtoServerWithAuth p),
124+
proxySrvs :: NonEmpty (Maybe OperatorId, ProtoServerWithAuth p),
125+
knownHosts :: Set TransportHost
112126
}
113127

128+
type OperatorId = Int64
129+
114130
-- This function sets all servers as enabled in case all passed servers are disabled.
115131
mkUserServers :: NonEmpty (ServerCfg p) -> UserServers p
116-
mkUserServers srvs = UserServers {enabledSrvs, knownSrvs}
132+
mkUserServers srvs = UserServers {storageSrvs = filterSrvs storage, proxySrvs = filterSrvs proxy, knownHosts}
117133
where
118-
enabledSrvs = L.map (\ServerCfg {server} -> server) $ fromMaybe srvs $ L.nonEmpty $ L.filter (\ServerCfg {enabled} -> enabled) srvs
119-
knownSrvs = L.map (\ServerCfg {server = ProtoServerWithAuth srv _} -> srv) srvs
134+
filterSrvs role = L.map (\ServerCfg {operator, server} -> (operator, server)) $ fromMaybe srvs $ L.nonEmpty $ L.filter (\ServerCfg {enabled, roles} -> enabled && role roles) srvs
135+
knownHosts = S.unions $ L.map (\ServerCfg {server = ProtoServerWithAuth srv _} -> serverHosts srv) srvs
136+
137+
serverHosts :: ProtocolServer p -> Set TransportHost
138+
serverHosts ProtocolServer {host} = S.fromList $ L.toList host
120139

121140
data AgentConfig = AgentConfig
122141
{ tcpPort :: Maybe ServiceName,
@@ -337,6 +356,8 @@ updateRestartCount t (RestartCount minute count) = do
337356

338357
$(pure [])
339358

359+
$(JQ.deriveJSON defaultJSON ''ServerRoles)
360+
340361
instance ProtocolTypeI p => ToJSON (ServerCfg p) where
341362
toEncoding = $(JQ.mkToEncoding defaultJSON ''ServerCfg)
342363
toJSON = $(JQ.mkToJSON defaultJSON ''ServerCfg)

src/Simplex/Messaging/Server.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,9 +1821,9 @@ importMessages tty ms f old_ = do
18211821
mergeQuotaMsgs >> writeMsg ms rId q False msg $> (stored, expired, M.insert rId q overQuota)
18221822
where
18231823
-- if the first message in queue head is "quota", remove it.
1824-
mergeQuotaMsgs = withPeekMsgQueue ms rId q "mergeQuotaMsgs" $ maybe (pure ()) $ \(mq, msg) ->
1825-
case msg of
1826-
MessageQuota {} -> tryDeleteMsg_ q mq False
1824+
mergeQuotaMsgs =
1825+
withPeekMsgQueue ms rId q "mergeQuotaMsgs" $ maybe (pure ()) $ \case
1826+
(mq, MessageQuota {}) -> tryDeleteMsg_ q mq False
18271827
_ -> pure ()
18281828
msgErr :: Show e => String -> e -> String
18291829
msgErr op e = op <> " error (" <> show e <> "): " <> B.unpack (B.take 100 s)

tests/AgentTests.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import AgentTests.FunctionalAPITests (functionalAPITests)
1616
import AgentTests.MigrationTests (migrationTests)
1717
import AgentTests.NotificationTests (notificationTests)
1818
import AgentTests.SQLiteTests (storeTests)
19+
import AgentTests.ServerChoice (serverChoiceTests)
1920
import Simplex.Messaging.Transport (ATransport (..))
2021
import Test.Hspec
2122

@@ -26,4 +27,5 @@ agentTests (ATransport t) = do
2627
describe "Functional API" $ functionalAPITests (ATransport t)
2728
describe "Notification tests" $ notificationTests (ATransport t)
2829
describe "SQLite store" storeTests
30+
describe "Chosen servers" serverChoiceTests
2931
describe "Migration tests" migrationTests

0 commit comments

Comments
 (0)