@@ -44,7 +44,6 @@ import Control.Monad.Except
4444import Control.Monad.IO.Unlift
4545import Control.Monad.Reader
4646import Control.Monad.Trans.Except
47- import Crypto.Random
4847import Control.Monad.STM (retry )
4948import Data.Bifunctor (first )
5049import Data.ByteString.Base64 (encode )
@@ -247,7 +246,7 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
247246 old <- liftIO $ expireBeforeEpoch expCfg
248247 rIds <- M. keysSet <$> readTVarIO ms
249248 forM_ rIds $ \ rId -> do
250- q <- atomically ( getMsgQueue ms rId quota)
249+ q <- liftIO $ getMsgQueue ms rId quota
251250 deleted <- atomically $ deleteExpiredMsgs q old
252251 liftIO $ atomicModifyIORef'_ (msgExpired stats) (+ deleted)
253252
@@ -1255,15 +1254,7 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
12551254 Just (msg, wasEmpty) -> time " SEND ok" $ do
12561255 when wasEmpty $ tryDeliverMessage msg
12571256 when (notification msgFlags) $ do
1258- forM_ (notifier qr) $ \ ntf -> do
1259- asks random >>= atomically . trySendNotification ntf msg >>= \ case
1260- Nothing -> do
1261- incStat $ msgNtfNoSub stats
1262- logWarn " No notification subscription"
1263- Just False -> do
1264- incStat $ msgNtfLost stats
1265- logWarn " Dropped message notification"
1266- Just True -> incStat $ msgNtfs stats
1257+ mapM_ (`trySendNotification` msg) (notifier qr)
12671258 incStat $ msgSentNtf stats
12681259 liftIO $ updatePeriodStats (activeQueuesNtf stats) (recipientId qr)
12691260 incStat $ msgSent stats
@@ -1335,23 +1326,35 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
13351326 deliver q s
13361327 writeTVar st NoSub
13371328
1338- trySendNotification :: NtfCreds -> Message -> TVar ChaChaDRG -> STM (Maybe Bool )
1339- trySendNotification NtfCreds {notifierId, rcvNtfDhSecret} msg ntfNonceDrg =
1340- mapM (writeNtf notifierId msg rcvNtfDhSecret ntfNonceDrg) =<< TM. lookup notifierId notifiers
1341-
1342- writeNtf :: NotifierId -> Message -> RcvNtfDhSecret -> TVar ChaChaDRG -> Client -> STM Bool
1343- writeNtf nId msg rcvNtfDhSecret ntfNonceDrg Client {sndQ = q} =
1344- ifM (isFullTBQueue q) (pure False ) (sendNtf $> True )
1345- where
1346- sendNtf = case msg of
1347- Message {msgId, msgTs} -> do
1348- (nmsgNonce, encNMsgMeta) <- mkMessageNotification msgId msgTs rcvNtfDhSecret ntfNonceDrg
1349- writeTBQueue q [(CorrId " " , nId, NMSG nmsgNonce encNMsgMeta)]
1350- _ -> pure ()
1351-
1352- mkMessageNotification :: ByteString -> SystemTime -> RcvNtfDhSecret -> TVar ChaChaDRG -> STM (C. CbNonce , EncNMsgMeta )
1353- mkMessageNotification msgId msgTs rcvNtfDhSecret ntfNonceDrg = do
1354- cbNonce <- C. randomCbNonce ntfNonceDrg
1329+ trySendNotification :: NtfCreds -> Message -> M ()
1330+ trySendNotification NtfCreds {notifierId, rcvNtfDhSecret} msg = do
1331+ stats <- asks serverStats
1332+ liftIO (TM. lookupIO notifierId notifiers) >>= \ case
1333+ Nothing -> do
1334+ incStat $ msgNtfNoSub stats
1335+ logWarn " No notification subscription"
1336+ Just ntfClnt -> do
1337+ let updateStats True = incStat $ msgNtfs stats
1338+ updateStats _ = do
1339+ incStat $ msgNtfLost stats
1340+ logWarn " Dropped message notification"
1341+ writeNtf notifierId msg rcvNtfDhSecret ntfClnt >>= mapM_ updateStats
1342+
1343+ writeNtf :: NotifierId -> Message -> RcvNtfDhSecret -> Client -> M (Maybe Bool )
1344+ writeNtf nId msg rcvNtfDhSecret Client {sndQ = q} = case msg of
1345+ Message {msgId, msgTs} -> Just <$> do
1346+ (nmsgNonce, encNMsgMeta) <- mkMessageNotification msgId msgTs rcvNtfDhSecret
1347+ -- must be in one STM transaction to avoid the queue becoming full between the check and writing
1348+ atomically $
1349+ ifM
1350+ (isFullTBQueue q)
1351+ (pure $ False )
1352+ (True <$ writeTBQueue q [(CorrId " " , nId, NMSG nmsgNonce encNMsgMeta)])
1353+ _ -> pure Nothing
1354+
1355+ mkMessageNotification :: ByteString -> SystemTime -> RcvNtfDhSecret -> M (C. CbNonce , EncNMsgMeta )
1356+ mkMessageNotification msgId msgTs rcvNtfDhSecret = do
1357+ cbNonce <- atomically . C. randomCbNonce =<< asks random
13551358 let msgMeta = NMsgMeta {msgId, msgTs}
13561359 encNMsgMeta = C. cbEncrypt rcvNtfDhSecret cbNonce (smpEncode msgMeta) 128
13571360 pure . (cbNonce,) $ fromRight " " encNMsgMeta
@@ -1441,7 +1444,7 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
14411444 getStoreMsgQueue name rId = time (name <> " getMsgQueue" ) $ do
14421445 ms <- asks msgStore
14431446 quota <- asks $ msgQueueQuota . config
1444- atomically $ getMsgQueue ms rId quota
1447+ liftIO $ getMsgQueue ms rId quota
14451448
14461449 delQueueAndMsgs :: QueueStore -> M (Transmission BrokerMsg )
14471450 delQueueAndMsgs st = do
@@ -1459,24 +1462,23 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
14591462
14601463 getQueueInfo :: QueueRec -> M (Transmission BrokerMsg )
14611464 getQueueInfo QueueRec {senderKey, notifier} = do
1462- q@ MsgQueue {size} <- getStoreMsgQueue " getQueueInfo" entId
1463- info <- atomically $ do
1464- qiSub <- TM. lookup entId subscriptions >>= mapM mkQSub
1465- qiSize <- readTVar size
1466- qiMsg <- toMsgInfo <$$> tryPeekMsg q
1467- pure QueueInfo {qiSnd = isJust senderKey, qiNtf = isJust notifier, qiSub, qiSize, qiMsg}
1465+ q <- getStoreMsgQueue " getQueueInfo" entId
1466+ qiSub <- liftIO $ TM. lookupIO entId subscriptions >>= mapM mkQSub
1467+ qiSize <- liftIO $ getQueueSize q
1468+ qiMsg <- atomically $ toMsgInfo <$$> tryPeekMsg q
1469+ let info = QueueInfo {qiSnd = isJust senderKey, qiNtf = isJust notifier, qiSub, qiSize, qiMsg}
14681470 pure (corrId, entId, INFO info)
14691471 where
14701472 mkQSub Sub {subThread, delivered} = do
14711473 qSubThread <- case subThread of
14721474 ServerSub t -> do
1473- st <- readTVar t
1475+ st <- readTVarIO t
14741476 pure $ case st of
14751477 NoSub -> QNoSub
14761478 SubPending -> QSubPending
14771479 SubThread _ -> QSubThread
14781480 ProhibitSub -> pure QProhibitSub
1479- qDelivered <- decodeLatin1 . encode <$$> tryReadTMVar delivered
1481+ qDelivered <- atomically $ decodeLatin1 . encode <$$> tryReadTMVar delivered
14801482 pure QSub {qSubThread, qDelivered}
14811483
14821484 ok :: Transmission BrokerMsg
@@ -1564,13 +1566,12 @@ restoreServerMessages =
15641566 where
15651567 s = LB. toStrict s'
15661568 addToMsgQueue rId msg = do
1567- (isExpired, logFull) <- atomically $ do
1568- q <- getMsgQueue ms rId quota
1569- case msg of
1570- Message {msgTs}
1571- | maybe True (systemSeconds msgTs >= ) old_ -> (False ,) . isNothing <$> writeMsg q msg
1572- | otherwise -> pure (True , False )
1573- MessageQuota {} -> writeMsg q msg $> (False , False )
1569+ q <- liftIO $ getMsgQueue ms rId quota
1570+ (isExpired, logFull) <- atomically $ case msg of
1571+ Message {msgTs}
1572+ | maybe True (systemSeconds msgTs >= ) old_ -> (False ,) . isNothing <$> writeMsg q msg
1573+ | otherwise -> pure (True , False )
1574+ MessageQuota {} -> writeMsg q msg $> (False , False )
15741575 when logFull . logError . decodeLatin1 $ " message queue " <> strEncode rId <> " is full, message not restored: " <> strEncode (messageId msg)
15751576 pure $ if isExpired then expired + 1 else expired
15761577 msgErr :: Show e => String -> e -> String
@@ -1595,7 +1596,7 @@ restoreServerStats expiredWhileRestoring = asks (serverStatsBackupFile . config)
15951596 Right d@ ServerStatsData {_qCount = statsQCount} -> do
15961597 s <- asks serverStats
15971598 _qCount <- fmap M. size . readTVarIO . queues =<< asks queueStore
1598- _msgCount <- foldM (\ (! n) q -> (n + ) <$> readTVarIO (size q) ) 0 =<< readTVarIO =<< asks msgStore
1599+ _msgCount <- liftIO . foldM (\ (! n) q -> (n + ) <$> getQueueSize q ) 0 =<< readTVarIO =<< asks msgStore
15991600 liftIO $ setServerStats s d {_qCount, _msgCount, _msgExpired = _msgExpired d + expiredWhileRestoring}
16001601 renameFile f $ f <> " .bak"
16011602 logInfo " server stats restored"
0 commit comments