mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-10-12 02:22:45 +00:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
099ff67885 | ||
|
|
c311a41b5e | ||
|
|
7565ddd91c | ||
|
|
0de596dbcf | ||
|
|
e59a098e66 | ||
|
|
8d56b0ba85 | ||
|
|
b40d55c358 | ||
|
|
784d36d691 | ||
|
|
44634366be | ||
|
|
f843752404 | ||
|
|
f3865f7d1f | ||
|
|
8ba036b594 | ||
|
|
0dbbf718ea | ||
|
|
70b5c2985c | ||
|
|
50040231c7 | ||
|
|
6cd0eff6fa | ||
|
|
ac8f271a36 | ||
|
|
1208df2344 | ||
|
|
0e58811525 | ||
|
|
e727090020 | ||
|
|
5baffbb370 |
@@ -0,0 +1,26 @@
|
||||
{- Benchmark harness
|
||||
|
||||
Run with: cabal bench -O2 simplexmq-bench
|
||||
|
||||
List cases: cabal bench -O2 simplexmq-bench --benchmark-options "-l"
|
||||
Pick one or group: cabal bench -O2 simplexmq-bench --benchmark-options "-p TRcvQueues.getDelSessQueues"
|
||||
-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Bench.Base64
|
||||
import Bench.BsConcat
|
||||
import Bench.Compression
|
||||
import Bench.SNTRUP761
|
||||
import Bench.TRcvQueues
|
||||
import Test.Tasty.Bench
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
defaultMain
|
||||
[ bgroup "TRcvQueues" benchTRcvQueues,
|
||||
bgroup "SNTRUP761" benchSNTRUP761,
|
||||
bgroup "Compression" benchCompression,
|
||||
bgroup "BsConcat" benchBsConcat,
|
||||
bgroup "Base64" benchBase64
|
||||
]
|
||||
@@ -0,0 +1,71 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE PackageImports #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
module Bench.Base64 where
|
||||
|
||||
import qualified Data.Attoparsec.ByteString.Char8 as A
|
||||
import Data.ByteString (ByteString)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.Char (isAlphaNum)
|
||||
import Test.Tasty.Bench
|
||||
import qualified "base64" Data.Base64.Types as New
|
||||
import qualified "base64" Data.ByteString.Base64 as New
|
||||
import qualified "base64" Data.ByteString.Base64.URL as NewUrl
|
||||
import qualified "base64-bytestring" Data.ByteString.Base64 as Old
|
||||
import qualified "base64-bytestring" Data.ByteString.Base64.URL as OldUrl
|
||||
|
||||
benchBase64 :: [Benchmark]
|
||||
benchBase64 =
|
||||
[ bgroup
|
||||
"encode"
|
||||
[ bench "e-old" $ nf Old.encode decoded,
|
||||
bcompare "e-old" . bench "e-new" $ nf New.encodeBase64' decoded
|
||||
],
|
||||
bgroup
|
||||
"decode"
|
||||
[ bench "d-old" $ nf Old.decode encoded,
|
||||
bcompare "d-old" . bench "d-new" $ nf New.decodeBase64Untyped encoded,
|
||||
bcompare "d-old" . bench "d-typed" $ nf (New.decodeBase64 . New.assertBase64 @New.StdPadded) encoded
|
||||
],
|
||||
bgroup
|
||||
"encode url"
|
||||
[ bench "eu-old" $ nf OldUrl.encode decoded,
|
||||
bcompare "eu-old" . bench "eu-new" $ nf NewUrl.encodeBase64' decoded
|
||||
],
|
||||
bgroup
|
||||
"decode url"
|
||||
[ bench "du-old" $ nf OldUrl.decode encodedUrl,
|
||||
bcompare "du-old" . bench "du-new" $ nf NewUrl.decodeBase64Untyped encodedUrl,
|
||||
bcompare "du-old" . bench "du-typed" $ nf (NewUrl.decodeBase64 . New.assertBase64 @New.UrlPadded) encodedUrl
|
||||
],
|
||||
bgroup
|
||||
"parsing"
|
||||
[ bench "predicates" $ nf parsePredicates encoded,
|
||||
bcompare "predicates" . bench "alphabet" $ nf parseAlphabet encoded
|
||||
]
|
||||
]
|
||||
|
||||
parsePredicates :: ByteString -> Either String ByteString
|
||||
parsePredicates = A.parseOnly $ do
|
||||
str <- A.takeWhile1 (\c -> isAlphaNum c || c == '+' || c == '/')
|
||||
pad <- A.takeWhile (== '=')
|
||||
either fail pure $ Old.decode (str <> pad)
|
||||
|
||||
parseAlphabet :: ByteString -> Either String ByteString
|
||||
parseAlphabet = A.parseOnly $ do
|
||||
str <- A.takeWhile1 (`B.elem` base64Alphabet)
|
||||
pad <- A.takeWhile (== '=')
|
||||
either fail pure $ Old.decode (str <> pad)
|
||||
where
|
||||
base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
encoded :: ByteString
|
||||
encoded = "e8JK+8V3fq6kOLqco/SaKlpNaQ7i1gfOrXoqekEl42u4mF8Bgu14T5j0189CGcUhJHw2RwCMvON+qbvQ9ecJAA=="
|
||||
|
||||
encodedUrl :: ByteString
|
||||
encodedUrl = "e8JK-8V3fq6kOLqco_SaKlpNaQ7i1gfOrXoqekEl42u4mF8Bgu14T5j0189CGcUhJHw2RwCMvON-qbvQ9ecJAA=="
|
||||
|
||||
decoded :: ByteString
|
||||
decoded = "{\194J\251\197w~\174\164\&8\186\156\163\244\154*ZMi\SO\226\214\a\206\173z*zA%\227k\184\152_\SOH\130\237xO\152\244\215\207B\EM\197!$|6G\NUL\140\188\227~\169\187\208\245\231\t\NUL"
|
||||
@@ -0,0 +1,23 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Bench.BsConcat where
|
||||
|
||||
import Data.ByteString (ByteString)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Test.Tasty.Bench
|
||||
|
||||
benchBsConcat :: [Benchmark]
|
||||
benchBsConcat =
|
||||
[ bgroup "3 elements"
|
||||
[ bench "(3-tuple baseline)" $ nf (\(a, s, b) -> a `seq` s `seq` b `seq` "" :: ByteString) ("aaa" :: ByteString, " " :: ByteString, "bbb" :: ByteString),
|
||||
bench "a <> s <> b" $ nf (\(a, s, b) -> a <> s <> b :: ByteString) ("aaa", " ", "bbb"),
|
||||
bench "concat [a, s, b]" $ nf (\(a, s, b) -> B.concat [a, s, b] :: ByteString) ("aaa", " ", "bbb"),
|
||||
bench "unwords [a, b]" $ nf (\(a, b) -> B.unwords [a, b] :: ByteString) ("aaa", "bbb")
|
||||
],
|
||||
bgroup "5 elements"
|
||||
[ bench "a <> s <> b <> s <> c" $ nf (\(a, s1, b, s2, c) -> a <> s1 <> b <> s2 <> c :: ByteString) ("aaa", " ", "bbb", " ", "ccc"),
|
||||
bench "(a <> s <> b) <> (s <> c)" $ nf (\(a, s1, b, s2, c) -> (a <> s1 <> b) <> (s2 <> c) :: ByteString) ("aaa", " ", "bbb", " ", "ccc"),
|
||||
bench "concat [a, s, b, s c]" $ nf (\(a, s1, b, s2, c) -> B.concat [a, s1, b, s2, c] :: ByteString) ("aaa", " ", "bbb", " ", "ccc"),
|
||||
bench "unwords [a, b, c]" $ nf (\(a, b, c) -> B.unwords [a, b, c] :: ByteString) ("aaa", "bbb", "ccc")
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Bench.Compression where
|
||||
|
||||
import qualified Codec.Compression.Zstd as Z
|
||||
import Data.Aeson
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import qualified Data.ByteString.Lazy as LB
|
||||
import Simplex.Messaging.Compression
|
||||
import Test.Tasty.Bench
|
||||
|
||||
benchCompression :: [Benchmark]
|
||||
benchCompression =
|
||||
[ bgroup
|
||||
"stateless"
|
||||
[ bench "1" $ nf (Z.compress 1) testJson,
|
||||
bench "3" $ nf (Z.compress 3) testJson,
|
||||
bench "5" $ nf (Z.compress 5) testJson,
|
||||
bench "9" $ nf (Z.compress 9) testJson,
|
||||
bench "15" $ nf (Z.compress 19) testJson
|
||||
]
|
||||
]
|
||||
|
||||
shortJson :: B.ByteString
|
||||
shortJson = B.take maxLengthPassthrough testJson
|
||||
|
||||
testJson :: B.ByteString
|
||||
testJson = LB.toStrict . encode $ object ["some stuff" .= [obj, obj, obj, obj]]
|
||||
where
|
||||
obj = object ["test" .= [True, False, True], "arr" .= [0 :: Int .. 50], "loooooooooong key" .= String "is loooooooooooooooooooooooong-ish"]
|
||||
@@ -0,0 +1,15 @@
|
||||
module Bench.SNTRUP761 where
|
||||
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Crypto.SNTRUP761.Bindings
|
||||
import Test.Tasty.Bench
|
||||
|
||||
import Test.Tasty (withResource)
|
||||
|
||||
benchSNTRUP761 :: [Benchmark]
|
||||
benchSNTRUP761 =
|
||||
[ bgroup
|
||||
"sntrup761Keypair"
|
||||
[ withResource C.newRandom (\_ -> pure ()) $ bench "current" . whnfAppIO (>>= sntrup761Keypair)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,138 @@
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
module Bench.TRcvQueues where
|
||||
|
||||
import Control.Monad (replicateM, unless)
|
||||
import Crypto.Random
|
||||
import Data.Bifunctor (bimap)
|
||||
import Data.ByteString (ByteString)
|
||||
import Data.Hashable (hash)
|
||||
import Simplex.Messaging.Agent.Protocol (ConnId, QueueStatus (..), UserId)
|
||||
import Simplex.Messaging.Agent.Store (DBQueueId (..), RcvQueue, StoredRcvQueue (..))
|
||||
import qualified Simplex.Messaging.Agent.TRcvQueues as Current
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Protocol (ProtocolServer (..), SMPServer, SProtocolType (..), currentSMPClientVersion)
|
||||
import Simplex.Messaging.Transport.Client (TransportHost (..))
|
||||
import Test.Tasty.Bench
|
||||
import qualified Data.Map.Strict as M
|
||||
import UnliftIO
|
||||
|
||||
-- For quick equivalence tests
|
||||
-- import GHC.IO (unsafePerformIO)
|
||||
-- import Test.Hspec
|
||||
-- import Test.Tasty.Hspec (testSpec)
|
||||
|
||||
|
||||
benchTRcvQueues :: [Benchmark]
|
||||
benchTRcvQueues =
|
||||
[ bgroup
|
||||
"addQueue"
|
||||
[ bench "aq-current" $ nfIO prepareCurrent,
|
||||
bcompare "aq-current" . bench "aq-batch" $ nfIO prepareCurrentBatch
|
||||
],
|
||||
bgroup "getDelSessQueues" benchGDS,
|
||||
bgroup "resubscribe" benchResubscribe
|
||||
]
|
||||
|
||||
benchGDS :: [Benchmark]
|
||||
benchGDS =
|
||||
[ env prepareCurrent $ bench "gds-current" . nfAppIO (fmap (bimap length length) . benchGDSCurrent)
|
||||
-- unsafePerformIO $ testSpec "gds-equiv" testGDSequivalent
|
||||
]
|
||||
where
|
||||
benchGDSCurrent (tSess, qs) = atomically $ Current.getDelSessQueues tSess qs
|
||||
|
||||
-- testGDSequivalent = it "same" $ do
|
||||
-- m@(mKey, _) <- prepareMaster
|
||||
-- c@(cKey, _) <- prepareCurrent
|
||||
-- mKey `shouldBe` cKey
|
||||
-- qsMaster <- benchGDSMaster m
|
||||
-- (qsCurrent, _connIds) <- benchGDSCurrent c
|
||||
-- length qsMaster `shouldNotBe` 0
|
||||
-- length qsMaster `shouldBe` length qsCurrent
|
||||
-- qsMaster `shouldBe` qsCurrent
|
||||
|
||||
benchResubscribe :: [Benchmark]
|
||||
benchResubscribe =
|
||||
[ env (prepareCurrent >>= pickActiveCurrent 1.0) $ bench "resub-current-full" . nfAppIO benchResubCurrent,
|
||||
env (prepareCurrent >>= pickActiveCurrent 0.5) $ bench "resub-current-half" . nfAppIO benchResubCurrent,
|
||||
env (prepareCurrent >>= pickActiveCurrent 0.0) $ bench "resub-current-none" . nfAppIO benchResubCurrent
|
||||
]
|
||||
where
|
||||
pickActiveCurrent rOk (_tsess, activeSubs) = do
|
||||
ok <- readTVarIO $ Current.getConnections activeSubs
|
||||
let num = fromIntegral (M.size ok) * rOk :: Float
|
||||
let ok' = take (round num) $ M.keys ok
|
||||
pure (ok', activeSubs)
|
||||
benchResubCurrent (okConns, activeSubs) = do
|
||||
cs <- readTVarIO $ Current.getConnections activeSubs
|
||||
let conns = filter (`M.notMember` cs) okConns
|
||||
unless (null conns) $ pure ()
|
||||
|
||||
type TSessKey = (UserId, SMPServer, Maybe ConnId)
|
||||
|
||||
prepareCurrent :: IO (TSessKey, Current.TRcvQueues)
|
||||
prepareCurrent = prepareWith Current.empty Current.addQueue
|
||||
|
||||
prepareCurrentBatch :: IO (TSessKey, Current.TRcvQueues)
|
||||
prepareCurrentBatch = prepareQueues Current.empty Current.batchAddQueues
|
||||
|
||||
prepareWith :: STM qs -> (RcvQueue -> qs -> STM ()) -> IO (TSessKey, qs)
|
||||
prepareWith initQS addQueue = prepareQueues initQS (\trqs qs -> mapM_ (`addQueue` trqs) qs)
|
||||
|
||||
prepareQueues :: STM qs -> (qs -> [RcvQueue] -> STM ()) -> IO (TSessKey, qs)
|
||||
prepareQueues initQS addQueues = do
|
||||
let (servers, gen1) = genServers gen0 nServers
|
||||
let (qs, _gen2) = genQueues gen1 servers nUsers nQueues
|
||||
atomically $ do
|
||||
trqs <- initQS
|
||||
addQueues trqs qs
|
||||
pure (fmap (const Nothing) . Current.qKey $ head qs, trqs)
|
||||
where
|
||||
nUsers = 4
|
||||
nServers = 10
|
||||
nQueues = 10000
|
||||
|
||||
genServers :: ChaChaDRG -> Int -> ([SMPServer], ChaChaDRG)
|
||||
genServers random nServers =
|
||||
withDRG random . replicateM nServers $ do
|
||||
host <- THOnionHost <$> getRandomBytes 32
|
||||
keyHash <- C.KeyHash <$> getRandomBytes 64
|
||||
pure ProtocolServer {scheme = SPSMP, host = pure host, port = "12345", keyHash}
|
||||
|
||||
genQueues :: ChaChaDRG -> [SMPServer] -> Int -> Int -> ([RcvQueue], ChaChaDRG)
|
||||
genQueues random servers nUsers nQueues =
|
||||
withDRG random . replicateM nQueues $ do
|
||||
userRandom <- hash @ByteString <$> getRandomBytes 8
|
||||
let userId = fromIntegral $ userRandom `mod` nUsers
|
||||
connId <- getRandomBytes 10
|
||||
serverRandom <- hash @ByteString <$> getRandomBytes 8
|
||||
let server = servers !! (serverRandom `mod` nServers)
|
||||
pure
|
||||
RcvQueue
|
||||
{ userId,
|
||||
connId,
|
||||
server,
|
||||
rcvId = "",
|
||||
rcvPrivateKey = C.APrivateAuthKey C.SEd25519 "MC4CAQAwBQYDK2VwBCIEIDfEfevydXXfKajz3sRkcQ7RPvfWUPoq6pu1TYHV1DEe",
|
||||
rcvDhSecret = "01234567890123456789012345678901",
|
||||
e2ePrivKey = "MC4CAQAwBQYDK2VuBCIEINCzbVFaCiYHoYncxNY8tSIfn0pXcIAhLBfFc0m+gOpk",
|
||||
e2eDhSecret = Nothing,
|
||||
sndId = "",
|
||||
sndSecure = False,
|
||||
status = New,
|
||||
dbQueueId = DBQueueId 0,
|
||||
primary = True,
|
||||
dbReplaceQueueId = Nothing,
|
||||
rcvSwchStatus = Nothing,
|
||||
smpClientVersion = currentSMPClientVersion,
|
||||
clientNtfCreds = Nothing,
|
||||
deleteErrors = 0
|
||||
}
|
||||
where
|
||||
nServers = length servers
|
||||
|
||||
gen0 :: ChaChaDRG
|
||||
gen0 = drgNewSeed (seedFromInteger 100500)
|
||||
@@ -28,3 +28,8 @@ source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/sqlcipher-simple.git
|
||||
tag: a46bd361a19376c5211f1058908fc0ae6bf42446
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/emilypi/base64.git
|
||||
tag: e67505b35084040c91c833bae6a9e6592863fd04
|
||||
|
||||
+27
-2
@@ -1,5 +1,5 @@
|
||||
name: simplexmq
|
||||
version: 6.0.0.1
|
||||
version: 6.0.0.3
|
||||
synopsis: SimpleXMQ message broker
|
||||
description: |
|
||||
This package includes <./docs/Simplex-Messaging-Server.html server>,
|
||||
@@ -44,6 +44,7 @@ dependencies:
|
||||
- crypton-x509-validation == 1.6.*
|
||||
- cryptostore == 0.3.*
|
||||
- data-default == 0.7.*
|
||||
- deepseq == 1.4.*
|
||||
- direct-sqlcipher == 2.3.*
|
||||
- directory == 1.3.*
|
||||
- filepath == 1.4.*
|
||||
@@ -162,7 +163,6 @@ tests:
|
||||
main: Test.hs
|
||||
dependencies:
|
||||
- simplexmq
|
||||
- deepseq == 1.4.*
|
||||
- generic-random == 1.5.*
|
||||
- hspec == 2.11.*
|
||||
- hspec-core == 2.11.*
|
||||
@@ -177,6 +177,31 @@ tests:
|
||||
- -with-rtsopts=-A64M
|
||||
- -with-rtsopts=-N1
|
||||
|
||||
benchmarks:
|
||||
simplexmq-bench:
|
||||
source-dirs: benchmarks
|
||||
main: Bench.hs
|
||||
dependencies:
|
||||
- base64 >= 1.0
|
||||
- base64-bytestring
|
||||
- containers
|
||||
- hashable == 1.4.*
|
||||
- hspec
|
||||
- simplexmq
|
||||
- tasty
|
||||
- tasty-bench
|
||||
- tasty-hspec
|
||||
- unliftio
|
||||
- unordered-containers
|
||||
- zstd
|
||||
ghc-options:
|
||||
- -fproc-alignment=64
|
||||
- -rtsopts
|
||||
- -threaded
|
||||
- -with-rtsopts=-A64m
|
||||
- -with-rtsopts=-N1
|
||||
- -with-rtsopts=-T
|
||||
|
||||
ghc-options:
|
||||
# - -haddock
|
||||
- -Weverything
|
||||
|
||||
+95
-1
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplexmq
|
||||
version: 6.0.0.1
|
||||
version: 6.0.0.3
|
||||
synopsis: SimpleXMQ message broker
|
||||
description: This package includes <./docs/Simplex-Messaging-Server.html server>,
|
||||
<./docs/Simplex-Messaging-Client.html client> and
|
||||
@@ -233,6 +233,7 @@ library
|
||||
, crypton-x509-validation ==1.6.*
|
||||
, cryptostore ==0.3.*
|
||||
, data-default ==0.7.*
|
||||
, deepseq ==1.4.*
|
||||
, direct-sqlcipher ==2.3.*
|
||||
, directory ==1.3.*
|
||||
, filepath ==1.4.*
|
||||
@@ -307,6 +308,7 @@ executable ntf-server
|
||||
, crypton-x509-validation ==1.6.*
|
||||
, cryptostore ==0.3.*
|
||||
, data-default ==0.7.*
|
||||
, deepseq ==1.4.*
|
||||
, direct-sqlcipher ==2.3.*
|
||||
, directory ==1.3.*
|
||||
, filepath ==1.4.*
|
||||
@@ -385,6 +387,7 @@ executable smp-server
|
||||
, crypton-x509-validation ==1.6.*
|
||||
, cryptostore ==0.3.*
|
||||
, data-default ==0.7.*
|
||||
, deepseq ==1.4.*
|
||||
, direct-sqlcipher ==2.3.*
|
||||
, directory ==1.3.*
|
||||
, file-embed
|
||||
@@ -464,6 +467,7 @@ executable xftp
|
||||
, crypton-x509-validation ==1.6.*
|
||||
, cryptostore ==0.3.*
|
||||
, data-default ==0.7.*
|
||||
, deepseq ==1.4.*
|
||||
, direct-sqlcipher ==2.3.*
|
||||
, directory ==1.3.*
|
||||
, filepath ==1.4.*
|
||||
@@ -539,6 +543,7 @@ executable xftp-server
|
||||
, crypton-x509-validation ==1.6.*
|
||||
, cryptostore ==0.3.*
|
||||
, data-default ==0.7.*
|
||||
, deepseq ==1.4.*
|
||||
, direct-sqlcipher ==2.3.*
|
||||
, directory ==1.3.*
|
||||
, filepath ==1.4.*
|
||||
@@ -701,3 +706,92 @@ test-suite simplexmq-test
|
||||
bytestring ==0.10.*
|
||||
, template-haskell ==2.16.*
|
||||
, text >=1.2.3.0 && <1.3
|
||||
|
||||
benchmark simplexmq-bench
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Bench.hs
|
||||
other-modules:
|
||||
Bench.Base64
|
||||
Bench.BsConcat
|
||||
Bench.Compression
|
||||
Bench.SNTRUP761
|
||||
Bench.TRcvQueues
|
||||
Paths_simplexmq
|
||||
hs-source-dirs:
|
||||
benchmarks
|
||||
default-extensions:
|
||||
StrictData
|
||||
ghc-options: -Wall -Wcompat -Werror=incomplete-patterns -Wredundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns -Wunused-type-patterns -O2 -fproc-alignment=64 -rtsopts -threaded -with-rtsopts=-A64m -with-rtsopts=-N1 -with-rtsopts=-T
|
||||
build-depends:
|
||||
aeson ==2.2.*
|
||||
, ansi-terminal >=0.10 && <0.12
|
||||
, asn1-encoding ==0.9.*
|
||||
, asn1-types ==0.3.*
|
||||
, async ==2.2.*
|
||||
, attoparsec ==0.14.*
|
||||
, base >=4.14 && <5
|
||||
, base64 >=1.0
|
||||
, base64-bytestring
|
||||
, case-insensitive ==1.2.*
|
||||
, composition ==1.0.*
|
||||
, constraints >=0.12 && <0.14
|
||||
, containers
|
||||
, crypton ==0.34.*
|
||||
, crypton-x509 ==1.7.*
|
||||
, crypton-x509-store ==1.6.*
|
||||
, crypton-x509-validation ==1.6.*
|
||||
, cryptostore ==0.3.*
|
||||
, data-default ==0.7.*
|
||||
, deepseq ==1.4.*
|
||||
, direct-sqlcipher ==2.3.*
|
||||
, directory ==1.3.*
|
||||
, filepath ==1.4.*
|
||||
, hashable ==1.4.*
|
||||
, hourglass ==0.2.*
|
||||
, hspec
|
||||
, http-types ==0.12.*
|
||||
, http2 >=4.2.2 && <4.3
|
||||
, ini ==0.4.1
|
||||
, iproute ==1.7.*
|
||||
, iso8601-time ==0.1.*
|
||||
, memory ==0.18.*
|
||||
, mtl >=2.3.1 && <3.0
|
||||
, network >=3.1.2.7 && <3.2
|
||||
, network-info ==0.2.*
|
||||
, network-transport ==0.5.6
|
||||
, network-udp ==0.0.*
|
||||
, optparse-applicative >=0.15 && <0.17
|
||||
, process ==1.6.*
|
||||
, random >=1.1 && <1.3
|
||||
, simple-logger ==0.1.*
|
||||
, simplexmq
|
||||
, socks ==0.6.*
|
||||
, sqlcipher-simple ==0.4.*
|
||||
, stm ==2.5.*
|
||||
, tasty
|
||||
, tasty-bench
|
||||
, tasty-hspec
|
||||
, temporary ==1.3.*
|
||||
, time ==1.12.*
|
||||
, time-manager ==0.0.*
|
||||
, tls >=1.7.0 && <1.8
|
||||
, transformers ==0.6.*
|
||||
, unliftio
|
||||
, unliftio-core ==0.2.*
|
||||
, unordered-containers
|
||||
, websockets ==0.12.*
|
||||
, yaml ==0.11.*
|
||||
, zstd
|
||||
default-language: Haskell2010
|
||||
if flag(swift)
|
||||
cpp-options: -DswiftJSON
|
||||
if impl(ghc >= 9.6.2)
|
||||
build-depends:
|
||||
bytestring ==0.11.*
|
||||
, template-haskell ==2.20.*
|
||||
, text >=2.0.1 && <2.2
|
||||
if impl(ghc < 9.6.2)
|
||||
build-depends:
|
||||
bytestring ==0.10.*
|
||||
, template-haskell ==2.16.*
|
||||
, text >=1.2.3.0 && <1.3
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
module Simplex.FileTransfer.Agent
|
||||
( startXFTPWorkers,
|
||||
startXFTPSndWorkers,
|
||||
closeXFTPAgent,
|
||||
toFSFilePath,
|
||||
-- Receiving files
|
||||
@@ -82,13 +83,21 @@ import UnliftIO.Directory
|
||||
import qualified UnliftIO.Exception as E
|
||||
|
||||
startXFTPWorkers :: AgentClient -> Maybe FilePath -> AM ()
|
||||
startXFTPWorkers c workDir = do
|
||||
startXFTPWorkers = startXFTPWorkers_ True
|
||||
{-# INLINE startXFTPWorkers #-}
|
||||
|
||||
startXFTPSndWorkers :: AgentClient -> Maybe FilePath -> AM ()
|
||||
startXFTPSndWorkers = startXFTPWorkers_ False
|
||||
{-# INLINE startXFTPSndWorkers #-}
|
||||
|
||||
startXFTPWorkers_ :: Bool -> AgentClient -> Maybe FilePath -> AM ()
|
||||
startXFTPWorkers_ allWorkers c workDir = do
|
||||
wd <- asks $ xftpWorkDir . xftpAgent
|
||||
atomically $ writeTVar wd workDir
|
||||
cfg <- asks config
|
||||
startRcvFiles cfg
|
||||
when allWorkers $ startRcvFiles cfg
|
||||
startSndFiles cfg
|
||||
startDelFiles cfg
|
||||
when allWorkers $ startDelFiles cfg
|
||||
where
|
||||
startRcvFiles :: AgentConfig -> AM ()
|
||||
startRcvFiles AgentConfig {rcvFilesTTL} = do
|
||||
|
||||
@@ -92,6 +92,7 @@ module Simplex.Messaging.Agent
|
||||
getNtfTokenData,
|
||||
toggleConnectionNtfs,
|
||||
xftpStartWorkers,
|
||||
xftpStartSndWorkers,
|
||||
xftpReceiveFile,
|
||||
xftpDeleteRcvFile,
|
||||
xftpDeleteRcvFiles,
|
||||
@@ -146,7 +147,7 @@ import Data.Time.Clock
|
||||
import Data.Time.Clock.System (systemToUTCTime)
|
||||
import Data.Traversable (mapAccumL)
|
||||
import Data.Word (Word16)
|
||||
import Simplex.FileTransfer.Agent (closeXFTPAgent, deleteSndFileInternal, deleteSndFileRemote, deleteSndFilesInternal, deleteSndFilesRemote, startXFTPWorkers, toFSFilePath, xftpDeleteRcvFile', xftpDeleteRcvFiles', xftpReceiveFile', xftpSendDescription', xftpSendFile')
|
||||
import Simplex.FileTransfer.Agent (closeXFTPAgent, deleteSndFileInternal, deleteSndFileRemote, deleteSndFilesInternal, deleteSndFilesRemote, startXFTPSndWorkers, startXFTPWorkers, toFSFilePath, xftpDeleteRcvFile', xftpDeleteRcvFiles', xftpReceiveFile', xftpSendDescription', xftpSendFile')
|
||||
import Simplex.FileTransfer.Description (ValidFileDescription)
|
||||
import Simplex.FileTransfer.Protocol (FileParty (..))
|
||||
import Simplex.FileTransfer.Types (RcvFileId, SndFileId)
|
||||
@@ -338,7 +339,7 @@ prepareConnectionToJoin :: AgentClient -> UserId -> Bool -> ConnectionRequestUri
|
||||
prepareConnectionToJoin c userId enableNtfs = withAgentEnv c .: newConnToJoin c userId "" enableNtfs
|
||||
|
||||
-- | Join SMP agent connection (JOIN command).
|
||||
joinConnection :: AgentClient -> UserId -> Maybe ConnId -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> AE ConnId
|
||||
joinConnection :: AgentClient -> UserId -> Maybe ConnId -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> AE (ConnId, SndQueueSecured)
|
||||
joinConnection c userId Nothing enableNtfs = withAgentEnv c .:: joinConn c userId "" False enableNtfs
|
||||
joinConnection c userId (Just connId) enableNtfs = withAgentEnv c .:: joinConn c userId connId True enableNtfs
|
||||
{-# INLINE joinConnection #-}
|
||||
@@ -349,7 +350,7 @@ allowConnection c = withAgentEnv c .:. allowConnection' c
|
||||
{-# INLINE allowConnection #-}
|
||||
|
||||
-- | Accept contact after REQ notification (ACPT command)
|
||||
acceptContact :: AgentClient -> Bool -> ConfirmationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AE ConnId
|
||||
acceptContact :: AgentClient -> Bool -> ConfirmationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AE (ConnId, SndQueueSecured)
|
||||
acceptContact c enableNtfs = withAgentEnv c .:: acceptContact' c "" enableNtfs
|
||||
{-# INLINE acceptContact #-}
|
||||
|
||||
@@ -522,6 +523,10 @@ xftpStartWorkers :: AgentClient -> Maybe FilePath -> AE ()
|
||||
xftpStartWorkers c = withAgentEnv c . startXFTPWorkers c
|
||||
{-# INLINE xftpStartWorkers #-}
|
||||
|
||||
xftpStartSndWorkers :: AgentClient -> Maybe FilePath -> AE ()
|
||||
xftpStartSndWorkers c = withAgentEnv c . startXFTPSndWorkers c
|
||||
{-# INLINE xftpStartSndWorkers #-}
|
||||
|
||||
-- | Receive XFTP file
|
||||
xftpReceiveFile :: AgentClient -> UserId -> ValidFileDescription 'FRecipient -> Maybe CryptoFileArgs -> Bool -> AE RcvFileId
|
||||
xftpReceiveFile c = withAgentEnv c .:: xftpReceiveFile' c
|
||||
@@ -778,7 +783,7 @@ newConnToJoin c userId connId enableNtfs cReq pqSup = case cReq of
|
||||
cData = ConnData {userId, connId, connAgentVersion, enableNtfs, lastExternalSndId = 0, deleted = False, ratchetSyncState = RSOk, pqSupport}
|
||||
withStore c $ \db -> createNewConn db g cData SCMInvitation
|
||||
|
||||
joinConn :: AgentClient -> UserId -> ConnId -> Bool -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> AM ConnId
|
||||
joinConn :: AgentClient -> UserId -> ConnId -> Bool -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> AM (ConnId, SndQueueSecured)
|
||||
joinConn c userId connId hasNewConn enableNtfs cReq cInfo pqSupport subMode = do
|
||||
srv <- case cReq of
|
||||
CRInvitationUri ConnReqUriData {crSmpQueues = q :| _} _ ->
|
||||
@@ -837,7 +842,7 @@ versionPQSupport_ :: VersionSMPA -> Maybe CR.VersionE2E -> PQSupport
|
||||
versionPQSupport_ agentV e2eV_ = PQSupport $ agentV >= pqdrSMPAgentVersion && maybe True (>= CR.pqRatchetE2EEncryptVersion) e2eV_
|
||||
{-# INLINE versionPQSupport_ #-}
|
||||
|
||||
joinConnSrv :: AgentClient -> UserId -> ConnId -> Bool -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> SMPServerWithAuth -> AM ConnId
|
||||
joinConnSrv :: AgentClient -> UserId -> ConnId -> Bool -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> SMPServerWithAuth -> AM (ConnId, SndQueueSecured)
|
||||
joinConnSrv c userId connId hasNewConn enableNtfs inv@CRInvitationUri {} cInfo pqSup subMode srv =
|
||||
withInvLock c (strEncode inv) "joinConnSrv" $ do
|
||||
(cData, q, _, rc, e2eSndParams) <- startJoinInvitation userId connId Nothing enableNtfs inv pqSup
|
||||
@@ -854,7 +859,7 @@ joinConnSrv c userId connId hasNewConn enableNtfs inv@CRInvitationUri {} cInfo p
|
||||
-- otherwise we would need to manage retries here to avoid SndQueue recreated with a different key,
|
||||
-- similar to how joinConnAsync does that.
|
||||
tryError (secureConfirmQueue c cData' sq srv cInfo (Just e2eSndParams) subMode) >>= \case
|
||||
Right _ -> pure connId'
|
||||
Right sqSecured -> pure (connId', sqSecured)
|
||||
Left e -> do
|
||||
-- possible improvement: recovery for failure on network timeout, see rfcs/2022-04-20-smp-conf-timeout-recovery.md
|
||||
void $ withStore' c $ \db -> deleteConn db Nothing connId'
|
||||
@@ -864,10 +869,10 @@ joinConnSrv c userId connId hasNewConn enableNtfs cReqUri@CRContactUri {} cInfo
|
||||
Just (qInfo, vrsn) -> do
|
||||
(connId', cReq) <- newConnSrv c userId connId hasNewConn enableNtfs SCMInvitation Nothing (CR.IKNoPQ pqSup) subMode srv
|
||||
void $ sendInvitation c userId qInfo vrsn cReq cInfo
|
||||
pure connId'
|
||||
pure (connId', False)
|
||||
Nothing -> throwE $ AGENT A_VERSION
|
||||
|
||||
joinConnSrvAsync :: AgentClient -> UserId -> ConnId -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> SMPServerWithAuth -> AM ()
|
||||
joinConnSrvAsync :: AgentClient -> UserId -> ConnId -> Bool -> ConnectionRequestUri c -> ConnInfo -> PQSupport -> SubscriptionMode -> SMPServerWithAuth -> AM SndQueueSecured
|
||||
joinConnSrvAsync c userId connId enableNtfs inv@CRInvitationUri {} cInfo pqSupport subMode srv = do
|
||||
SomeConn cType conn <- withStore c (`getConn` connId)
|
||||
case conn of
|
||||
@@ -875,7 +880,7 @@ joinConnSrvAsync c userId connId enableNtfs inv@CRInvitationUri {} cInfo pqSuppo
|
||||
SndConnection _ sq -> doJoin $ Just sq
|
||||
_ -> throwE $ CMD PROHIBITED $ "joinConnSrvAsync: bad connection " <> show cType
|
||||
where
|
||||
doJoin :: Maybe SndQueue -> AM ()
|
||||
doJoin :: Maybe SndQueue -> AM SndQueueSecured
|
||||
doJoin sq_ = do
|
||||
(cData, sq, _, rc, e2eSndParams) <- startJoinInvitation userId connId sq_ enableNtfs inv pqSupport
|
||||
sq' <- withStore c $ \db -> runExceptT $ do
|
||||
@@ -902,18 +907,14 @@ createReplyQueue c ConnData {userId, connId, enableNtfs} SndQueue {smpClientVers
|
||||
allowConnection' :: AgentClient -> ConnId -> ConfirmationId -> ConnInfo -> AM ()
|
||||
allowConnection' c connId confId ownConnInfo = withConnLock c connId "allowConnection" $ do
|
||||
withStore c (`getConn` connId) >>= \case
|
||||
SomeConn _ (RcvConnection _ rq@RcvQueue {server, rcvId, e2ePrivKey, smpClientVersion = v}) -> do
|
||||
senderKey <- withStore c $ \db -> runExceptT $ do
|
||||
AcceptedConfirmation {ratchetState, senderConf = SMPConfirmation {senderKey, e2ePubKey, smpClientVersion = v'}} <- ExceptT $ acceptConfirmation db confId ownConnInfo
|
||||
liftIO $ createRatchet db connId ratchetState
|
||||
let dhSecret = C.dh' e2ePubKey e2ePrivKey
|
||||
liftIO $ setRcvQueueConfirmedE2E db rq dhSecret $ min v v'
|
||||
pure senderKey
|
||||
SomeConn _ (RcvConnection _ RcvQueue {server, rcvId}) -> do
|
||||
AcceptedConfirmation {senderConf = SMPConfirmation {senderKey}} <-
|
||||
withStore c $ \db -> acceptConfirmation db confId ownConnInfo
|
||||
enqueueCommand c "" connId (Just server) . AInternalCommand $ ICAllowSecure rcvId senderKey
|
||||
_ -> throwE $ CMD PROHIBITED "allowConnection"
|
||||
|
||||
-- | Accept contact (ACPT command) in Reader monad
|
||||
acceptContact' :: AgentClient -> ConnId -> Bool -> InvitationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AM ConnId
|
||||
acceptContact' :: AgentClient -> ConnId -> Bool -> InvitationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AM (ConnId, SndQueueSecured)
|
||||
acceptContact' c connId enableNtfs invId ownConnInfo pqSupport subMode = withConnLock c connId "acceptContact" $ do
|
||||
Invitation {contactConnId, connReq} <- withStore c (`getInvitation` invId)
|
||||
withStore c (`getConn` contactConnId) >>= \case
|
||||
@@ -1150,8 +1151,8 @@ runCommandProcessing c@AgentClient {subQ} server_ Worker {doWork} = do
|
||||
let initUsed = [qServer q]
|
||||
usedSrvs <- newTVarIO initUsed
|
||||
tryCommand . withNextSrv c userId usedSrvs initUsed $ \srv -> do
|
||||
joinConnSrvAsync c userId connId enableNtfs cReq connInfo pqEnc subMode srv
|
||||
notify OK
|
||||
sqSecured <- joinConnSrvAsync c userId connId enableNtfs cReq connInfo pqEnc subMode srv
|
||||
notify $ JOINED sqSecured
|
||||
LET confId ownCInfo -> withServer' . tryCommand $ allowConnection' c connId confId ownCInfo >> notify OK
|
||||
ACK msgId rcptInfo_ -> withServer' . tryCommand $ ackMessage' c connId msgId rcptInfo_ >> notify OK
|
||||
SWCH ->
|
||||
@@ -2487,6 +2488,18 @@ processSMPTransmissions c@AgentClient {subQ} (tSess@(userId, srv, _), _v, sessId
|
||||
confId <- withStore c $ \db -> do
|
||||
setConnAgentVersion db connId agentVersion
|
||||
when (pqSupport /= pqSupport') $ setConnPQSupport db connId pqSupport'
|
||||
-- /
|
||||
-- Starting with agent version 7 (ratchetOnConfSMPAgentVersion),
|
||||
-- initiating party initializes ratchet on processing confirmation;
|
||||
-- previously, it initialized ratchet on allowConnection;
|
||||
-- this is to support decryption of messages that may be received before allowConnection
|
||||
liftIO $ do
|
||||
createRatchet db connId rc'
|
||||
let RcvQueue {smpClientVersion = v, e2ePrivKey = e2ePrivKey'} = rq
|
||||
SMPConfirmation {smpClientVersion = v', e2ePubKey = e2ePubKey'} = senderConf
|
||||
dhSecret = C.dh' e2ePubKey' e2ePrivKey'
|
||||
setRcvQueueConfirmedE2E db rq dhSecret $ min v v'
|
||||
-- /
|
||||
createConfirmation db g newConfirmation
|
||||
let srvs = map qServer $ smpReplyQueues senderConf
|
||||
notify $ CONF confId pqSupport' srvs connInfo
|
||||
@@ -2770,25 +2783,27 @@ connectReplyQueues c cData@ConnData {userId, connId} ownConnInfo sq_ (qInfo :| _
|
||||
Just qInfo' -> do
|
||||
-- in case of SKEY retry the connection is already duplex
|
||||
sq' <- maybe upgradeConn pure sq_
|
||||
agentSecureSndQueue c sq'
|
||||
void $ agentSecureSndQueue c cData sq'
|
||||
enqueueConfirmation c cData sq' ownConnInfo Nothing
|
||||
where
|
||||
upgradeConn = do
|
||||
(sq, _) <- lift $ newSndQueue userId connId qInfo'
|
||||
withStore c $ \db -> upgradeRcvConnToDuplex db connId sq
|
||||
|
||||
secureConfirmQueueAsync :: AgentClient -> ConnData -> SndQueue -> SMPServerWithAuth -> ConnInfo -> Maybe (CR.SndE2ERatchetParams 'C.X448) -> SubscriptionMode -> AM ()
|
||||
secureConfirmQueueAsync :: AgentClient -> ConnData -> SndQueue -> SMPServerWithAuth -> ConnInfo -> Maybe (CR.SndE2ERatchetParams 'C.X448) -> SubscriptionMode -> AM SndQueueSecured
|
||||
secureConfirmQueueAsync c cData sq srv connInfo e2eEncryption_ subMode = do
|
||||
agentSecureSndQueue c sq
|
||||
sqSecured <- agentSecureSndQueue c cData sq
|
||||
storeConfirmation c cData sq e2eEncryption_ =<< mkAgentConfirmation c cData sq srv connInfo subMode
|
||||
lift $ submitPendingMsg c cData sq
|
||||
pure sqSecured
|
||||
|
||||
secureConfirmQueue :: AgentClient -> ConnData -> SndQueue -> SMPServerWithAuth -> ConnInfo -> Maybe (CR.SndE2ERatchetParams 'C.X448) -> SubscriptionMode -> AM ()
|
||||
secureConfirmQueue :: AgentClient -> ConnData -> SndQueue -> SMPServerWithAuth -> ConnInfo -> Maybe (CR.SndE2ERatchetParams 'C.X448) -> SubscriptionMode -> AM SndQueueSecured
|
||||
secureConfirmQueue c cData@ConnData {connId, connAgentVersion, pqSupport} sq srv connInfo e2eEncryption_ subMode = do
|
||||
agentSecureSndQueue c sq
|
||||
sqSecured <- agentSecureSndQueue c cData sq
|
||||
msg <- mkConfirmation =<< mkAgentConfirmation c cData sq srv connInfo subMode
|
||||
void $ sendConfirmation c sq msg
|
||||
withStore' c $ \db -> setSndQueueStatus db sq Confirmed
|
||||
pure sqSecured
|
||||
where
|
||||
mkConfirmation :: AgentMessage -> AM MsgBody
|
||||
mkConfirmation aMessage = do
|
||||
@@ -2801,11 +2816,17 @@ secureConfirmQueue c cData@ConnData {connId, connAgentVersion, pqSupport} sq srv
|
||||
(encConnInfo, _) <- agentRatchetEncrypt db cData agentMsgBody e2eEncConnInfoLength (Just pqEnc) currentE2EVersion
|
||||
pure . smpEncode $ AgentConfirmation {agentVersion = connAgentVersion, e2eEncryption_, encConnInfo}
|
||||
|
||||
agentSecureSndQueue :: AgentClient -> SndQueue -> AM ()
|
||||
agentSecureSndQueue c sq@SndQueue {sndSecure, status} =
|
||||
when (sndSecure && status == New) $ do
|
||||
secureSndQueue c sq
|
||||
withStore' c $ \db -> setSndQueueStatus db sq Secured
|
||||
agentSecureSndQueue :: AgentClient -> ConnData -> SndQueue -> AM SndQueueSecured
|
||||
agentSecureSndQueue c ConnData {connAgentVersion} sq@SndQueue {sndSecure, status}
|
||||
| sndSecure && status == New = do
|
||||
secureSndQueue c sq
|
||||
withStore' c $ \db -> setSndQueueStatus db sq Secured
|
||||
pure initiatorRatchetOnConf
|
||||
-- on repeat JOIN processing (e.g. previous attempt to create reply queue failed)
|
||||
| sndSecure && status == Secured = pure initiatorRatchetOnConf
|
||||
| otherwise = pure False
|
||||
where
|
||||
initiatorRatchetOnConf = connAgentVersion >= ratchetOnConfSMPAgentVersion
|
||||
|
||||
mkAgentConfirmation :: AgentClient -> ConnData -> SndQueue -> SMPServerWithAuth -> ConnInfo -> SubscriptionMode -> AM AgentMessage
|
||||
mkAgentConfirmation c cData sq srv connInfo subMode = do
|
||||
|
||||
@@ -42,6 +42,7 @@ module Simplex.Messaging.Agent.Protocol
|
||||
deliveryRcptsSMPAgentVersion,
|
||||
pqdrSMPAgentVersion,
|
||||
sndAuthKeySMPAgentVersion,
|
||||
ratchetOnConfSMPAgentVersion,
|
||||
currentSMPAgentVersion,
|
||||
supportedSMPAgentVRange,
|
||||
e2eEncConnInfoLength,
|
||||
@@ -49,6 +50,7 @@ module Simplex.Messaging.Agent.Protocol
|
||||
|
||||
-- * SMP agent protocol types
|
||||
ConnInfo,
|
||||
SndQueueSecured,
|
||||
ACommand (..),
|
||||
AEvent (..),
|
||||
AEvt (..),
|
||||
@@ -257,11 +259,14 @@ pqdrSMPAgentVersion = VersionSMPA 5
|
||||
sndAuthKeySMPAgentVersion :: VersionSMPA
|
||||
sndAuthKeySMPAgentVersion = VersionSMPA 6
|
||||
|
||||
ratchetOnConfSMPAgentVersion :: VersionSMPA
|
||||
ratchetOnConfSMPAgentVersion = VersionSMPA 7
|
||||
|
||||
minSupportedSMPAgentVersion :: VersionSMPA
|
||||
minSupportedSMPAgentVersion = duplexHandshakeSMPAgentVersion
|
||||
|
||||
currentSMPAgentVersion :: VersionSMPA
|
||||
currentSMPAgentVersion = VersionSMPA 6
|
||||
currentSMPAgentVersion = VersionSMPA 7
|
||||
|
||||
supportedSMPAgentVRange :: VersionRangeSMPA
|
||||
supportedSMPAgentVRange = mkVersionRange minSupportedSMPAgentVersion currentSMPAgentVersion
|
||||
@@ -327,6 +332,8 @@ deriving instance Show AEvt
|
||||
|
||||
type ConnInfo = ByteString
|
||||
|
||||
type SndQueueSecured = Bool
|
||||
|
||||
-- | Parameterized type for SMP agent events
|
||||
data AEvent (e :: AEntity) where
|
||||
INV :: AConnectionRequestUri -> AEvent AEConn
|
||||
@@ -354,6 +361,7 @@ data AEvent (e :: AEntity) where
|
||||
DEL_USER :: Int64 -> AEvent AENone
|
||||
STAT :: ConnectionStats -> AEvent AEConn
|
||||
OK :: AEvent AEConn
|
||||
JOINED :: SndQueueSecured -> AEvent AEConn
|
||||
ERR :: AgentErrorType -> AEvent AEConn
|
||||
SUSPENDED :: AEvent AENone
|
||||
RFPROG :: Int64 -> Int64 -> AEvent AERcvFile
|
||||
@@ -422,6 +430,7 @@ data AEventTag (e :: AEntity) where
|
||||
DEL_USER_ :: AEventTag AENone
|
||||
STAT_ :: AEventTag AEConn
|
||||
OK_ :: AEventTag AEConn
|
||||
JOINED_ :: AEventTag AEConn
|
||||
ERR_ :: AEventTag AEConn
|
||||
SUSPENDED_ :: AEventTag AENone
|
||||
-- XFTP commands and responses
|
||||
@@ -474,6 +483,7 @@ aEventTag = \case
|
||||
DEL_USER _ -> DEL_USER_
|
||||
STAT _ -> STAT_
|
||||
OK -> OK_
|
||||
JOINED _ -> JOINED_
|
||||
ERR _ -> ERR_
|
||||
SUSPENDED -> SUSPENDED_
|
||||
RFPROG {} -> RFPROG_
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE StrictData #-}
|
||||
|
||||
module Simplex.Messaging.Agent.TRcvQueues
|
||||
( TRcvQueues (getRcvQueues, getConnections),
|
||||
@@ -16,6 +17,7 @@ module Simplex.Messaging.Agent.TRcvQueues
|
||||
where
|
||||
|
||||
import Control.Concurrent.STM
|
||||
import Control.DeepSeq (NFData (..))
|
||||
import Data.Foldable (foldl')
|
||||
import Data.List.NonEmpty (NonEmpty (..), (<|))
|
||||
import qualified Data.List.NonEmpty as L
|
||||
@@ -33,6 +35,8 @@ data TRcvQueues = TRcvQueues
|
||||
getConnections :: TMap ConnId (NonEmpty (UserId, SMPServer, RecipientId))
|
||||
}
|
||||
|
||||
instance NFData TRcvQueues where rnf TRcvQueues {} = ()
|
||||
|
||||
empty :: STM TRcvQueues
|
||||
empty = TRcvQueues <$> TM.empty <*> TM.empty
|
||||
|
||||
|
||||
@@ -244,6 +244,16 @@ data SocksMode
|
||||
SMOnion
|
||||
deriving (Eq, Show)
|
||||
|
||||
instance StrEncoding SocksMode where
|
||||
strEncode = \case
|
||||
SMAlways -> "always"
|
||||
SMOnion -> "onion"
|
||||
strP =
|
||||
A.takeTill (== ' ') >>= \case
|
||||
"always" -> pure SMAlways
|
||||
"onion" -> pure SMOnion
|
||||
_ -> fail "Invalid Socks mode"
|
||||
|
||||
-- | network configuration for the client
|
||||
data NetworkConfig = NetworkConfig
|
||||
{ -- | use SOCKS5 proxy
|
||||
|
||||
@@ -132,7 +132,7 @@ ntfServerCLI cfgPath logPath =
|
||||
{ networkConfig =
|
||||
defaultNetworkConfig
|
||||
{ socksProxy = either error id <$!> strDecodeIni "SUBSCRIBER" "socks_proxy" ini,
|
||||
socksMode = either (const SMOnion) textToSocksMode $ lookupValue "SUBSCRIBER" "socks_mode" ini
|
||||
socksMode = maybe SMOnion (either error id) $! strDecodeIni "SUBSCRIBER" "socks_mode" ini
|
||||
}
|
||||
},
|
||||
persistErrorInterval = 0 -- seconds
|
||||
|
||||
@@ -181,6 +181,7 @@ module Simplex.Messaging.Protocol
|
||||
where
|
||||
|
||||
import Control.Applicative (optional, (<|>))
|
||||
import Control.DeepSeq (NFData (..))
|
||||
import Control.Exception (Exception)
|
||||
import Control.Monad
|
||||
import Control.Monad.Except
|
||||
@@ -898,6 +899,8 @@ deriving instance Ord (SProtocolType p)
|
||||
|
||||
deriving instance Show (SProtocolType p)
|
||||
|
||||
instance NFData (SProtocolType p) where rnf spt = spt `seq` ()
|
||||
|
||||
data AProtocolType = forall p. ProtocolTypeI p => AProtocolType (SProtocolType p)
|
||||
|
||||
instance Eq AProtocolType where
|
||||
@@ -982,6 +985,8 @@ data ProtocolServer p = ProtocolServer
|
||||
|
||||
data AProtocolServer = forall p. ProtocolTypeI p => AProtocolServer (SProtocolType p) (ProtocolServer p)
|
||||
|
||||
instance NFData (ProtocolServer p) where rnf ProtocolServer {} = ()
|
||||
|
||||
instance ProtocolTypeI p => IsString (ProtocolServer p) where
|
||||
fromString = parseString strDecode
|
||||
|
||||
|
||||
+135
-73
@@ -158,7 +158,7 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
forall s.
|
||||
Server ->
|
||||
String ->
|
||||
(Server -> TQueue (QueueId, Client)) ->
|
||||
(Server -> TQueue (QueueId, Client, Subscribed)) ->
|
||||
(Server -> TMap QueueId Client) ->
|
||||
(Client -> TMap QueueId s) ->
|
||||
(s -> IO ()) ->
|
||||
@@ -172,14 +172,16 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
where
|
||||
updateSubscribers :: STM (Maybe (QueueId, Client))
|
||||
updateSubscribers = do
|
||||
(qId, clnt) <- readTQueue $ subQ s
|
||||
let clientToBeNotified c' =
|
||||
if sameClientId clnt c'
|
||||
then pure Nothing
|
||||
else do
|
||||
(qId, clnt, subscribed) <- readTQueue $ subQ s
|
||||
let updateSub
|
||||
| subscribed = TM.lookupInsert qId clnt (subs s)
|
||||
| otherwise = TM.lookupDelete qId (subs s)
|
||||
clientToBeNotified c'
|
||||
| sameClientId clnt c' = pure Nothing
|
||||
| otherwise = do
|
||||
yes <- readTVar $ connected c'
|
||||
pure $ if yes then Just (qId, c') else Nothing
|
||||
TM.lookupInsert qId clnt (subs s) $>>= clientToBeNotified
|
||||
updateSub $>>= clientToBeNotified
|
||||
endPreviousSubscriptions :: (QueueId, Client) -> M (Maybe s)
|
||||
endPreviousSubscriptions (qId, c) = do
|
||||
forkClient c (label <> ".endPreviousSubscriptions") $
|
||||
@@ -229,7 +231,7 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
initialDelay <- (startAt -) . fromIntegral . (`div` 1000000_000000) . diffTimeToPicoseconds . utctDayTime <$> liftIO getCurrentTime
|
||||
liftIO $ putStrLn $ "server stats log enabled: " <> statsFilePath
|
||||
liftIO $ threadDelay' $ 1000000 * (initialDelay + if initialDelay < 0 then 86400 else 0)
|
||||
ss@ServerStats {fromTime, qCreated, qSecured, qDeletedAll, qDeletedNew, qDeletedSecured, qSub, qSubAuth, qSubDuplicate, qSubProhibited, msgSent, msgSentAuth, msgSentQuota, msgSentLarge, msgRecv, msgExpired, activeQueues, msgSentNtf, msgRecvNtf, activeQueuesNtf, qCount, msgCount, pRelays, pRelaysOwn, pMsgFwds, pMsgFwdsOwn, pMsgFwdsRecv} <- asks serverStats
|
||||
ss@ServerStats {fromTime, qCreated, qSecured, qDeletedAll, qDeletedNew, qDeletedSecured, qSub, qSubNoMsg, qSubAuth, qSubDuplicate, qSubProhibited, msgSent, msgSentAuth, msgSentQuota, msgSentLarge, msgRecv, msgRecvGet, msgGet, msgGetNoMsg, msgGetAuth, msgGetDuplicate, msgGetProhibited, msgExpired, activeQueues, msgSentNtf, msgRecvNtf, activeQueuesNtf, qCount, msgCount, pRelays, pRelaysOwn, pMsgFwds, pMsgFwdsOwn, pMsgFwdsRecv} <- asks serverStats
|
||||
let interval = 1000000 * logInterval
|
||||
forever $ do
|
||||
withFile statsFilePath AppendMode $ \h -> liftIO $ do
|
||||
@@ -242,6 +244,7 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
qDeletedNew' <- atomically $ swapTVar qDeletedNew 0
|
||||
qDeletedSecured' <- atomically $ swapTVar qDeletedSecured 0
|
||||
qSub' <- atomically $ swapTVar qSub 0
|
||||
qSubNoMsg' <- atomically $ swapTVar qSubNoMsg 0
|
||||
qSubAuth' <- atomically $ swapTVar qSubAuth 0
|
||||
qSubDuplicate' <- atomically $ swapTVar qSubDuplicate 0
|
||||
qSubProhibited' <- atomically $ swapTVar qSubProhibited 0
|
||||
@@ -250,6 +253,12 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
msgSentQuota' <- atomically $ swapTVar msgSentQuota 0
|
||||
msgSentLarge' <- atomically $ swapTVar msgSentLarge 0
|
||||
msgRecv' <- atomically $ swapTVar msgRecv 0
|
||||
msgRecvGet' <- atomically $ swapTVar msgRecvGet 0
|
||||
msgGet' <- atomically $ swapTVar msgGet 0
|
||||
msgGetNoMsg' <- atomically $ swapTVar msgGetNoMsg 0
|
||||
msgGetAuth' <- atomically $ swapTVar msgGetAuth 0
|
||||
msgGetDuplicate' <- atomically $ swapTVar msgGetDuplicate 0
|
||||
msgGetProhibited' <- atomically $ swapTVar msgGetProhibited 0
|
||||
msgExpired' <- atomically $ swapTVar msgExpired 0
|
||||
ps <- atomically $ periodStatCounts activeQueues ts
|
||||
msgSentNtf' <- atomically $ swapTVar msgSentNtf 0
|
||||
@@ -302,7 +311,14 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
show msgSentLarge',
|
||||
show msgNtfs',
|
||||
show msgNtfNoSub',
|
||||
show msgNtfLost'
|
||||
show msgNtfLost',
|
||||
show qSubNoMsg',
|
||||
show msgRecvGet',
|
||||
show msgGet',
|
||||
show msgGetNoMsg',
|
||||
show msgGetAuth',
|
||||
show msgGetDuplicate',
|
||||
show msgGetProhibited'
|
||||
]
|
||||
)
|
||||
liftIO $ threadDelay' interval
|
||||
@@ -394,6 +410,12 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
readTVarIO (day $ activeQueues ss) >>= \v -> B.hPutStr h $ "dayMsgQueues" <> ": " <> bshow (S.size v) <> "\n"
|
||||
putStat "msgSent" msgSent
|
||||
putStat "msgRecv" msgRecv
|
||||
putStat "msgRecvGet" msgRecvGet
|
||||
putStat "msgGet" msgGet
|
||||
putStat "msgGetNoMsg" msgGetNoMsg
|
||||
putStat "msgGetAuth" msgGetAuth
|
||||
putStat "msgGetDuplicate" msgGetDuplicate
|
||||
putStat "msgGetProhibited" msgGetProhibited
|
||||
putStat "msgSentNtf" msgSentNtf
|
||||
putStat "msgRecvNtf" msgRecvNtf
|
||||
putStat "qCount" qCount
|
||||
@@ -452,9 +474,10 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
activeClients <- readTVarIO clients
|
||||
hPutStrLn h $ "Clients: " <> show (IM.size activeClients)
|
||||
when (r == CPRAdmin) $ do
|
||||
(smpSubCnt, smpClCnt) <- countClientSubs subscriptions activeClients
|
||||
(ntfSubCnt, ntfClCnt) <- countClientSubs ntfSubscriptions activeClients
|
||||
(smpSubCnt, smpSubCntByGroup, smpClCnt) <- countClientSubs subscriptions countSMPSubs activeClients
|
||||
(ntfSubCnt, _, ntfClCnt) <- countClientSubs ntfSubscriptions (\_ -> pure (0, 0, 0, 0)) activeClients
|
||||
hPutStrLn h $ "SMP subscriptions (via clients, slow): " <> show smpSubCnt
|
||||
hPutStrLn h $ "SMP subscriptions (by group: NoSub, SubPending, SubThread, ProhibitSub): " <> show smpSubCntByGroup
|
||||
hPutStrLn h $ "SMP subscribed clients (via clients, slow): " <> show smpClCnt
|
||||
hPutStrLn h $ "Ntf subscriptions (via clients, slow): " <> show ntfSubCnt
|
||||
hPutStrLn h $ "Ntf subscribed clients (via clients, slow): " <> show ntfClCnt
|
||||
@@ -465,14 +488,25 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} = do
|
||||
hPutStrLn h $ "Ntf subscriptions: " <> show (M.size activeNtfSubs)
|
||||
hPutStrLn h $ "Ntf subscribed clients: " <> show (countSubClients activeNtfSubs)
|
||||
where
|
||||
countClientSubs :: (Client -> TMap QueueId a) -> IM.IntMap Client -> IO (Int, Int)
|
||||
countClientSubs subSel = foldM addSubs (0, 0)
|
||||
countClientSubs :: (Client -> TMap QueueId a) -> (M.Map QueueId a -> IO (Int, Int, Int, Int)) -> IM.IntMap Client -> IO (Int, (Int, Int, Int, Int), Int)
|
||||
countClientSubs subSel countSubs = foldM addSubs (0, (0, 0, 0, 0), 0)
|
||||
where
|
||||
addSubs :: (Int, Int) -> Client -> IO (Int, Int)
|
||||
addSubs (subCnt, clCnt) cl = do
|
||||
addSubs :: (Int, (Int, Int, Int, Int), Int) -> Client -> IO (Int, (Int, Int, Int, Int), Int)
|
||||
addSubs (subCnt, (c1, c2, c3, c4), clCnt) cl = do
|
||||
subs <- readTVarIO $ subSel cl
|
||||
(c1', c2', c3', c4') <- countSubs subs
|
||||
let cnt = M.size subs
|
||||
pure (subCnt + cnt, clCnt + if cnt == 0 then 0 else 1)
|
||||
cnts' = (c1 + c1', c2 + c2', c3 + c3', c4 + c4')
|
||||
pure (subCnt + cnt, cnts', clCnt + if cnt == 0 then 0 else 1)
|
||||
countSMPSubs :: M.Map QueueId Sub -> IO (Int, Int, Int, Int)
|
||||
countSMPSubs = foldM countSubs (0, 0, 0, 0)
|
||||
where
|
||||
countSubs (c1, c2, c3, c4) Sub {subThread} =
|
||||
readTVarIO subThread >>= \st -> pure $ case st of
|
||||
NoSub -> (c1 + 1, c2, c3, c4)
|
||||
SubPending -> (c1, c2 + 1, c3, c4)
|
||||
SubThread _ -> (c1, c2, c3 + 1, c4)
|
||||
ProhibitSub -> (c1, c2, c3, c4 + 1)
|
||||
countSubClients = S.size . M.foldr' (S.insert . clientId) S.empty
|
||||
CPDelete queueId' -> withUserRole $ unliftIO u $ do
|
||||
st <- asks queueStore
|
||||
@@ -531,19 +565,22 @@ runClientTransport h@THandle {params = thParams@THandleParams {thVersion, sessio
|
||||
noSubscriptions c = atomically $ (&&) <$> TM.null (subscriptions c) <*> TM.null (ntfSubscriptions c)
|
||||
|
||||
clientDisconnected :: Client -> M ()
|
||||
clientDisconnected c@Client {clientId, subscriptions, connected, sessionId, endThreads} = do
|
||||
clientDisconnected c@Client {clientId, subscriptions, ntfSubscriptions, connected, sessionId, endThreads} = do
|
||||
labelMyThread . B.unpack $ "client $" <> encode sessionId <> " disc"
|
||||
subs <- atomically $ do
|
||||
(subs, ntfSubs) <- atomically $ do
|
||||
writeTVar connected False
|
||||
swapTVar subscriptions M.empty
|
||||
(,) <$> swapTVar subscriptions M.empty <*> swapTVar ntfSubscriptions M.empty
|
||||
liftIO $ mapM_ cancelSub subs
|
||||
srvSubs <- asks $ subscribers . server
|
||||
atomically $ modifyTVar' srvSubs $ \cs ->
|
||||
M.foldrWithKey (\sub _ -> M.update deleteCurrentClient sub) cs subs
|
||||
Server {subscribers, notifiers} <- asks server
|
||||
updateSubscribers subs subscribers
|
||||
updateSubscribers ntfSubs notifiers
|
||||
asks clients >>= atomically . (`modifyTVar'` IM.delete clientId)
|
||||
tIds <- atomically $ swapTVar endThreads IM.empty
|
||||
liftIO $ mapM_ (mapM_ killThread <=< deRefWeak) tIds
|
||||
where
|
||||
updateSubscribers subs srvSubs = do
|
||||
atomically $ modifyTVar' srvSubs $ \cs ->
|
||||
M.foldrWithKey (\sub _ -> M.update deleteCurrentClient sub) cs subs
|
||||
deleteCurrentClient :: Client -> Maybe Client
|
||||
deleteCurrentClient c'
|
||||
| sameClientId c c' = Nothing
|
||||
@@ -579,8 +616,9 @@ receive h@THandle {params = THandleParams {thAuth}} Client {rcvQ, sndQ, rcvActiv
|
||||
VRVerified qr -> pure $ Right (qr, (corrId, entId, cmd))
|
||||
VRFailed -> do
|
||||
case cmd of
|
||||
Cmd _ SEND {} -> atomically $ modifyTVar' (msgSentAuth stats) (+ 1)
|
||||
Cmd _ SUB -> atomically $ modifyTVar' (qSubAuth stats) (+ 1)
|
||||
Cmd _ SEND {} -> incStat $ msgSentAuth stats
|
||||
Cmd _ SUB -> incStat $ qSubAuth stats
|
||||
Cmd _ GET -> incStat $ msgGetAuth stats
|
||||
_ -> pure ()
|
||||
pure $ Left (corrId, entId, ERR AUTH)
|
||||
write q = mapM_ (atomically . writeTBQueue q) . L.nonEmpty
|
||||
@@ -808,8 +846,8 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
transportErr = PROXY . BROKER . TRANSPORT
|
||||
mkIncProxyStats :: MonadIO m => ProxyStats -> ProxyStats -> OwnServer -> (ProxyStats -> TVar Int) -> m ()
|
||||
mkIncProxyStats ps psOwn own sel = do
|
||||
atomically $ modifyTVar' (sel ps) (+ 1)
|
||||
when own $ atomically $ modifyTVar' (sel psOwn) (+ 1)
|
||||
incStat $ sel ps
|
||||
when own $ incStat $ sel psOwn
|
||||
processCommand :: (Maybe QueueRec, Transmission Cmd) -> M (Maybe (Transmission BrokerMsg))
|
||||
processCommand (qr_, (corrId, queueId, cmd)) = case cmd of
|
||||
Cmd SProxiedClient command -> processProxiedCmd (corrId, queueId, command)
|
||||
@@ -878,8 +916,8 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
Right _ -> do
|
||||
withLog (`logCreateById` rId)
|
||||
stats <- asks serverStats
|
||||
atomically $ modifyTVar' (qCreated stats) (+ 1)
|
||||
atomically $ modifyTVar' (qCount stats) (+ 1)
|
||||
incStat $ qCreated stats
|
||||
incStat $ qCount stats
|
||||
case subMode of
|
||||
SMOnlyCreate -> pure ()
|
||||
SMSubscribe -> void $ subscribeQueue qr rId
|
||||
@@ -901,7 +939,7 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
withLog $ \s -> logSecureQueue s rId sKey
|
||||
st <- asks queueStore
|
||||
stats <- asks serverStats
|
||||
atomically $ modifyTVar' (qSecured stats) (+ 1)
|
||||
incStat $ qSecured stats
|
||||
atomically $ either ERR (const OK) <$> secureQueue st rId sKey
|
||||
|
||||
addQueueNotifier_ :: QueueStore -> NtfPublicAuthKey -> RcvNtfPublicDhKey -> M (Transmission BrokerMsg)
|
||||
@@ -925,7 +963,12 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
deleteQueueNotifier_ :: QueueStore -> M (Transmission BrokerMsg)
|
||||
deleteQueueNotifier_ st = do
|
||||
withLog (`logDeleteNotifier` queueId)
|
||||
okResp <$> atomically (deleteQueueNotifier st queueId)
|
||||
atomically (deleteQueueNotifier st queueId) >>= \case
|
||||
Right () -> do
|
||||
-- Possibly, the same should be done if the queue is suspended, but currently we do not use it
|
||||
atomically $ writeTQueue ntfSubscribedQ (queueId, clnt, False)
|
||||
pure ok
|
||||
Left e -> pure $ err e
|
||||
|
||||
suspendQueue_ :: QueueStore -> M (Transmission BrokerMsg)
|
||||
suspendQueue_ st = do
|
||||
@@ -934,60 +977,69 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
|
||||
subscribeQueue :: QueueRec -> RecipientId -> M (Transmission BrokerMsg)
|
||||
subscribeQueue qr rId = do
|
||||
stats <- asks serverStats
|
||||
atomically (TM.lookup rId subscriptions) >>= \case
|
||||
Nothing -> do
|
||||
atomically $ modifyTVar' (qSub stats) (+ 1)
|
||||
newSub >>= deliver
|
||||
Just s@Sub {subThread} ->
|
||||
Nothing -> newSub >>= deliver True
|
||||
Just s@Sub {subThread} -> do
|
||||
stats <- asks serverStats
|
||||
readTVarIO subThread >>= \case
|
||||
ProhibitSub -> do
|
||||
-- cannot use SUB in the same connection where GET was used
|
||||
atomically $ modifyTVar' (qSubProhibited stats) (+ 1)
|
||||
incStat $ qSubProhibited stats
|
||||
pure (corrId, rId, ERR $ CMD PROHIBITED)
|
||||
_ -> do
|
||||
atomically $ modifyTVar' (qSubDuplicate stats) (+ 1)
|
||||
atomically (tryTakeTMVar $ delivered s) >> deliver s
|
||||
incStat $ qSubDuplicate stats
|
||||
atomically (tryTakeTMVar $ delivered s) >> deliver False s
|
||||
where
|
||||
newSub :: M Sub
|
||||
newSub = time "SUB newSub" . atomically $ do
|
||||
writeTQueue subscribedQ (rId, clnt)
|
||||
writeTQueue subscribedQ (rId, clnt, True)
|
||||
sub <- newSubscription NoSub
|
||||
TM.insert rId sub subscriptions
|
||||
pure sub
|
||||
deliver :: Sub -> M (Transmission BrokerMsg)
|
||||
deliver sub = do
|
||||
deliver :: Bool -> Sub -> M (Transmission BrokerMsg)
|
||||
deliver inc sub = do
|
||||
q <- getStoreMsgQueue "SUB" rId
|
||||
msg_ <- atomically $ tryPeekMsg q
|
||||
when inc $ do
|
||||
stats <- asks serverStats
|
||||
incStat $ (if isJust msg_ then qSub else qSubNoMsg) stats
|
||||
deliverMessage "SUB" qr rId sub msg_
|
||||
|
||||
getMessage :: QueueRec -> M (Transmission BrokerMsg)
|
||||
getMessage qr = time "GET" $ do
|
||||
atomically (TM.lookup queueId subscriptions) >>= \case
|
||||
Nothing ->
|
||||
atomically newSub >>= getMessage_
|
||||
atomically newSub >>= (`getMessage_` Nothing)
|
||||
Just s@Sub {subThread} ->
|
||||
readTVarIO subThread >>= \case
|
||||
ProhibitSub ->
|
||||
atomically (tryTakeTMVar $ delivered s)
|
||||
>> getMessage_ s
|
||||
>>= getMessage_ s
|
||||
-- cannot use GET in the same connection where there is an active subscription
|
||||
_ -> pure (corrId, queueId, ERR $ CMD PROHIBITED)
|
||||
_ -> do
|
||||
stats <- asks serverStats
|
||||
incStat $ msgGetProhibited stats
|
||||
pure (corrId, queueId, ERR $ CMD PROHIBITED)
|
||||
where
|
||||
newSub :: STM Sub
|
||||
newSub = do
|
||||
s <- newSubscription ProhibitSub
|
||||
TM.insert queueId s subscriptions
|
||||
pure s
|
||||
getMessage_ :: Sub -> M (Transmission BrokerMsg)
|
||||
getMessage_ s = do
|
||||
getMessage_ :: Sub -> Maybe MsgId -> M (Transmission BrokerMsg)
|
||||
getMessage_ s delivered_ = do
|
||||
q <- getStoreMsgQueue "GET" queueId
|
||||
atomically $
|
||||
tryPeekMsg q >>= \case
|
||||
Just msg ->
|
||||
let encMsg = encryptMsg qr msg
|
||||
in setDelivered s msg $> (corrId, queueId, MSG encMsg)
|
||||
_ -> pure (corrId, queueId, OK)
|
||||
stats <- asks serverStats
|
||||
(statCnt, r) <-
|
||||
atomically $
|
||||
tryPeekMsg q >>= \case
|
||||
Just msg ->
|
||||
let encMsg = encryptMsg qr msg
|
||||
cnt = if isJust delivered_ then msgGetDuplicate else msgGet
|
||||
in setDelivered s msg $> (cnt, (corrId, queueId, MSG encMsg))
|
||||
_ -> pure (msgGetNoMsg, (corrId, queueId, OK))
|
||||
incStat $ statCnt stats
|
||||
pure r
|
||||
|
||||
withQueue :: (QueueRec -> M (Transmission BrokerMsg)) -> M (Transmission BrokerMsg)
|
||||
withQueue action = maybe (pure $ err AUTH) action qr_
|
||||
@@ -995,7 +1047,7 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
subscribeNotifications :: M (Transmission BrokerMsg)
|
||||
subscribeNotifications = time "NSUB" . atomically $ do
|
||||
unlessM (TM.member queueId ntfSubscriptions) $ do
|
||||
writeTQueue ntfSubscribedQ (queueId, clnt)
|
||||
writeTQueue ntfSubscribedQ (queueId, clnt, True)
|
||||
TM.insert queueId () ntfSubscriptions
|
||||
pure ok
|
||||
|
||||
@@ -1010,11 +1062,11 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
case st of
|
||||
ProhibitSub -> do
|
||||
deletedMsg_ <- atomically $ tryDelMsg q msgId
|
||||
mapM_ updateStats deletedMsg_
|
||||
mapM_ (updateStats True) deletedMsg_
|
||||
pure ok
|
||||
_ -> do
|
||||
(deletedMsg_, msg_) <- atomically $ tryDelPeekMsg q msgId
|
||||
mapM_ updateStats deletedMsg_
|
||||
mapM_ (updateStats False) deletedMsg_
|
||||
deliverMessage "ACK" qr queueId sub msg_
|
||||
_ -> pure $ err NO_MSG
|
||||
where
|
||||
@@ -1024,29 +1076,30 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
if msgId == msgId' || B.null msgId
|
||||
then Just <$> readTVar subThread
|
||||
else putTMVar delivered msgId' $> Nothing
|
||||
updateStats :: Message -> M ()
|
||||
updateStats = \case
|
||||
updateStats :: Bool -> Message -> M ()
|
||||
updateStats isGet = \case
|
||||
MessageQuota {} -> pure ()
|
||||
Message {msgFlags} -> do
|
||||
stats <- asks serverStats
|
||||
atomically $ modifyTVar' (msgRecv stats) (+ 1)
|
||||
incStat $ msgRecv stats
|
||||
when isGet $ incStat $ msgRecvGet stats
|
||||
atomically $ modifyTVar' (msgCount stats) (subtract 1)
|
||||
atomically $ updatePeriodStats (activeQueues stats) queueId
|
||||
when (notification msgFlags) $ do
|
||||
atomically $ modifyTVar' (msgRecvNtf stats) (+ 1)
|
||||
incStat $ msgRecvNtf stats
|
||||
atomically $ updatePeriodStats (activeQueuesNtf stats) queueId
|
||||
|
||||
sendMessage :: QueueRec -> MsgFlags -> MsgBody -> M (Transmission BrokerMsg)
|
||||
sendMessage qr msgFlags msgBody
|
||||
| B.length msgBody > maxMessageLength thVersion = do
|
||||
stats <- asks serverStats
|
||||
atomically $ modifyTVar' (msgSentLarge stats) (+ 1)
|
||||
incStat $ msgSentLarge stats
|
||||
pure $ err LARGE_MSG
|
||||
| otherwise = do
|
||||
stats <- asks serverStats
|
||||
case status qr of
|
||||
QueueOff -> do
|
||||
atomically $ modifyTVar' (msgSentAuth stats) (+ 1)
|
||||
incStat $ msgSentAuth stats
|
||||
pure $ err AUTH
|
||||
QueueActive ->
|
||||
case C.maxLenBS msgBody of
|
||||
@@ -1058,7 +1111,7 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
atomically . writeMsg q =<< mkMessage body
|
||||
case msg_ of
|
||||
Nothing -> do
|
||||
atomically $ modifyTVar' (msgSentQuota stats) (+ 1)
|
||||
incStat $ msgSentQuota stats
|
||||
pure $ err QUOTA
|
||||
Just (msg, wasEmpty) -> time "SEND ok" $ do
|
||||
when wasEmpty $ tryDeliverMessage msg
|
||||
@@ -1066,16 +1119,16 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
forM_ (notifier qr) $ \ntf -> do
|
||||
asks random >>= atomically . trySendNotification ntf msg >>= \case
|
||||
Nothing -> do
|
||||
atomically $ modifyTVar' (msgNtfNoSub stats) (+ 1)
|
||||
incStat $ msgNtfNoSub stats
|
||||
logWarn "No notification subscription"
|
||||
Just False -> do
|
||||
atomically $ modifyTVar' (msgNtfLost stats) (+ 1)
|
||||
incStat $ msgNtfLost stats
|
||||
logWarn "Dropped message notification"
|
||||
Just True -> atomically $ modifyTVar' (msgNtfs stats) (+ 1)
|
||||
atomically $ modifyTVar' (msgSentNtf stats) (+ 1)
|
||||
Just True -> incStat $ msgNtfs stats
|
||||
incStat $ msgSentNtf stats
|
||||
atomically $ updatePeriodStats (activeQueuesNtf stats) (recipientId qr)
|
||||
atomically $ modifyTVar' (msgSent stats) (+ 1)
|
||||
atomically $ modifyTVar' (msgCount stats) (+ 1)
|
||||
incStat $ msgSent stats
|
||||
incStat $ msgCount stats
|
||||
atomically $ updatePeriodStats (activeQueues stats) (recipientId qr)
|
||||
pure ok
|
||||
where
|
||||
@@ -1197,7 +1250,7 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
let fr = FwdResponse {fwdCorrId, fwdResponse = r2}
|
||||
r3 = EncFwdResponse $ C.cbEncryptNoPad sessSecret (C.reverseNonce proxyNonce) (smpEncode fr)
|
||||
stats <- asks serverStats
|
||||
atomically $ modifyTVar' (pMsgFwdsRecv stats) (+ 1)
|
||||
incStat $ pMsgFwdsRecv stats
|
||||
pure $ RRES r3
|
||||
where
|
||||
rejectOrVerify :: Maybe (THandleAuth 'TServer) -> SignedTransmission ErrorType Cmd -> M (Either (Transmission BrokerMsg) (Maybe QueueRec, Transmission Cmd))
|
||||
@@ -1254,7 +1307,12 @@ client thParams' clnt@Client {subscriptions, ntfSubscriptions, rcvQ, sndQ, sessi
|
||||
withLog (`logDeleteQueue` queueId)
|
||||
ms <- asks msgStore
|
||||
atomically (deleteQueue st queueId $>>= \q -> delMsgQueue ms queueId $> Right q) >>= \case
|
||||
Right q -> updateDeletedStats q $> ok
|
||||
Right q -> do
|
||||
-- Possibly, the same should be done if the queue is suspended, but currently we do not use it
|
||||
atomically $ writeTQueue subscribedQ (queueId, clnt, False)
|
||||
atomically $ writeTQueue ntfSubscribedQ (queueId, clnt, False)
|
||||
updateDeletedStats q
|
||||
pure ok
|
||||
Left e -> pure $ err e
|
||||
|
||||
getQueueInfo :: QueueRec -> M (Transmission BrokerMsg)
|
||||
@@ -1290,9 +1348,13 @@ updateDeletedStats :: QueueRec -> M ()
|
||||
updateDeletedStats q = do
|
||||
stats <- asks serverStats
|
||||
let delSel = if isNothing (senderKey q) then qDeletedNew else qDeletedSecured
|
||||
atomically $ modifyTVar' (delSel stats) (+ 1)
|
||||
atomically $ modifyTVar' (qDeletedAll stats) (+ 1)
|
||||
atomically $ modifyTVar' (qCount stats) (subtract 1)
|
||||
incStat $ delSel stats
|
||||
incStat $ qDeletedAll stats
|
||||
incStat $ qCount stats
|
||||
|
||||
incStat :: MonadIO m => TVar Int -> m ()
|
||||
incStat v = atomically $ modifyTVar' v (+ 1)
|
||||
{-# INLINE incStat #-}
|
||||
|
||||
withLog :: (StoreLog 'WriteMode -> IO a) -> M ()
|
||||
withLog action = do
|
||||
|
||||
@@ -24,7 +24,6 @@ import qualified Data.X509.File as XF
|
||||
import Data.X509.Validation (Fingerprint (..))
|
||||
import Network.Socket (HostName, ServiceName)
|
||||
import Options.Applicative
|
||||
import Simplex.Messaging.Client (SocksMode (..))
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Protocol (ProtoServerWithAuth (..), ProtocolServer (..), ProtocolTypeI)
|
||||
import Simplex.Messaging.Transport (ATransport (..), TLS, Transport (..))
|
||||
@@ -302,9 +301,3 @@ clearDirIfExists path = whenM (doesDirectoryExist path) $ listDirectory path >>=
|
||||
|
||||
getEnvPath :: String -> FilePath -> IO FilePath
|
||||
getEnvPath name def = maybe def (\case "" -> def; f -> f) <$> lookupEnv name
|
||||
|
||||
textToSocksMode :: Text -> SocksMode
|
||||
textToSocksMode = \case
|
||||
"always" -> SMAlways
|
||||
"onion" -> SMOnion
|
||||
s -> error . T.unpack $ "Invalid socks_mode: " <> s
|
||||
|
||||
@@ -128,10 +128,12 @@ data Env = Env
|
||||
proxyAgent :: ProxyAgent -- senders served on this proxy
|
||||
}
|
||||
|
||||
type Subscribed = Bool
|
||||
|
||||
data Server = Server
|
||||
{ subscribedQ :: TQueue (RecipientId, Client),
|
||||
{ subscribedQ :: TQueue (RecipientId, Client, Subscribed),
|
||||
subscribers :: TMap RecipientId Client,
|
||||
ntfSubscribedQ :: TQueue (NotifierId, Client),
|
||||
ntfSubscribedQ :: TQueue (NotifierId, Client, Subscribed),
|
||||
notifiers :: TMap NotifierId Client,
|
||||
savingLock :: Lock
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ smpServerCLI_ generateSite serveStaticFiles cfgPath logPath =
|
||||
networkConfig =
|
||||
defaultNetworkConfig
|
||||
{ socksProxy = either error id <$!> strDecodeIni "PROXY" "socks_proxy" ini,
|
||||
socksMode = either (const SMOnion) textToSocksMode $ lookupValue "PROXY" "socks_mode" ini,
|
||||
socksMode = maybe SMOnion (either error id) $! strDecodeIni "PROXY" "socks_mode" ini,
|
||||
hostMode = either (const HMPublic) textToHostMode $ lookupValue "PROXY" "host_mode" ini,
|
||||
requiredHostMode = fromMaybe False $ iniOnOff "PROXY" "required_host_mode" ini
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ data ServerStats = ServerStats
|
||||
qDeletedNew :: TVar Int,
|
||||
qDeletedSecured :: TVar Int,
|
||||
qSub :: TVar Int,
|
||||
qSubNoMsg :: TVar Int,
|
||||
qSubAuth :: TVar Int,
|
||||
qSubDuplicate :: TVar Int,
|
||||
qSubProhibited :: TVar Int,
|
||||
@@ -35,6 +36,12 @@ data ServerStats = ServerStats
|
||||
msgSentQuota :: TVar Int,
|
||||
msgSentLarge :: TVar Int,
|
||||
msgRecv :: TVar Int,
|
||||
msgRecvGet :: TVar Int,
|
||||
msgGet :: TVar Int,
|
||||
msgGetNoMsg :: TVar Int,
|
||||
msgGetAuth :: TVar Int,
|
||||
msgGetDuplicate :: TVar Int,
|
||||
msgGetProhibited :: TVar Int,
|
||||
msgExpired :: TVar Int,
|
||||
activeQueues :: PeriodStats RecipientId,
|
||||
msgSentNtf :: TVar Int, -- sent messages with NTF flag
|
||||
@@ -60,6 +67,7 @@ data ServerStatsData = ServerStatsData
|
||||
_qDeletedNew :: Int,
|
||||
_qDeletedSecured :: Int,
|
||||
_qSub :: Int,
|
||||
_qSubNoMsg :: Int,
|
||||
_qSubAuth :: Int,
|
||||
_qSubDuplicate :: Int,
|
||||
_qSubProhibited :: Int,
|
||||
@@ -68,6 +76,12 @@ data ServerStatsData = ServerStatsData
|
||||
_msgSentQuota :: Int,
|
||||
_msgSentLarge :: Int,
|
||||
_msgRecv :: Int,
|
||||
_msgRecvGet :: Int,
|
||||
_msgGet :: Int,
|
||||
_msgGetNoMsg :: Int,
|
||||
_msgGetAuth :: Int,
|
||||
_msgGetDuplicate :: Int,
|
||||
_msgGetProhibited :: Int,
|
||||
_msgExpired :: Int,
|
||||
_activeQueues :: PeriodStatsData RecipientId,
|
||||
_msgSentNtf :: Int,
|
||||
@@ -95,6 +109,7 @@ newServerStats ts = do
|
||||
qDeletedNew <- newTVar 0
|
||||
qDeletedSecured <- newTVar 0
|
||||
qSub <- newTVar 0
|
||||
qSubNoMsg <- newTVar 0
|
||||
qSubAuth <- newTVar 0
|
||||
qSubDuplicate <- newTVar 0
|
||||
qSubProhibited <- newTVar 0
|
||||
@@ -103,6 +118,12 @@ newServerStats ts = do
|
||||
msgSentQuota <- newTVar 0
|
||||
msgSentLarge <- newTVar 0
|
||||
msgRecv <- newTVar 0
|
||||
msgRecvGet <- newTVar 0
|
||||
msgGet <- newTVar 0
|
||||
msgGetNoMsg <- newTVar 0
|
||||
msgGetAuth <- newTVar 0
|
||||
msgGetDuplicate <- newTVar 0
|
||||
msgGetProhibited <- newTVar 0
|
||||
msgExpired <- newTVar 0
|
||||
activeQueues <- newPeriodStats
|
||||
msgSentNtf <- newTVar 0
|
||||
@@ -127,6 +148,7 @@ newServerStats ts = do
|
||||
qDeletedNew,
|
||||
qDeletedSecured,
|
||||
qSub,
|
||||
qSubNoMsg,
|
||||
qSubAuth,
|
||||
qSubDuplicate,
|
||||
qSubProhibited,
|
||||
@@ -135,6 +157,12 @@ newServerStats ts = do
|
||||
msgSentQuota,
|
||||
msgSentLarge,
|
||||
msgRecv,
|
||||
msgRecvGet,
|
||||
msgGet,
|
||||
msgGetNoMsg,
|
||||
msgGetAuth,
|
||||
msgGetDuplicate,
|
||||
msgGetProhibited,
|
||||
msgExpired,
|
||||
activeQueues,
|
||||
msgSentNtf,
|
||||
@@ -161,6 +189,7 @@ getServerStatsData s = do
|
||||
_qDeletedNew <- readTVar $ qDeletedNew s
|
||||
_qDeletedSecured <- readTVar $ qDeletedSecured s
|
||||
_qSub <- readTVar $ qSub s
|
||||
_qSubNoMsg <- readTVar $ qSubNoMsg s
|
||||
_qSubAuth <- readTVar $ qSubAuth s
|
||||
_qSubDuplicate <- readTVar $ qSubDuplicate s
|
||||
_qSubProhibited <- readTVar $ qSubProhibited s
|
||||
@@ -169,6 +198,12 @@ getServerStatsData s = do
|
||||
_msgSentQuota <- readTVar $ msgSentQuota s
|
||||
_msgSentLarge <- readTVar $ msgSentLarge s
|
||||
_msgRecv <- readTVar $ msgRecv s
|
||||
_msgRecvGet <- readTVar $ msgRecvGet s
|
||||
_msgGet <- readTVar $ msgGet s
|
||||
_msgGetNoMsg <- readTVar $ msgGetNoMsg s
|
||||
_msgGetAuth <- readTVar $ msgGetAuth s
|
||||
_msgGetDuplicate <- readTVar $ msgGetDuplicate s
|
||||
_msgGetProhibited <- readTVar $ msgGetProhibited s
|
||||
_msgExpired <- readTVar $ msgExpired s
|
||||
_activeQueues <- getPeriodStatsData $ activeQueues s
|
||||
_msgSentNtf <- readTVar $ msgSentNtf s
|
||||
@@ -193,6 +228,7 @@ getServerStatsData s = do
|
||||
_qDeletedNew,
|
||||
_qDeletedSecured,
|
||||
_qSub,
|
||||
_qSubNoMsg,
|
||||
_qSubAuth,
|
||||
_qSubDuplicate,
|
||||
_qSubProhibited,
|
||||
@@ -201,6 +237,12 @@ getServerStatsData s = do
|
||||
_msgSentQuota,
|
||||
_msgSentLarge,
|
||||
_msgRecv,
|
||||
_msgRecvGet,
|
||||
_msgGet,
|
||||
_msgGetNoMsg,
|
||||
_msgGetAuth,
|
||||
_msgGetDuplicate,
|
||||
_msgGetProhibited,
|
||||
_msgExpired,
|
||||
_activeQueues,
|
||||
_msgSentNtf,
|
||||
@@ -227,6 +269,7 @@ setServerStats s d = do
|
||||
writeTVar (qDeletedNew s) $! _qDeletedNew d
|
||||
writeTVar (qDeletedSecured s) $! _qDeletedSecured d
|
||||
writeTVar (qSub s) $! _qSub d
|
||||
writeTVar (qSubNoMsg s) $! _qSubNoMsg d
|
||||
writeTVar (qSubAuth s) $! _qSubAuth d
|
||||
writeTVar (qSubDuplicate s) $! _qSubDuplicate d
|
||||
writeTVar (qSubProhibited s) $! _qSubProhibited d
|
||||
@@ -235,6 +278,12 @@ setServerStats s d = do
|
||||
writeTVar (msgSentQuota s) $! _msgSentQuota d
|
||||
writeTVar (msgSentLarge s) $! _msgSentLarge d
|
||||
writeTVar (msgRecv s) $! _msgRecv d
|
||||
writeTVar (msgRecvGet s) $! _msgRecvGet d
|
||||
writeTVar (msgGet s) $! _msgGet d
|
||||
writeTVar (msgGetNoMsg s) $! _msgGetNoMsg d
|
||||
writeTVar (msgGetAuth s) $! _msgGetAuth d
|
||||
writeTVar (msgGetDuplicate s) $! _msgGetDuplicate d
|
||||
writeTVar (msgGetProhibited s) $! _msgGetProhibited d
|
||||
writeTVar (msgExpired s) $! _msgExpired d
|
||||
setPeriodStats (activeQueues s) (_activeQueues d)
|
||||
writeTVar (msgSentNtf s) $! _msgSentNtf d
|
||||
@@ -262,6 +311,7 @@ instance StrEncoding ServerStatsData where
|
||||
"qDeletedSecured=" <> strEncode (_qDeletedSecured d),
|
||||
"qCount=" <> strEncode (_qCount d),
|
||||
"qSub=" <> strEncode (_qSub d),
|
||||
"qSubNoMsg=" <> strEncode (_qSubNoMsg d),
|
||||
"qSubAuth=" <> strEncode (_qSubAuth d),
|
||||
"qSubDuplicate=" <> strEncode (_qSubDuplicate d),
|
||||
"qSubProhibited=" <> strEncode (_qSubProhibited d),
|
||||
@@ -270,6 +320,12 @@ instance StrEncoding ServerStatsData where
|
||||
"msgSentQuota=" <> strEncode (_msgSentQuota d),
|
||||
"msgSentLarge=" <> strEncode (_msgSentLarge d),
|
||||
"msgRecv=" <> strEncode (_msgRecv d),
|
||||
"msgRecvGet=" <> strEncode (_msgRecvGet d),
|
||||
"msgGet=" <> strEncode (_msgGet d),
|
||||
"msgGetNoMsg=" <> strEncode (_msgGetNoMsg d),
|
||||
"msgGetAuth=" <> strEncode (_msgGetAuth d),
|
||||
"msgGetDuplicate=" <> strEncode (_msgGetDuplicate d),
|
||||
"msgGetProhibited=" <> strEncode (_msgGetProhibited d),
|
||||
"msgExpired=" <> strEncode (_msgExpired d),
|
||||
"msgSentNtf=" <> strEncode (_msgSentNtf d),
|
||||
"msgRecvNtf=" <> strEncode (_msgRecvNtf d),
|
||||
@@ -299,6 +355,7 @@ instance StrEncoding ServerStatsData where
|
||||
<|> ((,,) <$> ("qDeletedAll=" *> strP <* A.endOfLine) <*> ("qDeletedNew=" *> strP <* A.endOfLine) <*> ("qDeletedSecured=" *> strP <* A.endOfLine))
|
||||
_qCount <- opt "qCount="
|
||||
_qSub <- opt "qSub="
|
||||
_qSubNoMsg <- opt "qSubNoMsg="
|
||||
_qSubAuth <- opt "qSubAuth="
|
||||
_qSubDuplicate <- opt "qSubDuplicate="
|
||||
_qSubProhibited <- opt "qSubProhibited="
|
||||
@@ -307,6 +364,12 @@ instance StrEncoding ServerStatsData where
|
||||
_msgSentQuota <- opt "msgSentQuota="
|
||||
_msgSentLarge <- opt "msgSentLarge="
|
||||
_msgRecv <- "msgRecv=" *> strP <* A.endOfLine
|
||||
_msgRecvGet <- opt "msgRecvGet="
|
||||
_msgGet <- opt "msgGet="
|
||||
_msgGetNoMsg <- opt "msgGetNoMsg="
|
||||
_msgGetAuth <- opt "msgGetAuth="
|
||||
_msgGetDuplicate <- opt "msgGetDuplicate="
|
||||
_msgGetProhibited <- opt "msgGetProhibited="
|
||||
_msgExpired <- opt "msgExpired="
|
||||
_msgSentNtf <- opt "msgSentNtf="
|
||||
_msgRecvNtf <- opt "msgRecvNtf="
|
||||
@@ -339,6 +402,7 @@ instance StrEncoding ServerStatsData where
|
||||
_qDeletedNew,
|
||||
_qDeletedSecured,
|
||||
_qSub,
|
||||
_qSubNoMsg,
|
||||
_qSubAuth,
|
||||
_qSubDuplicate,
|
||||
_qSubProhibited,
|
||||
@@ -347,6 +411,12 @@ instance StrEncoding ServerStatsData where
|
||||
_msgSentQuota,
|
||||
_msgSentLarge,
|
||||
_msgRecv,
|
||||
_msgRecvGet,
|
||||
_msgGet,
|
||||
_msgGetNoMsg,
|
||||
_msgGetAuth,
|
||||
_msgGetDuplicate,
|
||||
_msgGetProhibited,
|
||||
_msgExpired,
|
||||
_msgSentNtf,
|
||||
_msgRecvNtf,
|
||||
|
||||
@@ -225,23 +225,23 @@ connectionRequestTests =
|
||||
queueV1NoPort #== ("smp://[email protected]/3456-w==#/?v=1-1&dh=" <> url testDhKeyStr <> "&srv=jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion")
|
||||
queueV1NoPort #== ("smp://[email protected],jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion/3456-w==#" <> testDhKeyStr)
|
||||
it "should serialize and parse connection invitations and contact addresses" $ do
|
||||
connectionRequest #==# ("simplex:/invitation#/?v=2-6&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest #== ("https://simplex.chat/invitation#/?v=2-6&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestSK #==# ("simplex:/invitation#/?v=2-6&smp=" <> url queueStrSK <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest1 #==# ("simplex:/invitation#/?v=2-6&smp=" <> url queue1Str <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest2queues #==# ("simplex:/invitation#/?v=2-6&smp=" <> url (queueStr <> ";" <> queueStr) <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestNew #==# ("simplex:/invitation#/?v=2-6&smp=" <> url queueNewStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestNew1 #==# ("simplex:/invitation#/?v=2-6&smp=" <> url queueNew1Str <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest2queuesNew #==# ("simplex:/invitation#/?v=2-6&smp=" <> url (queueNewStr <> ";" <> queueNewStr) <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest #==# ("simplex:/invitation#/?v=2-7&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest #== ("https://simplex.chat/invitation#/?v=2-7&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestSK #==# ("simplex:/invitation#/?v=2-7&smp=" <> url queueStrSK <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest1 #==# ("simplex:/invitation#/?v=2-7&smp=" <> url queue1Str <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest2queues #==# ("simplex:/invitation#/?v=2-7&smp=" <> url (queueStr <> ";" <> queueStr) <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestNew #==# ("simplex:/invitation#/?v=2-7&smp=" <> url queueNewStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestNew1 #==# ("simplex:/invitation#/?v=2-7&smp=" <> url queueNew1Str <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequest2queuesNew #==# ("simplex:/invitation#/?v=2-7&smp=" <> url (queueNewStr <> ";" <> queueNewStr) <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestV1 #== ("https://simplex.chat/invitation#/?v=1&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri)
|
||||
connectionRequestClientDataEmpty #==# ("simplex:/invitation#/?v=2-6&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri <> "&data=" <> url "{}")
|
||||
contactAddress #==# ("simplex:/contact#/?v=2-6&smp=" <> url queueStr)
|
||||
contactAddress #== ("https://simplex.chat/contact#/?v=2-6&smp=" <> url queueStr)
|
||||
contactAddress2queues #==# ("simplex:/contact#/?v=2-6&smp=" <> url (queueStr <> ";" <> queueStr))
|
||||
contactAddressNew #==# ("simplex:/contact#/?v=2-6&smp=" <> url queueNewStr)
|
||||
contactAddress2queuesNew #==# ("simplex:/contact#/?v=2-6&smp=" <> url (queueNewStr <> ";" <> queueNewStr))
|
||||
connectionRequestClientDataEmpty #==# ("simplex:/invitation#/?v=2-7&smp=" <> url queueStr <> "&e2e=" <> testE2ERatchetParamsStrUri <> "&data=" <> url "{}")
|
||||
contactAddress #==# ("simplex:/contact#/?v=2-7&smp=" <> url queueStr)
|
||||
contactAddress #== ("https://simplex.chat/contact#/?v=2-7&smp=" <> url queueStr)
|
||||
contactAddress2queues #==# ("simplex:/contact#/?v=2-7&smp=" <> url (queueStr <> ";" <> queueStr))
|
||||
contactAddressNew #==# ("simplex:/contact#/?v=2-7&smp=" <> url queueNewStr)
|
||||
contactAddress2queuesNew #==# ("simplex:/contact#/?v=2-7&smp=" <> url (queueNewStr <> ";" <> queueNewStr))
|
||||
contactAddressV2 #==# ("simplex:/contact#/?v=2&smp=" <> url queueStr)
|
||||
contactAddressV2 #== ("https://simplex.chat/contact#/?v=1&smp=" <> url queueStr) -- adjusted to v2
|
||||
contactAddressV2 #== ("https://simplex.chat/contact#/?v=1-2&smp=" <> url queueStr) -- adjusted to v2
|
||||
contactAddressV2 #== ("https://simplex.chat/contact#/?v=2-2&smp=" <> url queueStr)
|
||||
contactAddressClientData #==# ("simplex:/contact#/?v=2-6&smp=" <> url queueStr <> "&data=" <> url "{\"type\":\"group_link\", \"group_link_id\":\"abc\"}")
|
||||
contactAddressClientData #==# ("simplex:/contact#/?v=2-7&smp=" <> url queueStr <> "&data=" <> url "{\"type\":\"group_link\", \"group_link_id\":\"abc\"}")
|
||||
|
||||
@@ -244,7 +244,7 @@ inAnyOrder g rs = withFrozenCallStack $ do
|
||||
createConnection :: AgentClient -> UserId -> Bool -> SConnectionMode c -> Maybe CRClientData -> SubscriptionMode -> AE (ConnId, ConnectionRequestUri c)
|
||||
createConnection c userId enableNtfs cMode clientData = A.createConnection c userId enableNtfs cMode clientData (IKNoPQ PQSupportOn)
|
||||
|
||||
joinConnection :: AgentClient -> UserId -> Bool -> ConnectionRequestUri c -> ConnInfo -> SubscriptionMode -> AE ConnId
|
||||
joinConnection :: AgentClient -> UserId -> Bool -> ConnectionRequestUri c -> ConnInfo -> SubscriptionMode -> AE (ConnId, SndQueueSecured)
|
||||
joinConnection c userId enableNtfs cReq connInfo = A.joinConnection c userId Nothing enableNtfs cReq connInfo PQSupportOn
|
||||
|
||||
sendMessage :: AgentClient -> ConnId -> SMP.MsgFlags -> MsgBody -> AE AgentMsgId
|
||||
@@ -269,13 +269,13 @@ functionalAPITests t = do
|
||||
describe "two way concurrently (50)" $ testMatrix2Stress t $ runAgentClientStressTestConc 25
|
||||
xdescribe "two way concurrently (1000)" $ testMatrix2Stress t $ runAgentClientStressTestConc 500
|
||||
describe "Establishing duplex connection, different PQ settings" $ do
|
||||
testPQMatrix2 t $ runAgentClientTestPQ True
|
||||
testPQMatrix2 t $ runAgentClientTestPQ False True
|
||||
describe "Establishing duplex connection v2, different Ratchet versions" $
|
||||
testRatchetMatrix2 t runAgentClientTest
|
||||
describe "Establish duplex connection via contact address" $
|
||||
testMatrix2 t runAgentClientContactTest
|
||||
describe "Establish duplex connection via contact address, different PQ settings" $ do
|
||||
testPQMatrix2NoInv t $ runAgentClientContactTestPQ True PQSupportOn
|
||||
testPQMatrix2NoInv t $ runAgentClientContactTestPQ False True PQSupportOn
|
||||
describe "Establish duplex connection via contact address v2, different Ratchet versions" $
|
||||
testRatchetMatrix2 t runAgentClientContactTest
|
||||
describe "Establish duplex connection via contact address, different PQ settings" $ do
|
||||
@@ -410,29 +410,30 @@ functionalAPITests t = do
|
||||
let v4 = prevVersion basicAuthSMPVersion
|
||||
forM_ (nub [prevVersion authCmdsSMPVersion, authCmdsSMPVersion, currentServerSMPRelayVersion]) $ \v -> do
|
||||
let baseId = if v >= sndAuthKeySMPVersion then 1 else 3
|
||||
sqSecured = if v >= sndAuthKeySMPVersion then True else False
|
||||
describe ("v" <> show v <> ": with server auth") $ do
|
||||
-- allow NEW | server auth, v | clnt1 auth, v | clnt2 auth, v | 2 - success, 1 - JOIN fail, 0 - NEW fail
|
||||
it "success " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Just "abcd", v) baseId `shouldReturn` 2
|
||||
it "disabled " $ testBasicAuth t False (Just "abcd", v) (Just "abcd", v) (Just "abcd", v) baseId `shouldReturn` 0
|
||||
it "NEW fail, no auth " $ testBasicAuth t True (Just "abcd", v) (Nothing, v) (Just "abcd", v) baseId `shouldReturn` 0
|
||||
it "NEW fail, bad auth " $ testBasicAuth t True (Just "abcd", v) (Just "wrong", v) (Just "abcd", v) baseId `shouldReturn` 0
|
||||
it "NEW fail, version " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v4) (Just "abcd", v) baseId `shouldReturn` 0
|
||||
it "JOIN fail, no auth " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Nothing, v) baseId `shouldReturn` 1
|
||||
it "JOIN fail, bad auth " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Just "wrong", v) baseId `shouldReturn` 1
|
||||
it "JOIN fail, version " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Just "abcd", v4) baseId `shouldReturn` 1
|
||||
it "success " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Just "abcd", v) sqSecured baseId `shouldReturn` 2
|
||||
it "disabled " $ testBasicAuth t False (Just "abcd", v) (Just "abcd", v) (Just "abcd", v) sqSecured baseId `shouldReturn` 0
|
||||
it "NEW fail, no auth " $ testBasicAuth t True (Just "abcd", v) (Nothing, v) (Just "abcd", v) sqSecured baseId `shouldReturn` 0
|
||||
it "NEW fail, bad auth " $ testBasicAuth t True (Just "abcd", v) (Just "wrong", v) (Just "abcd", v) sqSecured baseId `shouldReturn` 0
|
||||
it "NEW fail, version " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v4) (Just "abcd", v) sqSecured baseId `shouldReturn` 0
|
||||
it "JOIN fail, no auth " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Nothing, v) sqSecured baseId `shouldReturn` 1
|
||||
it "JOIN fail, bad auth " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Just "wrong", v) sqSecured baseId `shouldReturn` 1
|
||||
it "JOIN fail, version " $ testBasicAuth t True (Just "abcd", v) (Just "abcd", v) (Just "abcd", v4) sqSecured baseId `shouldReturn` 1
|
||||
describe ("v" <> show v <> ": no server auth") $ do
|
||||
it "success " $ testBasicAuth t True (Nothing, v) (Nothing, v) (Nothing, v) baseId `shouldReturn` 2
|
||||
it "srv disabled" $ testBasicAuth t False (Nothing, v) (Nothing, v) (Nothing, v) baseId `shouldReturn` 0
|
||||
it "version srv " $ testBasicAuth t True (Nothing, v4) (Nothing, v) (Nothing, v) 3 `shouldReturn` 2
|
||||
it "version fst " $ testBasicAuth t True (Nothing, v) (Nothing, v4) (Nothing, v) baseId `shouldReturn` 2
|
||||
it "version snd " $ testBasicAuth t True (Nothing, v) (Nothing, v) (Nothing, v4) 3 `shouldReturn` 2
|
||||
it "version both" $ testBasicAuth t True (Nothing, v) (Nothing, v4) (Nothing, v4) 3 `shouldReturn` 2
|
||||
it "version all " $ testBasicAuth t True (Nothing, v4) (Nothing, v4) (Nothing, v4) 3 `shouldReturn` 2
|
||||
it "auth fst " $ testBasicAuth t True (Nothing, v) (Just "abcd", v) (Nothing, v) baseId `shouldReturn` 2
|
||||
it "auth fst 2 " $ testBasicAuth t True (Nothing, v4) (Just "abcd", v) (Nothing, v) 3 `shouldReturn` 2
|
||||
it "auth snd " $ testBasicAuth t True (Nothing, v) (Nothing, v) (Just "abcd", v) baseId `shouldReturn` 2
|
||||
it "auth both " $ testBasicAuth t True (Nothing, v) (Just "abcd", v) (Just "abcd", v) baseId `shouldReturn` 2
|
||||
it "auth, disabled" $ testBasicAuth t False (Nothing, v) (Just "abcd", v) (Just "abcd", v) baseId `shouldReturn` 0
|
||||
it "success " $ testBasicAuth t True (Nothing, v) (Nothing, v) (Nothing, v) sqSecured baseId `shouldReturn` 2
|
||||
it "srv disabled" $ testBasicAuth t False (Nothing, v) (Nothing, v) (Nothing, v) sqSecured baseId `shouldReturn` 0
|
||||
it "version srv " $ testBasicAuth t True (Nothing, v4) (Nothing, v) (Nothing, v) False 3 `shouldReturn` 2
|
||||
it "version fst " $ testBasicAuth t True (Nothing, v) (Nothing, v4) (Nothing, v) False baseId `shouldReturn` 2
|
||||
it "version snd " $ testBasicAuth t True (Nothing, v) (Nothing, v) (Nothing, v4) sqSecured 3 `shouldReturn` 2
|
||||
it "version both" $ testBasicAuth t True (Nothing, v) (Nothing, v4) (Nothing, v4) False 3 `shouldReturn` 2
|
||||
it "version all " $ testBasicAuth t True (Nothing, v4) (Nothing, v4) (Nothing, v4) False 3 `shouldReturn` 2
|
||||
it "auth fst " $ testBasicAuth t True (Nothing, v) (Just "abcd", v) (Nothing, v) sqSecured baseId `shouldReturn` 2
|
||||
it "auth fst 2 " $ testBasicAuth t True (Nothing, v4) (Just "abcd", v) (Nothing, v) False 3 `shouldReturn` 2
|
||||
it "auth snd " $ testBasicAuth t True (Nothing, v) (Nothing, v) (Just "abcd", v) sqSecured baseId `shouldReturn` 2
|
||||
it "auth both " $ testBasicAuth t True (Nothing, v) (Just "abcd", v) (Just "abcd", v) sqSecured baseId `shouldReturn` 2
|
||||
it "auth, disabled" $ testBasicAuth t False (Nothing, v) (Just "abcd", v) (Just "abcd", v) sqSecured baseId `shouldReturn` 0
|
||||
describe "SMP server test via agent API" $ do
|
||||
it "should pass without basic auth" $ testSMPServerConnectionTest t Nothing (noAuthSrv testSMPServer2) `shouldReturn` Nothing
|
||||
let srv1 = testSMPServer2 {keyHash = "1234"}
|
||||
@@ -460,8 +461,8 @@ functionalAPITests t = do
|
||||
it "server should respond with queue and subscription information" $
|
||||
withSmpServer t testServerQueueInfo
|
||||
|
||||
testBasicAuth :: ATransport -> Bool -> (Maybe BasicAuth, VersionSMP) -> (Maybe BasicAuth, VersionSMP) -> (Maybe BasicAuth, VersionSMP) -> AgentMsgId -> IO Int
|
||||
testBasicAuth t allowNewQueues srv@(srvAuth, srvVersion) clnt1 clnt2 baseId = do
|
||||
testBasicAuth :: ATransport -> Bool -> (Maybe BasicAuth, VersionSMP) -> (Maybe BasicAuth, VersionSMP) -> (Maybe BasicAuth, VersionSMP) -> SndQueueSecured -> AgentMsgId -> IO Int
|
||||
testBasicAuth t allowNewQueues srv@(srvAuth, srvVersion) clnt1 clnt2 sqSecured baseId = do
|
||||
let testCfg = cfg {allowNewQueues, newQueueBasicAuth = srvAuth, smpServerVRange = V.mkVersionRange batchCmdsSMPVersion srvVersion}
|
||||
canCreate1 = canCreateQueue allowNewQueues srv clnt1
|
||||
canCreate2 = canCreateQueue allowNewQueues srv clnt2
|
||||
@@ -469,7 +470,7 @@ testBasicAuth t allowNewQueues srv@(srvAuth, srvVersion) clnt1 clnt2 baseId = do
|
||||
| canCreate1 && canCreate2 = 2
|
||||
| canCreate1 = 1
|
||||
| otherwise = 0
|
||||
created <- withSmpServerConfigOn t testCfg testPort $ \_ -> testCreateQueueAuth srvVersion clnt1 clnt2 baseId
|
||||
created <- withSmpServerConfigOn t testCfg testPort $ \_ -> testCreateQueueAuth srvVersion clnt1 clnt2 sqSecured baseId
|
||||
created `shouldBe` expected
|
||||
pure created
|
||||
|
||||
@@ -478,43 +479,43 @@ canCreateQueue allowNew (srvAuth, srvVersion) (clntAuth, clntVersion) =
|
||||
let v = basicAuthSMPVersion
|
||||
in allowNew && (isNothing srvAuth || (srvVersion >= v && clntVersion >= v && srvAuth == clntAuth))
|
||||
|
||||
testMatrix2 :: HasCallStack => ATransport -> (PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testMatrix2 :: HasCallStack => ATransport -> (PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testMatrix2 t runTest = do
|
||||
it "current, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentCfg agentCfg (initAgentServersProxy SPMAlways SPFProhibit) 1 $ runTest PQSupportOn True
|
||||
it "v8, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentProxyCfgV8 agentProxyCfgV8 (initAgentServersProxy SPMAlways SPFProhibit) 3 $ runTest PQSupportOn True
|
||||
it "current" $ withSmpServer t $ runTestCfg2 agentCfg agentCfg 1 $ runTest PQSupportOn False
|
||||
it "prev" $ withSmpServer t $ runTestCfg2 agentCfgVPrev agentCfgVPrev 3 $ runTest PQSupportOff False
|
||||
it "prev to current" $ withSmpServer t $ runTestCfg2 agentCfgVPrev agentCfg 3 $ runTest PQSupportOff False
|
||||
it "current to prev" $ withSmpServer t $ runTestCfg2 agentCfg agentCfgVPrev 3 $ runTest PQSupportOff False
|
||||
it "current, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentCfg agentCfg (initAgentServersProxy SPMAlways SPFProhibit) 1 $ runTest PQSupportOn True True
|
||||
it "v8, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentProxyCfgV8 agentProxyCfgV8 (initAgentServersProxy SPMAlways SPFProhibit) 3 $ runTest PQSupportOn False True
|
||||
it "current" $ withSmpServer t $ runTestCfg2 agentCfg agentCfg 1 $ runTest PQSupportOn True False
|
||||
it "prev" $ withSmpServer t $ runTestCfg2 agentCfgVPrev agentCfgVPrev 3 $ runTest PQSupportOff False False
|
||||
it "prev to current" $ withSmpServer t $ runTestCfg2 agentCfgVPrev agentCfg 3 $ runTest PQSupportOff False False
|
||||
it "current to prev" $ withSmpServer t $ runTestCfg2 agentCfg agentCfgVPrev 3 $ runTest PQSupportOff False False
|
||||
|
||||
testMatrix2Stress :: HasCallStack => ATransport -> (PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testMatrix2Stress :: HasCallStack => ATransport -> (PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testMatrix2Stress t runTest = do
|
||||
it "current, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 aCfg aCfg (initAgentServersProxy SPMAlways SPFProhibit) 1 $ runTest PQSupportOn True
|
||||
it "v8, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 aProxyCfgV8 aProxyCfgV8 (initAgentServersProxy SPMAlways SPFProhibit) 3 $ runTest PQSupportOn True
|
||||
it "current" $ withSmpServer t $ runTestCfg2 aCfg aCfg 1 $ runTest PQSupportOn False
|
||||
it "prev" $ withSmpServer t $ runTestCfg2 aCfgVPrev aCfgVPrev 3 $ runTest PQSupportOff False
|
||||
it "prev to current" $ withSmpServer t $ runTestCfg2 aCfgVPrev aCfg 3 $ runTest PQSupportOff False
|
||||
it "current to prev" $ withSmpServer t $ runTestCfg2 aCfg aCfgVPrev 3 $ runTest PQSupportOff False
|
||||
it "current, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 aCfg aCfg (initAgentServersProxy SPMAlways SPFProhibit) 1 $ runTest PQSupportOn True True
|
||||
it "v8, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 aProxyCfgV8 aProxyCfgV8 (initAgentServersProxy SPMAlways SPFProhibit) 3 $ runTest PQSupportOn False True
|
||||
it "current" $ withSmpServer t $ runTestCfg2 aCfg aCfg 1 $ runTest PQSupportOn True False
|
||||
it "prev" $ withSmpServer t $ runTestCfg2 aCfgVPrev aCfgVPrev 3 $ runTest PQSupportOff False False
|
||||
it "prev to current" $ withSmpServer t $ runTestCfg2 aCfgVPrev aCfg 3 $ runTest PQSupportOff False False
|
||||
it "current to prev" $ withSmpServer t $ runTestCfg2 aCfg aCfgVPrev 3 $ runTest PQSupportOff False False
|
||||
where
|
||||
aCfg = agentCfg {messageRetryInterval = fastMessageRetryInterval}
|
||||
aProxyCfgV8 = agentProxyCfgV8 {messageRetryInterval = fastMessageRetryInterval}
|
||||
aCfgVPrev = agentCfgVPrev {messageRetryInterval = fastMessageRetryInterval}
|
||||
|
||||
testBasicMatrix2 :: HasCallStack => ATransport -> (AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testBasicMatrix2 :: HasCallStack => ATransport -> (SndQueueSecured -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testBasicMatrix2 t runTest = do
|
||||
it "current" $ withSmpServer t $ runTestCfg2 agentCfg agentCfg 1 $ runTest
|
||||
it "prev" $ withSmpServer t $ runTestCfg2 agentCfgVPrevPQ agentCfgVPrevPQ 3 $ runTest
|
||||
it "prev to current" $ withSmpServer t $ runTestCfg2 agentCfgVPrevPQ agentCfg 3 $ runTest
|
||||
it "current to prev" $ withSmpServer t $ runTestCfg2 agentCfg agentCfgVPrevPQ 3 $ runTest
|
||||
it "current" $ withSmpServer t $ runTestCfg2 agentCfg agentCfg 1 $ runTest True
|
||||
it "prev" $ withSmpServer t $ runTestCfg2 agentCfgVPrevPQ agentCfgVPrevPQ 3 $ runTest False
|
||||
it "prev to current" $ withSmpServer t $ runTestCfg2 agentCfgVPrevPQ agentCfg 3 $ runTest False
|
||||
it "current to prev" $ withSmpServer t $ runTestCfg2 agentCfg agentCfgVPrevPQ 3 $ runTest False
|
||||
|
||||
testRatchetMatrix2 :: HasCallStack => ATransport -> (PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testRatchetMatrix2 :: HasCallStack => ATransport -> (PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()) -> Spec
|
||||
testRatchetMatrix2 t runTest = do
|
||||
it "current, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentCfg agentCfg (initAgentServersProxy SPMAlways SPFProhibit) 1 $ runTest PQSupportOn True
|
||||
it "v8, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentProxyCfgV8 agentProxyCfgV8 (initAgentServersProxy SPMAlways SPFProhibit) 3 $ runTest PQSupportOn True
|
||||
it "ratchet current" $ withSmpServer t $ runTestCfg2 agentCfg agentCfg 1 $ runTest PQSupportOn False
|
||||
it "ratchet prev" $ withSmpServer t $ runTestCfg2 agentCfgRatchetVPrev agentCfgRatchetVPrev 1 $ runTest PQSupportOff False
|
||||
it "ratchets prev to current" $ withSmpServer t $ runTestCfg2 agentCfgRatchetVPrev agentCfg 1 $ runTest PQSupportOff False
|
||||
it "ratchets current to prev" $ withSmpServer t $ runTestCfg2 agentCfg agentCfgRatchetVPrev 1 $ runTest PQSupportOff False
|
||||
it "current, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentCfg agentCfg (initAgentServersProxy SPMAlways SPFProhibit) 1 $ runTest PQSupportOn True True
|
||||
it "v8, via proxy" $ withSmpServerProxy t $ runTestCfgServers2 agentProxyCfgV8 agentProxyCfgV8 (initAgentServersProxy SPMAlways SPFProhibit) 3 $ runTest PQSupportOn False True
|
||||
it "ratchet current" $ withSmpServer t $ runTestCfg2 agentCfg agentCfg 1 $ runTest PQSupportOn True False
|
||||
it "ratchet prev" $ withSmpServer t $ runTestCfg2 agentCfgRatchetVPrev agentCfgRatchetVPrev 1 $ runTest PQSupportOff True False
|
||||
it "ratchets prev to current" $ withSmpServer t $ runTestCfg2 agentCfgRatchetVPrev agentCfg 1 $ runTest PQSupportOff True False
|
||||
it "ratchets current to prev" $ withSmpServer t $ runTestCfg2 agentCfg agentCfgRatchetVPrev 1 $ runTest PQSupportOff True False
|
||||
|
||||
testServerMatrix2 :: HasCallStack => ATransport -> (InitialAgentServers -> IO ()) -> Spec
|
||||
testServerMatrix2 t runTest = do
|
||||
@@ -589,15 +590,16 @@ withAgentClients3 runTest =
|
||||
withAgent 3 agentCfg initAgentServers testDB3 $ \c ->
|
||||
runTest a b c
|
||||
|
||||
runAgentClientTest :: HasCallStack => PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientTest pqSupport viaProxy alice bob baseId =
|
||||
runAgentClientTestPQ viaProxy (alice, IKNoPQ pqSupport) (bob, pqSupport) baseId
|
||||
runAgentClientTest :: HasCallStack => PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientTest pqSupport sqSecured viaProxy alice bob baseId =
|
||||
runAgentClientTestPQ sqSecured viaProxy (alice, IKNoPQ pqSupport) (bob, pqSupport) baseId
|
||||
|
||||
runAgentClientTestPQ :: HasCallStack => Bool -> (AgentClient, InitialKeys) -> (AgentClient, PQSupport) -> AgentMsgId -> IO ()
|
||||
runAgentClientTestPQ viaProxy (alice, aPQ) (bob, bPQ) baseId =
|
||||
runAgentClientTestPQ :: HasCallStack => SndQueueSecured -> Bool -> (AgentClient, InitialKeys) -> (AgentClient, PQSupport) -> AgentMsgId -> IO ()
|
||||
runAgentClientTestPQ sqSecured viaProxy (alice, aPQ) (bob, bPQ) baseId =
|
||||
runRight_ $ do
|
||||
(bobId, qInfo) <- A.createConnection alice 1 True SCMInvitation Nothing aPQ SMSubscribe
|
||||
aliceId <- A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" bPQ SMSubscribe
|
||||
(aliceId, sqSecured') <- A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" bPQ SMSubscribe
|
||||
liftIO $ sqSecured' `shouldBe` sqSecured
|
||||
("", _, A.CONF confId pqSup' _ "bob's connInfo") <- get alice
|
||||
liftIO $ pqSup' `shouldBe` CR.connPQEncryption aPQ
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
@@ -634,10 +636,10 @@ runAgentClientTestPQ viaProxy (alice, aPQ) (bob, bPQ) baseId =
|
||||
pqConnectionMode :: InitialKeys -> PQSupport -> Bool
|
||||
pqConnectionMode pqMode1 pqMode2 = supportPQ (CR.connPQEncryption pqMode1) && supportPQ pqMode2
|
||||
|
||||
runAgentClientStressTestOneWay :: HasCallStack => Int64 -> PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientStressTestOneWay n pqSupport viaProxy alice bob baseId = runRight_ $ do
|
||||
runAgentClientStressTestOneWay :: HasCallStack => Int64 -> PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientStressTestOneWay n pqSupport sqSecured viaProxy alice bob baseId = runRight_ $ do
|
||||
let pqEnc = PQEncryption $ supportPQ pqSupport
|
||||
(aliceId, bobId) <- makeConnection_ pqSupport alice bob
|
||||
(aliceId, bobId) <- makeConnection_ pqSupport sqSecured alice bob
|
||||
let proxySrv = if viaProxy then Just testSMPServer else Nothing
|
||||
message i = "message " <> bshow i
|
||||
concurrently_
|
||||
@@ -666,10 +668,10 @@ runAgentClientStressTestOneWay n pqSupport viaProxy alice bob baseId = runRight_
|
||||
where
|
||||
msgId = subtract baseId . fst
|
||||
|
||||
runAgentClientStressTestConc :: HasCallStack => Int64 -> PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientStressTestConc n pqSupport viaProxy alice bob baseId = runRight_ $ do
|
||||
runAgentClientStressTestConc :: HasCallStack => Int64 -> PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientStressTestConc n pqSupport sqSecured viaProxy alice bob baseId = runRight_ $ do
|
||||
let pqEnc = PQEncryption $ supportPQ pqSupport
|
||||
(aliceId, bobId) <- makeConnection_ pqSupport alice bob
|
||||
(aliceId, bobId) <- makeConnection_ pqSupport sqSecured alice bob
|
||||
let proxySrv = if viaProxy then Just testSMPServer else Nothing
|
||||
message i = "message " <> bshow i
|
||||
loop a bId mIdVar i = do
|
||||
@@ -703,7 +705,7 @@ testEnablePQEncryption :: HasCallStack => IO ()
|
||||
testEnablePQEncryption =
|
||||
withAgentClients2 $ \ca cb -> runRight_ $ do
|
||||
g <- liftIO C.newRandom
|
||||
(aId, bId) <- makeConnection_ PQSupportOff ca cb
|
||||
(aId, bId) <- makeConnection_ PQSupportOff True ca cb
|
||||
let a = (ca, aId)
|
||||
b = (cb, bId)
|
||||
(a, 2, "msg 1") \#>\ b
|
||||
@@ -789,20 +791,23 @@ testAgentClient3 =
|
||||
get c =##> \case ("", connId, Msg "c5") -> connId == aIdForC; _ -> False
|
||||
ackMessage c aIdForC 3 Nothing
|
||||
|
||||
runAgentClientContactTest :: HasCallStack => PQSupport -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientContactTest pqSupport viaProxy alice bob baseId =
|
||||
runAgentClientContactTestPQ viaProxy pqSupport (alice, IKNoPQ pqSupport) (bob, pqSupport) baseId
|
||||
runAgentClientContactTest :: HasCallStack => PQSupport -> SndQueueSecured -> Bool -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
runAgentClientContactTest pqSupport sqSecured viaProxy alice bob baseId =
|
||||
runAgentClientContactTestPQ sqSecured viaProxy pqSupport (alice, IKNoPQ pqSupport) (bob, pqSupport) baseId
|
||||
|
||||
runAgentClientContactTestPQ :: HasCallStack => Bool -> PQSupport -> (AgentClient, InitialKeys) -> (AgentClient, PQSupport) -> AgentMsgId -> IO ()
|
||||
runAgentClientContactTestPQ viaProxy reqPQSupport (alice, aPQ) (bob, bPQ) baseId =
|
||||
runAgentClientContactTestPQ :: HasCallStack => SndQueueSecured -> Bool -> PQSupport -> (AgentClient, InitialKeys) -> (AgentClient, PQSupport) -> AgentMsgId -> IO ()
|
||||
runAgentClientContactTestPQ sqSecured viaProxy reqPQSupport (alice, aPQ) (bob, bPQ) baseId =
|
||||
runRight_ $ do
|
||||
(_, qInfo) <- A.createConnection alice 1 True SCMContact Nothing aPQ SMSubscribe
|
||||
aliceId <- A.prepareConnectionToJoin bob 1 True qInfo bPQ
|
||||
aliceId' <- A.joinConnection bob 1 (Just aliceId) True qInfo "bob's connInfo" bPQ SMSubscribe
|
||||
liftIO $ aliceId' `shouldBe` aliceId
|
||||
(aliceId', sqSecuredJoin) <- A.joinConnection bob 1 (Just aliceId) True qInfo "bob's connInfo" bPQ SMSubscribe
|
||||
liftIO $ do
|
||||
aliceId' `shouldBe` aliceId
|
||||
sqSecuredJoin `shouldBe` False -- joining via contact address connection
|
||||
("", _, A.REQ invId pqSup' _ "bob's connInfo") <- get alice
|
||||
liftIO $ pqSup' `shouldBe` reqPQSupport
|
||||
bobId <- acceptContact alice True invId "alice's connInfo" (CR.connPQEncryption aPQ) SMSubscribe
|
||||
(bobId, sqSecured') <- acceptContact alice True invId "alice's connInfo" (CR.connPQEncryption aPQ) SMSubscribe
|
||||
liftIO $ sqSecured' `shouldBe` sqSecured
|
||||
("", _, A.CONF confId pqSup'' _ "alice's connInfo") <- get bob
|
||||
liftIO $ pqSup'' `shouldBe` bPQ
|
||||
allowConnection bob aliceId confId "bob's connInfo"
|
||||
@@ -847,11 +852,14 @@ runAgentClientContactTestPQ3 viaProxy (alice, aPQ) (bob, bPQ) (tom, tPQ) baseId
|
||||
msgId = subtract baseId . fst
|
||||
connectViaContact b pq qInfo = do
|
||||
aId <- A.prepareConnectionToJoin b 1 True qInfo pq
|
||||
aId' <- A.joinConnection b 1 (Just aId) True qInfo "bob's connInfo" pq SMSubscribe
|
||||
liftIO $ aId' `shouldBe` aId
|
||||
(aId', sqSecuredJoin) <- A.joinConnection b 1 (Just aId) True qInfo "bob's connInfo" pq SMSubscribe
|
||||
liftIO $ do
|
||||
aId' `shouldBe` aId
|
||||
sqSecuredJoin `shouldBe` False -- joining via contact address connection
|
||||
("", _, A.REQ invId pqSup' _ "bob's connInfo") <- get alice
|
||||
liftIO $ pqSup' `shouldBe` PQSupportOn
|
||||
bId <- acceptContact alice True invId "alice's connInfo" (CR.connPQEncryption aPQ) SMSubscribe
|
||||
(bId, sqSecuredAccept) <- acceptContact alice True invId "alice's connInfo" (CR.connPQEncryption aPQ) SMSubscribe
|
||||
liftIO $ sqSecuredAccept `shouldBe` False -- agent cfg is v8
|
||||
("", _, A.CONF confId pqSup'' _ "alice's connInfo") <- get b
|
||||
liftIO $ pqSup'' `shouldBe` pq
|
||||
allowConnection b aId confId "bob's connInfo"
|
||||
@@ -891,8 +899,10 @@ testRejectContactRequest =
|
||||
withAgentClients2 $ \alice bob -> runRight_ $ do
|
||||
(addrConnId, qInfo) <- A.createConnection alice 1 True SCMContact Nothing IKPQOn SMSubscribe
|
||||
aliceId <- A.prepareConnectionToJoin bob 1 True qInfo PQSupportOn
|
||||
aliceId' <- A.joinConnection bob 1 (Just aliceId) True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
liftIO $ aliceId' `shouldBe` aliceId
|
||||
(aliceId', sqSecured) <- A.joinConnection bob 1 (Just aliceId) True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
liftIO $ do
|
||||
aliceId' `shouldBe` aliceId
|
||||
sqSecured `shouldBe` False -- joining via contact address connection
|
||||
("", _, A.REQ invId PQSupportOn _ "bob's connInfo") <- get alice
|
||||
liftIO $ runExceptT (rejectContact alice "abcd" invId) `shouldReturn` Left (CONN NOT_FOUND)
|
||||
rejectContact alice addrConnId invId
|
||||
@@ -904,15 +914,34 @@ testAsyncInitiatingOffline =
|
||||
alice <- liftIO $ getSMPAgentClient' 1 agentCfg initAgentServers testDB
|
||||
(bobId, cReq) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
liftIO $ disposeAgentClient alice
|
||||
aliceId <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
|
||||
-- send messages
|
||||
msgId1 <- A.sendMessage bob aliceId PQEncOn SMP.noMsgFlags "can send 1"
|
||||
liftIO $ msgId1 `shouldBe` (2, PQEncOff)
|
||||
get bob ##> ("", aliceId, SENT 2)
|
||||
msgId2 <- A.sendMessage bob aliceId PQEncOn SMP.noMsgFlags "can send 2"
|
||||
liftIO $ msgId2 `shouldBe` (3, PQEncOff)
|
||||
get bob ##> ("", aliceId, SENT 3)
|
||||
|
||||
alice' <- liftIO $ getSMPAgentClient' 3 agentCfg initAgentServers testDB
|
||||
subscribeConnection alice' bobId
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice'
|
||||
-- receive messages
|
||||
get alice' =##> \case ("", c, Msg' mId pq "can send 1") -> c == bobId && mId == 1 && pq == PQEncOff; _ -> False
|
||||
ackMessage alice' bobId 1 Nothing
|
||||
get alice' =##> \case ("", c, Msg' mId pq "can send 2") -> c == bobId && mId == 2 && pq == PQEncOff; _ -> False
|
||||
ackMessage alice' bobId 2 Nothing
|
||||
-- for alice msg id 3 is sent confirmation, then they're matched with bob at msg id 4
|
||||
|
||||
-- allow connection
|
||||
allowConnection alice' bobId confId "alice's connInfo"
|
||||
get alice' ##> ("", bobId, CON)
|
||||
get bob ##> ("", aliceId, INFO "alice's connInfo")
|
||||
get bob ##> ("", aliceId, CON)
|
||||
exchangeGreetings alice' bobId bob aliceId
|
||||
exchangeGreetingsMsgId 4 alice' bobId bob aliceId
|
||||
liftIO $ disposeAgentClient alice'
|
||||
|
||||
testAsyncJoiningOfflineBeforeActivation :: HasCallStack => IO ()
|
||||
@@ -920,7 +949,8 @@ testAsyncJoiningOfflineBeforeActivation =
|
||||
withAgent 1 agentCfg initAgentServers testDB $ \alice -> runRight_ $ do
|
||||
bob <- liftIO $ getSMPAgentClient' 2 agentCfg initAgentServers testDB2
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
liftIO $ disposeAgentClient bob
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
@@ -939,7 +969,8 @@ testAsyncBothOffline = do
|
||||
runRight_ $ do
|
||||
(bobId, cReq) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
liftIO $ disposeAgentClient alice
|
||||
aliceId <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
liftIO $ disposeAgentClient bob
|
||||
alice' <- liftIO $ getSMPAgentClient' 3 agentCfg initAgentServers testDB
|
||||
subscribeConnection alice' bobId
|
||||
@@ -970,7 +1001,8 @@ testAsyncServerOffline t = withAgentClients2 $ \alice bob -> do
|
||||
liftIO $ do
|
||||
srv1 `shouldBe` testSMPServer
|
||||
conns1 `shouldBe` [bobId]
|
||||
aliceId <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
get alice ##> ("", bobId, CON)
|
||||
@@ -988,7 +1020,8 @@ testAllowConnectionClientRestart t = do
|
||||
withSmpServerConfigOn t cfg {storeLogFile = Just testStoreLogFile2} testPort2 $ \_ -> do
|
||||
runRight $ do
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
pure (aliceId, bobId, confId)
|
||||
|
||||
@@ -1024,7 +1057,7 @@ testIncreaseConnAgentVersion t = do
|
||||
bob <- getSMPAgentClient' 2 agentCfg {smpAgentVRange = mkVersionRange 1 2} initAgentServers testDB2
|
||||
withSmpServerStoreMsgLogOn t testPort $ \_ -> do
|
||||
(aliceId, bobId) <- runRight $ do
|
||||
(aliceId, bobId) <- makeConnection_ PQSupportOff alice bob
|
||||
(aliceId, bobId) <- makeConnection_ PQSupportOff False alice bob
|
||||
exchangeGreetingsMsgId_ PQEncOff 2 alice bobId bob aliceId
|
||||
checkVersion alice bobId 2
|
||||
checkVersion bob aliceId 2
|
||||
@@ -1089,7 +1122,7 @@ testIncreaseConnAgentVersionMaxCompatible t = do
|
||||
bob <- getSMPAgentClient' 2 agentCfg {smpAgentVRange = mkVersionRange 1 2} initAgentServers testDB2
|
||||
withSmpServerStoreMsgLogOn t testPort $ \_ -> do
|
||||
(aliceId, bobId) <- runRight $ do
|
||||
(aliceId, bobId) <- makeConnection_ PQSupportOff alice bob
|
||||
(aliceId, bobId) <- makeConnection_ PQSupportOff False alice bob
|
||||
exchangeGreetingsMsgId_ PQEncOff 2 alice bobId bob aliceId
|
||||
checkVersion alice bobId 2
|
||||
checkVersion bob aliceId 2
|
||||
@@ -1119,7 +1152,7 @@ testIncreaseConnAgentVersionStartDifferentVersion t = do
|
||||
bob <- getSMPAgentClient' 2 agentCfg {smpAgentVRange = mkVersionRange 1 3} initAgentServers testDB2
|
||||
withSmpServerStoreMsgLogOn t testPort $ \_ -> do
|
||||
(aliceId, bobId) <- runRight $ do
|
||||
(aliceId, bobId) <- makeConnection_ PQSupportOff alice bob
|
||||
(aliceId, bobId) <- makeConnection_ PQSupportOff False alice bob
|
||||
exchangeGreetingsMsgId_ PQEncOff 2 alice bobId bob aliceId
|
||||
checkVersion alice bobId 2
|
||||
checkVersion bob aliceId 2
|
||||
@@ -1620,7 +1653,8 @@ testRatchetSyncSimultaneous t = do
|
||||
testOnlyCreatePullSlowHandshake :: IO ()
|
||||
testOnlyCreatePullSlowHandshake = withAgentClientsCfg2 agentProxyCfgV8 agentProxyCfgV8 $ \alice bob -> runRight_ $ do
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMOnlyCreate
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMOnlyCreate
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMOnlyCreate
|
||||
liftIO $ sqSecured `shouldBe` False
|
||||
Just ("", _, CONF confId _ "bob's connInfo") <- getMsg alice bobId $ timeout 5_000000 $ get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
liftIO $ threadDelay 1_000000
|
||||
@@ -1654,7 +1688,8 @@ getMsg c cId action = do
|
||||
testOnlyCreatePull :: IO ()
|
||||
testOnlyCreatePull = withAgentClients2 $ \alice bob -> runRight_ $ do
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMOnlyCreate
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMOnlyCreate
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMOnlyCreate
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
Just ("", _, CONF confId _ "bob's connInfo") <- getMsg alice bobId $ timeout 5_000000 $ get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
liftIO $ threadDelay 1_000000
|
||||
@@ -1676,20 +1711,22 @@ testOnlyCreatePull = withAgentClients2 $ \alice bob -> runRight_ $ do
|
||||
ackMessage alice bobId 3 Nothing
|
||||
|
||||
makeConnection :: AgentClient -> AgentClient -> ExceptT AgentErrorType IO (ConnId, ConnId)
|
||||
makeConnection = makeConnection_ PQSupportOn
|
||||
makeConnection = makeConnection_ PQSupportOn True
|
||||
|
||||
makeConnection_ :: PQSupport -> AgentClient -> AgentClient -> ExceptT AgentErrorType IO (ConnId, ConnId)
|
||||
makeConnection_ pqEnc alice bob = makeConnectionForUsers_ pqEnc alice 1 bob 1
|
||||
makeConnection_ :: PQSupport -> SndQueueSecured -> AgentClient -> AgentClient -> ExceptT AgentErrorType IO (ConnId, ConnId)
|
||||
makeConnection_ pqEnc sqSecured alice bob = makeConnectionForUsers_ pqEnc sqSecured alice 1 bob 1
|
||||
|
||||
makeConnectionForUsers :: HasCallStack => AgentClient -> UserId -> AgentClient -> UserId -> ExceptT AgentErrorType IO (ConnId, ConnId)
|
||||
makeConnectionForUsers = makeConnectionForUsers_ PQSupportOn
|
||||
makeConnectionForUsers = makeConnectionForUsers_ PQSupportOn True
|
||||
|
||||
makeConnectionForUsers_ :: HasCallStack => PQSupport -> AgentClient -> UserId -> AgentClient -> UserId -> ExceptT AgentErrorType IO (ConnId, ConnId)
|
||||
makeConnectionForUsers_ pqSupport alice aliceUserId bob bobUserId = do
|
||||
makeConnectionForUsers_ :: HasCallStack => PQSupport -> SndQueueSecured -> AgentClient -> UserId -> AgentClient -> UserId -> ExceptT AgentErrorType IO (ConnId, ConnId)
|
||||
makeConnectionForUsers_ pqSupport sqSecured alice aliceUserId bob bobUserId = do
|
||||
(bobId, qInfo) <- A.createConnection alice aliceUserId True SCMInvitation Nothing (CR.IKNoPQ pqSupport) SMSubscribe
|
||||
aliceId <- A.prepareConnectionToJoin bob bobUserId True qInfo pqSupport
|
||||
aliceId' <- A.joinConnection bob bobUserId (Just aliceId) True qInfo "bob's connInfo" pqSupport SMSubscribe
|
||||
liftIO $ aliceId' `shouldBe` aliceId
|
||||
(aliceId', sqSecured') <- A.joinConnection bob bobUserId (Just aliceId) True qInfo "bob's connInfo" pqSupport SMSubscribe
|
||||
liftIO $ do
|
||||
aliceId' `shouldBe` aliceId
|
||||
sqSecured' `shouldBe` sqSecured
|
||||
("", _, A.CONF confId pqSup' _ "bob's connInfo") <- get alice
|
||||
liftIO $ pqSup' `shouldBe` pqSupport
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
@@ -1816,7 +1853,7 @@ testBatchedSubscriptions :: Int -> Int -> ATransport -> IO ()
|
||||
testBatchedSubscriptions nCreate nDel t =
|
||||
withAgentClientsCfgServers2 agentCfg agentCfg initAgentServers2 $ \a b -> do
|
||||
conns <- runServers $ do
|
||||
conns <- replicateM nCreate $ makeConnection_ PQSupportOff a b
|
||||
conns <- replicateM nCreate $ makeConnection_ PQSupportOff True a b
|
||||
forM_ conns $ \(aId, bId) -> exchangeGreetings_ PQEncOff a bId b aId
|
||||
let (aIds', bIds') = unzip $ take nDel conns
|
||||
delete a bIds'
|
||||
@@ -1894,15 +1931,17 @@ testBatchedPendingMessages nCreate nMsgs =
|
||||
withA = withAgent 1 agentCfg initAgentServers testDB
|
||||
withB = withAgent 2 agentCfg initAgentServers testDB2
|
||||
|
||||
testAsyncCommands :: AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
testAsyncCommands alice bob baseId =
|
||||
testAsyncCommands :: SndQueueSecured -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
testAsyncCommands sqSecured alice bob baseId =
|
||||
runRight_ $ do
|
||||
bobId <- createConnectionAsync alice 1 "1" True SCMInvitation (IKNoPQ PQSupportOn) SMSubscribe
|
||||
("1", bobId', INV (ACR _ qInfo)) <- get alice
|
||||
liftIO $ bobId' `shouldBe` bobId
|
||||
aliceId <- joinConnectionAsync bob 1 "2" True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
("2", aliceId', OK) <- get bob
|
||||
liftIO $ aliceId' `shouldBe` aliceId
|
||||
("2", aliceId', JOINED sqSecured') <- get bob
|
||||
liftIO $ do
|
||||
aliceId' `shouldBe` aliceId
|
||||
sqSecured' `shouldBe` sqSecured
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnectionAsync alice "3" bobId confId "alice's connInfo"
|
||||
get alice =##> \case ("3", _, OK) -> True; _ -> False
|
||||
@@ -1955,14 +1994,15 @@ testAsyncCommandsRestore t = do
|
||||
get alice' =##> \case ("1", _, INV _) -> True; _ -> False
|
||||
pure ()
|
||||
|
||||
testAcceptContactAsync :: AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
testAcceptContactAsync alice bob baseId =
|
||||
testAcceptContactAsync :: SndQueueSecured -> AgentClient -> AgentClient -> AgentMsgId -> IO ()
|
||||
testAcceptContactAsync sqSecured alice bob baseId =
|
||||
runRight_ $ do
|
||||
(_, qInfo) <- createConnection alice 1 True SCMContact Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecuredJoin) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecuredJoin `shouldBe` False -- joining via contact address connection
|
||||
("", _, REQ invId _ "bob's connInfo") <- get alice
|
||||
bobId <- acceptContactAsync alice "1" True invId "alice's connInfo" PQSupportOn SMSubscribe
|
||||
get alice =##> \case ("1", c, OK) -> c == bobId; _ -> False
|
||||
get alice =##> \case ("1", c, JOINED sqSecured') -> c == bobId && sqSecured' == sqSecured; _ -> False
|
||||
("", _, CONF confId _ "alice's connInfo") <- get bob
|
||||
allowConnection bob aliceId confId "bob's connInfo"
|
||||
get alice ##> ("", bobId, INFO "bob's connInfo")
|
||||
@@ -2238,7 +2278,7 @@ testJoinConnectionAsyncReplyErrorV8 t = do
|
||||
pure (aId, bId)
|
||||
nGet a =##> \case ("", "", DOWN _ [c]) -> c == bId; _ -> False
|
||||
withSmpServerOn t testPort2 $ do
|
||||
get b =##> \case ("2", c, OK) -> c == aId; _ -> False
|
||||
get b =##> \case ("2", c, JOINED sqSecured) -> c == aId && not sqSecured; _ -> False
|
||||
confId <- withSmpServerStoreLogOn t testPort $ \_ -> do
|
||||
pGet a >>= \case
|
||||
("", "", AEvt _ (UP _ [_])) -> do
|
||||
@@ -2279,7 +2319,7 @@ testJoinConnectionAsyncReplyError t = do
|
||||
withSmpServerOn t testPort2 $ do
|
||||
confId <- withSmpServerStoreLogOn t testPort $ \_ -> do
|
||||
-- both servers need to be online for connection to progress because of SKEY
|
||||
get b =##> \case ("2", c, OK) -> c == aId; _ -> False
|
||||
get b =##> \case ("2", c, JOINED sqSecured) -> c == aId && sqSecured; _ -> False
|
||||
pGet a >>= \case
|
||||
("", "", AEvt _ (UP _ [_])) -> do
|
||||
("", _, CONF confId _ "bob's connInfo") <- get a
|
||||
@@ -2733,8 +2773,8 @@ testSwitch2ConnectionsAbort1 servers = do
|
||||
withB :: (AgentClient -> IO a) -> IO a
|
||||
withB = withAgent 2 agentCfg servers testDB2
|
||||
|
||||
testCreateQueueAuth :: HasCallStack => VersionSMP -> (Maybe BasicAuth, VersionSMP) -> (Maybe BasicAuth, VersionSMP) -> AgentMsgId -> IO Int
|
||||
testCreateQueueAuth srvVersion clnt1 clnt2 baseId = do
|
||||
testCreateQueueAuth :: HasCallStack => VersionSMP -> (Maybe BasicAuth, VersionSMP) -> (Maybe BasicAuth, VersionSMP) -> SndQueueSecured -> AgentMsgId -> IO Int
|
||||
testCreateQueueAuth srvVersion clnt1 clnt2 sqSecured baseId = do
|
||||
a <- getClient 1 clnt1 testDB
|
||||
b <- getClient 2 clnt2 testDB2
|
||||
r <- runRight $ do
|
||||
@@ -2745,7 +2785,8 @@ testCreateQueueAuth srvVersion clnt1 clnt2 baseId = do
|
||||
tryError (joinConnection b 1 True qInfo "bob's connInfo" SMSubscribe) >>= \case
|
||||
Left (SMP _ AUTH) -> pure 1
|
||||
Left e -> throwError e
|
||||
Right aId -> do
|
||||
Right (aId, sqSecured') -> do
|
||||
liftIO $ sqSecured' `shouldBe` sqSecured
|
||||
("", _, CONF confId _ "bob's connInfo") <- get a
|
||||
allowConnection a bId confId "alice's connInfo"
|
||||
get a ##> ("", bId, CON)
|
||||
@@ -2805,7 +2846,7 @@ testDeliveryReceiptsVersion t = do
|
||||
b <- getSMPAgentClient' 2 agentCfg {smpAgentVRange = mkVersionRange 1 3} initAgentServers testDB2
|
||||
withSmpServerStoreMsgLogOn t testPort $ \_ -> do
|
||||
(aId, bId) <- runRight $ do
|
||||
(aId, bId) <- makeConnection_ PQSupportOff a b
|
||||
(aId, bId) <- makeConnection_ PQSupportOff False a b
|
||||
checkVersion a bId 3
|
||||
checkVersion b aId 3
|
||||
(2, _) <- A.sendMessage a bId PQEncOff SMP.noMsgFlags "hello"
|
||||
@@ -2829,8 +2870,8 @@ testDeliveryReceiptsVersion t = do
|
||||
subscribeConnection a' bId
|
||||
subscribeConnection b' aId
|
||||
exchangeGreetingsMsgId_ PQEncOff 4 a' bId b' aId
|
||||
checkVersion a' bId 6
|
||||
checkVersion b' aId 6
|
||||
checkVersion a' bId 7
|
||||
checkVersion b' aId 7
|
||||
(6, PQEncOff) <- A.sendMessage a' bId PQEncOn SMP.noMsgFlags "hello"
|
||||
get a' ##> ("", bId, SENT 6)
|
||||
get b' =##> \case ("", c, Msg' 6 PQEncOff "hello") -> c == aId; _ -> False
|
||||
@@ -2979,7 +3020,8 @@ testServerMultipleIdentities :: HasCallStack => IO ()
|
||||
testServerMultipleIdentities =
|
||||
withAgentClients2 $ \alice bob -> runRight_ $ do
|
||||
(bobId, cReq) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
get alice ##> ("", bobId, CON)
|
||||
@@ -3078,7 +3120,8 @@ testServerQueueInfo = do
|
||||
(bobId, cReq) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
liftIO $ threadDelay 200000
|
||||
checkEmptyQ alice bobId False
|
||||
aliceId <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True cReq "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
liftIO $ threadDelay 200000
|
||||
checkEmptyQ alice bobId True -- secured by sender
|
||||
|
||||
@@ -477,7 +477,7 @@ testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} baseId ali
|
||||
(bobId, aliceId, nonce, message) <- runRight $ do
|
||||
-- establish connection
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, _sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
get bob ##> ("", aliceId, INFO "alice's connInfo")
|
||||
@@ -507,14 +507,14 @@ testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} baseId ali
|
||||
threadDelay 500000
|
||||
suspendAgent alice 0
|
||||
closeSQLiteStore store
|
||||
threadDelay 500000
|
||||
threadDelay 1000000
|
||||
|
||||
-- aliceNtf client doesn't have subscription and is allowed to get notification message
|
||||
withAgent 3 aliceCfg initAgentServers testDB $ \aliceNtf -> runRight_ $ do
|
||||
(_, [SMPMsgMeta {msgFlags = MsgFlags True}]) <- getNotificationMessage aliceNtf nonce message
|
||||
pure ()
|
||||
|
||||
threadDelay 500000
|
||||
threadDelay 1000000
|
||||
reopenSQLiteStore store
|
||||
foregroundAgent alice
|
||||
threadDelay 500000
|
||||
@@ -524,7 +524,7 @@ testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} baseId ali
|
||||
ackMessage alice bobId (baseId + 1) Nothing
|
||||
-- delete notification subscription
|
||||
toggleConnectionNtfs alice bobId False
|
||||
liftIO $ threadDelay 250000
|
||||
liftIO $ threadDelay 500000
|
||||
-- send message
|
||||
2 <- msgId <$> sendMessage bob aliceId (SMP.MsgFlags True) "hello again"
|
||||
get bob ##> ("", aliceId, SENT $ baseId + 2)
|
||||
@@ -544,7 +544,7 @@ testNotificationSubscriptionNewConnection APNSMockServer {apnsQ} baseId alice bo
|
||||
liftIO $ threadDelay 50000
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
liftIO $ threadDelay 1000000
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, _sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
liftIO $ threadDelay 750000
|
||||
void $ messageNotificationData alice apnsQ
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
@@ -591,7 +591,8 @@ testChangeNotificationsMode APNSMockServer {apnsQ} =
|
||||
withAgentClients2 $ \alice bob -> runRight_ $ do
|
||||
-- establish connection
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
get bob ##> ("", aliceId, INFO "alice's connInfo")
|
||||
@@ -653,7 +654,8 @@ testChangeToken APNSMockServer {apnsQ} = withAgent 1 agentCfg initAgentServers t
|
||||
(aliceId, bobId) <- withAgent 2 agentCfg initAgentServers testDB $ \alice -> runRight $ do
|
||||
-- establish connection
|
||||
(bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
|
||||
aliceId <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
(aliceId, sqSecured) <- joinConnection bob 1 True qInfo "bob's connInfo" SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, CONF confId _ "bob's connInfo") <- get alice
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
get bob ##> ("", aliceId, INFO "alice's connInfo")
|
||||
|
||||
@@ -207,7 +207,8 @@ agentDeliverMessageViaProxy aTestCfg@(aSrvs, _, aViaProxy) bTestCfg@(bSrvs, _, b
|
||||
withAgent 1 aCfg (servers aTestCfg) testDB $ \alice ->
|
||||
withAgent 2 aCfg (servers bTestCfg) testDB2 $ \bob -> runRight_ $ do
|
||||
(bobId, qInfo) <- A.createConnection alice 1 True SCMInvitation Nothing (CR.IKNoPQ PQSupportOn) SMSubscribe
|
||||
aliceId <- A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
(aliceId, sqSecured) <- A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, A.CONF confId pqSup' _ "bob's connInfo") <- get alice
|
||||
liftIO $ pqSup' `shouldBe` PQSupportOn
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
@@ -261,7 +262,8 @@ agentDeliverMessagesViaProxyConc agentServers msgs =
|
||||
-- otherwise the CONF messages would get mixed with MSG
|
||||
prePair alice bob = do
|
||||
(bobId, qInfo) <- runExceptT' $ A.createConnection alice 1 True SCMInvitation Nothing (CR.IKNoPQ PQSupportOn) SMSubscribe
|
||||
aliceId <- runExceptT' $ A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
(aliceId, sqSecured) <- runExceptT' $ A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
confId <-
|
||||
get alice >>= \case
|
||||
("", _, A.CONF confId pqSup' _ "bob's connInfo") -> do
|
||||
@@ -329,7 +331,8 @@ agentViaProxyRetryOffline = do
|
||||
withServer $ \_ -> do
|
||||
(aliceId, bobId) <- withServer2 $ \_ -> runRight $ do
|
||||
(bobId, qInfo) <- A.createConnection alice 1 True SCMInvitation Nothing (CR.IKNoPQ PQSupportOn) SMSubscribe
|
||||
aliceId <- A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
(aliceId, sqSecured) <- A.joinConnection bob 1 Nothing True qInfo "bob's connInfo" PQSupportOn SMSubscribe
|
||||
liftIO $ sqSecured `shouldBe` True
|
||||
("", _, A.CONF confId pqSup' _ "bob's connInfo") <- get alice
|
||||
liftIO $ pqSup' `shouldBe` PQSupportOn
|
||||
allowConnection alice bobId confId "alice's connInfo"
|
||||
|
||||
@@ -610,7 +610,7 @@ testRestoreMessages at@(ATransport t) =
|
||||
|
||||
logSize testStoreLogFile `shouldReturn` 2
|
||||
logSize testStoreMsgsFile `shouldReturn` 5
|
||||
logSize testServerStatsBackupFile `shouldReturn` 55
|
||||
logSize testServerStatsBackupFile `shouldReturn` 62
|
||||
Right stats1 <- strDecode <$> B.readFile testServerStatsBackupFile
|
||||
checkStats stats1 [rId] 5 1
|
||||
|
||||
@@ -628,7 +628,7 @@ testRestoreMessages at@(ATransport t) =
|
||||
logSize testStoreLogFile `shouldReturn` 1
|
||||
-- the last message is not removed because it was not ACK'd
|
||||
logSize testStoreMsgsFile `shouldReturn` 3
|
||||
logSize testServerStatsBackupFile `shouldReturn` 55
|
||||
logSize testServerStatsBackupFile `shouldReturn` 62
|
||||
Right stats2 <- strDecode <$> B.readFile testServerStatsBackupFile
|
||||
checkStats stats2 [rId] 5 3
|
||||
|
||||
@@ -647,7 +647,7 @@ testRestoreMessages at@(ATransport t) =
|
||||
|
||||
logSize testStoreLogFile `shouldReturn` 1
|
||||
logSize testStoreMsgsFile `shouldReturn` 0
|
||||
logSize testServerStatsBackupFile `shouldReturn` 55
|
||||
logSize testServerStatsBackupFile `shouldReturn` 62
|
||||
Right stats3 <- strDecode <$> B.readFile testServerStatsBackupFile
|
||||
checkStats stats3 [rId] 5 5
|
||||
|
||||
|
||||
Reference in New Issue
Block a user