{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Simplex.Messaging.Agent
( runSMPAgent,
runSMPAgentBlocking,
getSMPAgentClient,
runSMPAgentClient,
)
where
import Control.Concurrent.STM (stateTVar)
import Control.Logger.Simple (logInfo, showText)
import Control.Monad.Except
import Control.Monad.IO.Unlift (MonadUnliftIO)
import Control.Monad.Reader
import Crypto.Random (MonadRandom)
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as L
import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8)
import Data.Time.Clock
import Database.SQLite.Simple (SQLError)
import Simplex.Messaging.Agent.Client
import Simplex.Messaging.Agent.Env.SQLite
import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Agent.Store
import Simplex.Messaging.Agent.Store.SQLite (SQLiteStore, connectSQLiteStore)
import Simplex.Messaging.Client (SMPServerTransmission)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Protocol (CorrId (..), MsgBody, SenderPublicKey)
import qualified Simplex.Messaging.Protocol as SMP
import Simplex.Messaging.Transport (putLn, runTCPServer)
import Simplex.Messaging.Util (bshow)
import System.IO (Handle)
import System.Random (randomR)
import UnliftIO.Async (race_)
import qualified UnliftIO.Exception as E
import UnliftIO.STM
runSMPAgent :: (MonadRandom m, MonadUnliftIO m) => AgentConfig -> m ()
runSMPAgent :: AgentConfig -> m ()
runSMPAgent cfg :: AgentConfig
cfg = m (TMVar Bool)
forall (m :: * -> *) a. MonadIO m => m (TMVar a)
newEmptyTMVarIO m (TMVar Bool) -> (TMVar Bool -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (TMVar Bool -> AgentConfig -> m ()
forall (m :: * -> *).
(MonadRandom m, MonadUnliftIO m) =>
TMVar Bool -> AgentConfig -> m ()
`runSMPAgentBlocking` AgentConfig
cfg)
runSMPAgentBlocking :: (MonadRandom m, MonadUnliftIO m) => TMVar Bool -> AgentConfig -> m ()
runSMPAgentBlocking :: TMVar Bool -> AgentConfig -> m ()
runSMPAgentBlocking started :: TMVar Bool
started cfg :: AgentConfig
cfg@AgentConfig {ServiceName
$sel:tcpPort:AgentConfig :: AgentConfig -> ServiceName
tcpPort :: ServiceName
tcpPort} = ReaderT Env m () -> Env -> m ()
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT Env m ()
forall (m' :: * -> *).
(MonadUnliftIO m', MonadReader Env m') =>
m' ()
smpAgent (Env -> m ()) -> m Env -> m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< AgentConfig -> m Env
forall (m :: * -> *).
(MonadUnliftIO m, MonadRandom m) =>
AgentConfig -> m Env
newSMPAgentEnv AgentConfig
cfg
where
smpAgent :: (MonadUnliftIO m', MonadReader Env m') => m' ()
smpAgent :: m' ()
smpAgent = TMVar Bool -> ServiceName -> (Handle -> m' ()) -> m' ()
forall (m :: * -> *).
MonadUnliftIO m =>
TMVar Bool -> ServiceName -> (Handle -> m ()) -> m ()
runTCPServer TMVar Bool
started ServiceName
tcpPort ((Handle -> m' ()) -> m' ()) -> (Handle -> m' ()) -> m' ()
forall a b. (a -> b) -> a -> b
$ \h :: Handle
h -> do
IO () -> m' ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m' ()) -> IO () -> m' ()
forall a b. (a -> b) -> a -> b
$ Handle -> ByteString -> IO ()
putLn Handle
h "Welcome to SMP v0.3.1 agent"
AgentClient
c <- m' AgentClient
forall (m :: * -> *).
(MonadUnliftIO m, MonadReader Env m) =>
m AgentClient
getSMPAgentClient
AgentClient -> Bool -> m' ()
forall (m :: * -> *).
MonadUnliftIO m =>
AgentClient -> Bool -> m ()
logConnection AgentClient
c Bool
True
m' () -> m' () -> m' ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m ()
race_ (Handle -> AgentClient -> m' ()
forall (m :: * -> *).
MonadUnliftIO m =>
Handle -> AgentClient -> m ()
connectClient Handle
h AgentClient
c) (AgentClient -> m' ()
forall (m :: * -> *).
(MonadUnliftIO m, MonadReader Env m) =>
AgentClient -> m ()
runSMPAgentClient AgentClient
c)
m' () -> m' () -> m' ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m a
`E.finally` (AgentClient -> m' ()
forall (m :: * -> *). MonadUnliftIO m => AgentClient -> m ()
closeSMPServerClients AgentClient
c m' () -> m' () -> m' ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> AgentClient -> Bool -> m' ()
forall (m :: * -> *).
MonadUnliftIO m =>
AgentClient -> Bool -> m ()
logConnection AgentClient
c Bool
False)
getSMPAgentClient :: (MonadUnliftIO m, MonadReader Env m) => m AgentClient
getSMPAgentClient :: m AgentClient
getSMPAgentClient = do
TVar Int
n <- (Env -> TVar Int) -> m (TVar Int)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> TVar Int
clientCounter
AgentConfig
cfg <- (Env -> AgentConfig) -> m AgentConfig
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> AgentConfig
config
STM AgentClient -> m AgentClient
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM AgentClient -> m AgentClient)
-> STM AgentClient -> m AgentClient
forall a b. (a -> b) -> a -> b
$ TVar Int -> AgentConfig -> STM AgentClient
newAgentClient TVar Int
n AgentConfig
cfg
connectClient :: MonadUnliftIO m => Handle -> AgentClient -> m ()
connectClient :: Handle -> AgentClient -> m ()
connectClient h :: Handle
h c :: AgentClient
c = m () -> m () -> m ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m ()
race_ (Handle -> AgentClient -> m ()
forall (m :: * -> *).
MonadUnliftIO m =>
Handle -> AgentClient -> m ()
send Handle
h AgentClient
c) (Handle -> AgentClient -> m ()
forall (m :: * -> *).
MonadUnliftIO m =>
Handle -> AgentClient -> m ()
receive Handle
h AgentClient
c)
logConnection :: MonadUnliftIO m => AgentClient -> Bool -> m ()
logConnection :: AgentClient -> Bool -> m ()
logConnection c :: AgentClient
c connected :: Bool
connected =
let event :: Text
event = if Bool
connected then "connected to" else "disconnected from"
in Text -> m ()
forall (m :: * -> *).
(?callStack::CallStack, MonadIO m) =>
Text -> m ()
logInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.unwords ["client", Int -> Text
forall a. Show a => a -> Text
showText (AgentClient -> Int
clientId AgentClient
c), Text
event, "Agent"]
runSMPAgentClient :: (MonadUnliftIO m, MonadReader Env m) => AgentClient -> m ()
runSMPAgentClient :: AgentClient -> m ()
runSMPAgentClient c :: AgentClient
c = do
ServiceName
db <- (Env -> ServiceName) -> m ServiceName
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks ((Env -> ServiceName) -> m ServiceName)
-> (Env -> ServiceName) -> m ServiceName
forall a b. (a -> b) -> a -> b
$ AgentConfig -> ServiceName
dbFile (AgentConfig -> ServiceName)
-> (Env -> AgentConfig) -> Env -> ServiceName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env -> AgentConfig
config
SQLiteStore
s1 <- ServiceName -> m SQLiteStore
forall (m :: * -> *).
MonadUnliftIO m =>
ServiceName -> m SQLiteStore
connectSQLiteStore ServiceName
db
SQLiteStore
s2 <- ServiceName -> m SQLiteStore
forall (m :: * -> *).
MonadUnliftIO m =>
ServiceName -> m SQLiteStore
connectSQLiteStore ServiceName
db
m () -> m () -> m ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m ()
race_ (AgentClient -> SQLiteStore -> m ()
forall (m :: * -> *).
(MonadUnliftIO m, MonadReader Env m) =>
AgentClient -> SQLiteStore -> m ()
subscriber AgentClient
c SQLiteStore
s1) (AgentClient -> SQLiteStore -> m ()
forall (m :: * -> *).
(MonadUnliftIO m, MonadReader Env m) =>
AgentClient -> SQLiteStore -> m ()
client AgentClient
c SQLiteStore
s2)
receive :: forall m. MonadUnliftIO m => Handle -> AgentClient -> m ()
receive :: Handle -> AgentClient -> m ()
receive h :: Handle
h c :: AgentClient
c@AgentClient {TBQueue (ATransmission 'Client)
$sel:rcvQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Client)
rcvQ :: TBQueue (ATransmission 'Client)
rcvQ, TBQueue (ATransmission 'Agent)
$sel:sndQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Agent)
sndQ :: TBQueue (ATransmission 'Agent)
sndQ} = m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
(corrId :: CorrId
corrId, cAlias :: ByteString
cAlias, cmdOrErr :: Either AgentErrorType (ACommand 'Client)
cmdOrErr) <- SAParty 'Client
-> Handle
-> m (CorrId, ByteString, Either AgentErrorType (ACommand 'Client))
forall (m :: * -> *) (p :: AParty).
MonadIO m =>
SAParty p -> Handle -> m (ATransmissionOrError p)
tGet SAParty 'Client
SClient Handle
h
case Either AgentErrorType (ACommand 'Client)
cmdOrErr of
Right cmd :: ACommand 'Client
cmd -> TBQueue (ATransmission 'Client) -> ATransmission 'Client -> m ()
forall (p :: AParty).
TBQueue (ATransmission p) -> ATransmission p -> m ()
write TBQueue (ATransmission 'Client)
rcvQ (CorrId
corrId, ByteString
cAlias, ACommand 'Client
cmd)
Left e :: AgentErrorType
e -> TBQueue (ATransmission 'Agent) -> ATransmission 'Agent -> m ()
forall (p :: AParty).
TBQueue (ATransmission p) -> ATransmission p -> m ()
write TBQueue (ATransmission 'Agent)
sndQ (CorrId
corrId, ByteString
cAlias, AgentErrorType -> ACommand 'Agent
ERR AgentErrorType
e)
where
write :: TBQueue (ATransmission p) -> ATransmission p -> m ()
write :: TBQueue (ATransmission p) -> ATransmission p -> m ()
write q :: TBQueue (ATransmission p)
q t :: ATransmission p
t = do
AgentClient -> ByteString -> ATransmission p -> m ()
forall (m :: * -> *) (a :: AParty).
MonadUnliftIO m =>
AgentClient -> ByteString -> ATransmission a -> m ()
logClient AgentClient
c "-->" ATransmission p
t
STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ()) -> STM () -> m ()
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission p) -> ATransmission p -> STM ()
forall a. TBQueue a -> a -> STM ()
writeTBQueue TBQueue (ATransmission p)
q ATransmission p
t
send :: MonadUnliftIO m => Handle -> AgentClient -> m ()
send :: Handle -> AgentClient -> m ()
send h :: Handle
h c :: AgentClient
c@AgentClient {TBQueue (ATransmission 'Agent)
sndQ :: TBQueue (ATransmission 'Agent)
$sel:sndQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Agent)
sndQ} = m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
ATransmission 'Agent
t <- STM (ATransmission 'Agent) -> m (ATransmission 'Agent)
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM (ATransmission 'Agent) -> m (ATransmission 'Agent))
-> STM (ATransmission 'Agent) -> m (ATransmission 'Agent)
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission 'Agent) -> STM (ATransmission 'Agent)
forall a. TBQueue a -> STM a
readTBQueue TBQueue (ATransmission 'Agent)
sndQ
Handle -> ATransmission 'Agent -> m ()
forall (m :: * -> *) (p :: AParty).
MonadIO m =>
Handle -> ATransmission p -> m ()
tPut Handle
h ATransmission 'Agent
t
AgentClient -> ByteString -> ATransmission 'Agent -> m ()
forall (m :: * -> *) (a :: AParty).
MonadUnliftIO m =>
AgentClient -> ByteString -> ATransmission a -> m ()
logClient AgentClient
c "<--" ATransmission 'Agent
t
logClient :: MonadUnliftIO m => AgentClient -> ByteString -> ATransmission a -> m ()
logClient :: AgentClient -> ByteString -> ATransmission a -> m ()
logClient AgentClient {Int
clientId :: Int
$sel:clientId:AgentClient :: AgentClient -> Int
clientId} dir :: ByteString
dir (CorrId corrId :: ByteString
corrId, cAlias :: ByteString
cAlias, cmd :: ACommand a
cmd) = do
Text -> m ()
forall (m :: * -> *).
(?callStack::CallStack, MonadIO m) =>
Text -> m ()
logInfo (Text -> m ()) -> (ByteString -> Text) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeUtf8 (ByteString -> m ()) -> ByteString -> m ()
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
B.unwords [Int -> ByteString
forall a. Show a => a -> ByteString
bshow Int
clientId, ByteString
dir, "A :", ByteString
corrId, ByteString
cAlias, (Char -> Bool) -> ByteString -> ByteString
B.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= ' ') (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ACommand a -> ByteString
forall (p :: AParty). ACommand p -> ByteString
serializeCommand ACommand a
cmd]
client :: (MonadUnliftIO m, MonadReader Env m) => AgentClient -> SQLiteStore -> m ()
client :: AgentClient -> SQLiteStore -> m ()
client c :: AgentClient
c@AgentClient {TBQueue (ATransmission 'Client)
rcvQ :: TBQueue (ATransmission 'Client)
$sel:rcvQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Client)
rcvQ, TBQueue (ATransmission 'Agent)
sndQ :: TBQueue (ATransmission 'Agent)
$sel:sndQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Agent)
sndQ} st :: SQLiteStore
st = m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
t :: ATransmission 'Client
t@(corrId :: CorrId
corrId, cAlias :: ByteString
cAlias, _) <- STM (ATransmission 'Client) -> m (ATransmission 'Client)
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM (ATransmission 'Client) -> m (ATransmission 'Client))
-> STM (ATransmission 'Client) -> m (ATransmission 'Client)
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission 'Client) -> STM (ATransmission 'Client)
forall a. TBQueue a -> STM a
readTBQueue TBQueue (ATransmission 'Client)
rcvQ
ExceptT AgentErrorType m () -> m (Either AgentErrorType ())
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (AgentClient
-> SQLiteStore
-> ATransmission 'Client
-> ExceptT AgentErrorType m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> SQLiteStore -> ATransmission 'Client -> m ()
processCommand AgentClient
c SQLiteStore
st ATransmission 'Client
t) m (Either AgentErrorType ())
-> (Either AgentErrorType () -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left e :: AgentErrorType
e -> STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ()) -> STM () -> m ()
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission 'Agent) -> ATransmission 'Agent -> STM ()
forall a. TBQueue a -> a -> STM ()
writeTBQueue TBQueue (ATransmission 'Agent)
sndQ (CorrId
corrId, ByteString
cAlias, AgentErrorType -> ACommand 'Agent
ERR AgentErrorType
e)
Right _ -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
withStore ::
AgentMonad m =>
(forall m'. (MonadUnliftIO m', MonadError StoreError m') => m' a) ->
m a
withStore :: (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore action :: forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a
action = do
ExceptT StoreError m a -> m (Either StoreError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT StoreError m a
forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a
action ExceptT StoreError m a
-> (SQLError -> ExceptT StoreError m a) -> ExceptT StoreError m a
forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m a) -> m a
`E.catch` SQLError -> ExceptT StoreError m a
forall (m' :: * -> *) a.
MonadError StoreError m' =>
SQLError -> m' a
handleInternal) m (Either StoreError a) -> (Either StoreError a -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Right c :: a
c -> a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
c
Left e :: StoreError
e -> AgentErrorType -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (AgentErrorType -> m a) -> AgentErrorType -> m a
forall a b. (a -> b) -> a -> b
$ StoreError -> AgentErrorType
storeError StoreError
e
where
handleInternal :: (MonadError StoreError m') => SQLError -> m' a
handleInternal :: SQLError -> m' a
handleInternal e :: SQLError
e = StoreError -> m' a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (StoreError -> m' a)
-> (ByteString -> StoreError) -> ByteString -> m' a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> StoreError
SEInternal (ByteString -> m' a) -> ByteString -> m' a
forall a b. (a -> b) -> a -> b
$ SQLError -> ByteString
forall a. Show a => a -> ByteString
bshow SQLError
e
storeError :: StoreError -> AgentErrorType
storeError :: StoreError -> AgentErrorType
storeError = \case
SEConnNotFound -> ConnectionErrorType -> AgentErrorType
CONN ConnectionErrorType
UNKNOWN
SEConnDuplicate -> ConnectionErrorType -> AgentErrorType
CONN ConnectionErrorType
DUPLICATE
e :: StoreError
e -> ServiceName -> AgentErrorType
INTERNAL (ServiceName -> AgentErrorType) -> ServiceName -> AgentErrorType
forall a b. (a -> b) -> a -> b
$ StoreError -> ServiceName
forall a. Show a => a -> ServiceName
show StoreError
e
processCommand :: forall m. AgentMonad m => AgentClient -> SQLiteStore -> ATransmission 'Client -> m ()
processCommand :: AgentClient -> SQLiteStore -> ATransmission 'Client -> m ()
processCommand c :: AgentClient
c@AgentClient {TBQueue (ATransmission 'Agent)
sndQ :: TBQueue (ATransmission 'Agent)
$sel:sndQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Agent)
sndQ} st :: SQLiteStore
st (corrId :: CorrId
corrId, connAlias :: ByteString
connAlias, cmd :: ACommand 'Client
cmd) =
case ACommand 'Client
cmd of
NEW -> m ()
createNewConnection
JOIN smpQueueInfo :: SMPQueueInfo
smpQueueInfo replyMode :: ReplyMode
replyMode -> SMPQueueInfo -> ReplyMode -> m ()
joinConnection SMPQueueInfo
smpQueueInfo ReplyMode
replyMode
SUB -> ByteString -> m ()
subscribeConnection ByteString
connAlias
SUBALL -> m ()
subscribeAll
SEND msgBody :: ByteString
msgBody -> ByteString -> m ()
sendMessage ByteString
msgBody
OFF -> m ()
suspendConnection
DEL -> m ()
deleteConnection
where
createNewConnection :: m ()
createNewConnection :: m ()
createNewConnection = do
SMPServer
srv <- m SMPServer
getSMPServer
(rq :: RcvQueue
rq, qInfo :: SMPQueueInfo
qInfo) <- AgentClient
-> SMPServer -> ByteString -> m (RcvQueue, SMPQueueInfo)
forall (m :: * -> *).
AgentMonad m =>
AgentClient
-> SMPServer -> ByteString -> m (RcvQueue, SMPQueueInfo)
newReceiveQueue AgentClient
c SMPServer
srv ByteString
connAlias
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> RcvQueue -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> RcvQueue -> m ()
createRcvConn SQLiteStore
st RcvQueue
rq
ACommand 'Agent -> m ()
respond (ACommand 'Agent -> m ()) -> ACommand 'Agent -> m ()
forall a b. (a -> b) -> a -> b
$ SMPQueueInfo -> ACommand 'Agent
INV SMPQueueInfo
qInfo
getSMPServer :: m SMPServer
getSMPServer :: m SMPServer
getSMPServer =
(Env -> NonEmpty SMPServer) -> m (NonEmpty SMPServer)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks (AgentConfig -> NonEmpty SMPServer
smpServers (AgentConfig -> NonEmpty SMPServer)
-> (Env -> AgentConfig) -> Env -> NonEmpty SMPServer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env -> AgentConfig
config) m (NonEmpty SMPServer)
-> (NonEmpty SMPServer -> m SMPServer) -> m SMPServer
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
srv :: SMPServer
srv :| [] -> SMPServer -> m SMPServer
forall (f :: * -> *) a. Applicative f => a -> f a
pure SMPServer
srv
servers :: NonEmpty SMPServer
servers -> do
TVar StdGen
gen <- (Env -> TVar StdGen) -> m (TVar StdGen)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> TVar StdGen
randomServer
Int
i <- STM Int -> m Int
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM Int -> m Int)
-> ((StdGen -> (Int, StdGen)) -> STM Int)
-> (StdGen -> (Int, StdGen))
-> m Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TVar StdGen -> (StdGen -> (Int, StdGen)) -> STM Int
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar StdGen
gen ((StdGen -> (Int, StdGen)) -> m Int)
-> (StdGen -> (Int, StdGen)) -> m Int
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> StdGen -> (Int, StdGen)
forall a g. (Random a, RandomGen g) => (a, a) -> g -> (a, g)
randomR (0, NonEmpty SMPServer -> Int
forall a. NonEmpty a -> Int
L.length NonEmpty SMPServer
servers Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1)
SMPServer -> m SMPServer
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SMPServer -> m SMPServer) -> SMPServer -> m SMPServer
forall a b. (a -> b) -> a -> b
$ NonEmpty SMPServer
servers NonEmpty SMPServer -> Int -> SMPServer
forall a. NonEmpty a -> Int -> a
L.!! Int
i
joinConnection :: SMPQueueInfo -> ReplyMode -> m ()
joinConnection :: SMPQueueInfo -> ReplyMode -> m ()
joinConnection qInfo :: SMPQueueInfo
qInfo (ReplyMode replyMode :: OnOff
replyMode) = do
(sq :: SndQueue
sq, senderKey :: SenderPublicKey
senderKey, verifyKey :: SenderPublicKey
verifyKey) <- SMPQueueInfo
-> ByteString -> m (SndQueue, SenderPublicKey, SenderPublicKey)
forall (m :: * -> *).
(MonadUnliftIO m, MonadReader Env m) =>
SMPQueueInfo
-> ByteString -> m (SndQueue, SenderPublicKey, SenderPublicKey)
newSendQueue SMPQueueInfo
qInfo ByteString
connAlias
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> SndQueue -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> SndQueue -> m ()
createSndConn SQLiteStore
st SndQueue
sq
AgentClient
-> SQLiteStore
-> SndQueue
-> SenderPublicKey
-> SenderPublicKey
-> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient
-> SQLiteStore
-> SndQueue
-> SenderPublicKey
-> SenderPublicKey
-> m ()
connectToSendQueue AgentClient
c SQLiteStore
st SndQueue
sq SenderPublicKey
senderKey SenderPublicKey
verifyKey
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (OnOff
replyMode OnOff -> OnOff -> Bool
forall a. Eq a => a -> a -> Bool
== OnOff
On) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ SndQueue -> m ()
createReplyQueue SndQueue
sq
subscribeConnection :: ConnAlias -> m ()
subscribeConnection :: ByteString -> m ()
subscribeConnection cAlias :: ByteString
cAlias =
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' SomeConn)
-> m SomeConn
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> ByteString -> m' SomeConn
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> m SomeConn
getConn SQLiteStore
st ByteString
cAlias) m SomeConn -> (SomeConn -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
SomeConn _ (DuplexConnection _ rq :: RcvQueue
rq _) -> RcvQueue -> m ()
subscribe RcvQueue
rq
SomeConn _ (RcvConnection _ rq :: RcvQueue
rq) -> RcvQueue -> m ()
subscribe RcvQueue
rq
_ -> AgentErrorType -> m ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (AgentErrorType -> m ()) -> AgentErrorType -> m ()
forall a b. (a -> b) -> a -> b
$ ConnectionErrorType -> AgentErrorType
CONN ConnectionErrorType
SIMPLEX
where
subscribe :: RcvQueue -> m ()
subscribe rq :: RcvQueue
rq = AgentClient -> RcvQueue -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> RcvQueue -> ByteString -> m ()
subscribeQueue AgentClient
c RcvQueue
rq ByteString
cAlias m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ByteString -> ACommand 'Agent -> m ()
respond' ByteString
cAlias ACommand 'Agent
OK
subscribeAll :: m ()
subscribeAll :: m ()
subscribeAll = (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' [ByteString])
-> m [ByteString]
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> m' [ByteString]
forall s (m :: * -> *). MonadAgentStore s m => s -> m [ByteString]
getAllConnAliases SQLiteStore
st) m [ByteString] -> ([ByteString] -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ByteString -> m ()) -> [ByteString] -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ByteString -> m ()
subscribeConnection
sendMessage :: MsgBody -> m ()
sendMessage :: ByteString -> m ()
sendMessage msgBody :: ByteString
msgBody =
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' SomeConn)
-> m SomeConn
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> ByteString -> m' SomeConn
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> m SomeConn
getConn SQLiteStore
st ByteString
connAlias) m SomeConn -> (SomeConn -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
SomeConn _ (DuplexConnection _ _ sq :: SndQueue
sq) -> SndQueue -> m ()
sendMsg SndQueue
sq
SomeConn _ (SndConnection _ sq :: SndQueue
sq) -> SndQueue -> m ()
sendMsg SndQueue
sq
_ -> AgentErrorType -> m ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (AgentErrorType -> m ()) -> AgentErrorType -> m ()
forall a b. (a -> b) -> a -> b
$ ConnectionErrorType -> AgentErrorType
CONN ConnectionErrorType
SIMPLEX
where
sendMsg :: SndQueue -> m ()
sendMsg sq :: SndQueue
sq = do
UTCTime
internalTs <- IO UTCTime -> m UTCTime
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
(internalId :: InternalId
internalId, internalSndId :: InternalSndId
internalSndId, previousMsgHash :: ByteString
previousMsgHash) <- (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' (InternalId, InternalSndId, ByteString))
-> m (InternalId, InternalSndId, ByteString)
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' (InternalId, InternalSndId, ByteString))
-> m (InternalId, InternalSndId, ByteString))
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' (InternalId, InternalSndId, ByteString))
-> m (InternalId, InternalSndId, ByteString)
forall a b. (a -> b) -> a -> b
$ SQLiteStore
-> SndQueue -> m' (InternalId, InternalSndId, ByteString)
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> SndQueue -> m (InternalId, InternalSndId, ByteString)
updateSndIds SQLiteStore
st SndQueue
sq
let msgStr :: ByteString
msgStr =
SMPMessage -> ByteString
serializeSMPMessage
SMPMessage :: AgentMsgId -> UTCTime -> ByteString -> AMessage -> SMPMessage
SMPMessage
{ senderMsgId :: AgentMsgId
senderMsgId = InternalSndId -> AgentMsgId
unSndId InternalSndId
internalSndId,
senderTimestamp :: UTCTime
senderTimestamp = UTCTime
internalTs,
ByteString
previousMsgHash :: ByteString
previousMsgHash :: ByteString
previousMsgHash,
agentMessage :: AMessage
agentMessage = ByteString -> AMessage
A_MSG ByteString
msgBody
}
msgHash :: ByteString
msgHash = ByteString -> ByteString
C.sha256Hash ByteString
msgStr
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$
SQLiteStore -> SndQueue -> SndMsgData -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> SndQueue -> SndMsgData -> m ()
createSndMsg SQLiteStore
st SndQueue
sq (SndMsgData -> m' ()) -> SndMsgData -> m' ()
forall a b. (a -> b) -> a -> b
$
SndMsgData :: InternalId
-> InternalSndId
-> UTCTime
-> ByteString
-> ByteString
-> SndMsgData
SndMsgData {InternalId
$sel:internalId:SndMsgData :: InternalId
internalId :: InternalId
internalId, InternalSndId
$sel:internalSndId:SndMsgData :: InternalSndId
internalSndId :: InternalSndId
internalSndId, UTCTime
$sel:internalTs:SndMsgData :: UTCTime
internalTs :: UTCTime
internalTs, ByteString
$sel:msgBody:SndMsgData :: ByteString
msgBody :: ByteString
msgBody, $sel:internalHash:SndMsgData :: ByteString
internalHash = ByteString
msgHash}
AgentClient -> SndQueue -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> SndQueue -> ByteString -> m ()
sendAgentMessage AgentClient
c SndQueue
sq ByteString
msgStr
ACommand 'Agent -> m ()
respond (ACommand 'Agent -> m ()) -> ACommand 'Agent -> m ()
forall a b. (a -> b) -> a -> b
$ AgentMsgId -> ACommand 'Agent
SENT (InternalId -> AgentMsgId
unId InternalId
internalId)
suspendConnection :: m ()
suspendConnection :: m ()
suspendConnection =
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' SomeConn)
-> m SomeConn
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> ByteString -> m' SomeConn
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> m SomeConn
getConn SQLiteStore
st ByteString
connAlias) m SomeConn -> (SomeConn -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
SomeConn _ (DuplexConnection _ rq :: RcvQueue
rq _) -> RcvQueue -> m ()
suspend RcvQueue
rq
SomeConn _ (RcvConnection _ rq :: RcvQueue
rq) -> RcvQueue -> m ()
suspend RcvQueue
rq
_ -> AgentErrorType -> m ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (AgentErrorType -> m ()) -> AgentErrorType -> m ()
forall a b. (a -> b) -> a -> b
$ ConnectionErrorType -> AgentErrorType
CONN ConnectionErrorType
SIMPLEX
where
suspend :: RcvQueue -> m ()
suspend rq :: RcvQueue
rq = AgentClient -> RcvQueue -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> RcvQueue -> m ()
suspendQueue AgentClient
c RcvQueue
rq m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ACommand 'Agent -> m ()
respond ACommand 'Agent
OK
deleteConnection :: m ()
deleteConnection :: m ()
deleteConnection =
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' SomeConn)
-> m SomeConn
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> ByteString -> m' SomeConn
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> m SomeConn
getConn SQLiteStore
st ByteString
connAlias) m SomeConn -> (SomeConn -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
SomeConn _ (DuplexConnection _ rq :: RcvQueue
rq _) -> RcvQueue -> m ()
delete RcvQueue
rq
SomeConn _ (RcvConnection _ rq :: RcvQueue
rq) -> RcvQueue -> m ()
delete RcvQueue
rq
_ -> m ()
delConn
where
delConn :: m ()
delConn = (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> ByteString -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> m ()
deleteConn SQLiteStore
st ByteString
connAlias) m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ACommand 'Agent -> m ()
respond ACommand 'Agent
OK
delete :: RcvQueue -> m ()
delete rq :: RcvQueue
rq = do
AgentClient -> RcvQueue -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> RcvQueue -> m ()
deleteQueue AgentClient
c RcvQueue
rq
AgentClient -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> ByteString -> m ()
removeSubscription AgentClient
c ByteString
connAlias
m ()
delConn
createReplyQueue :: SndQueue -> m ()
createReplyQueue :: SndQueue -> m ()
createReplyQueue sq :: SndQueue
sq = do
SMPServer
srv <- m SMPServer
getSMPServer
(rq :: RcvQueue
rq, qInfo :: SMPQueueInfo
qInfo) <- AgentClient
-> SMPServer -> ByteString -> m (RcvQueue, SMPQueueInfo)
forall (m :: * -> *).
AgentMonad m =>
AgentClient
-> SMPServer -> ByteString -> m (RcvQueue, SMPQueueInfo)
newReceiveQueue AgentClient
c SMPServer
srv ByteString
connAlias
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> ByteString -> RcvQueue -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> RcvQueue -> m ()
upgradeSndConnToDuplex SQLiteStore
st ByteString
connAlias RcvQueue
rq
UTCTime
senderTimestamp <- IO UTCTime -> m UTCTime
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
AgentClient -> SndQueue -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> SndQueue -> ByteString -> m ()
sendAgentMessage AgentClient
c SndQueue
sq (ByteString -> m ())
-> (SMPMessage -> ByteString) -> SMPMessage -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SMPMessage -> ByteString
serializeSMPMessage (SMPMessage -> m ()) -> SMPMessage -> m ()
forall a b. (a -> b) -> a -> b
$
SMPMessage :: AgentMsgId -> UTCTime -> ByteString -> AMessage -> SMPMessage
SMPMessage
{ senderMsgId :: AgentMsgId
senderMsgId = 0,
UTCTime
senderTimestamp :: UTCTime
senderTimestamp :: UTCTime
senderTimestamp,
previousMsgHash :: ByteString
previousMsgHash = "",
agentMessage :: AMessage
agentMessage = SMPQueueInfo -> AMessage
REPLY SMPQueueInfo
qInfo
}
respond :: ACommand 'Agent -> m ()
respond :: ACommand 'Agent -> m ()
respond = ByteString -> ACommand 'Agent -> m ()
respond' ByteString
connAlias
respond' :: ConnAlias -> ACommand 'Agent -> m ()
respond' :: ByteString -> ACommand 'Agent -> m ()
respond' cAlias :: ByteString
cAlias resp :: ACommand 'Agent
resp = STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ()) -> STM () -> m ()
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission 'Agent) -> ATransmission 'Agent -> STM ()
forall a. TBQueue a -> a -> STM ()
writeTBQueue TBQueue (ATransmission 'Agent)
sndQ (CorrId
corrId, ByteString
cAlias, ACommand 'Agent
resp)
subscriber :: (MonadUnliftIO m, MonadReader Env m) => AgentClient -> SQLiteStore -> m ()
subscriber :: AgentClient -> SQLiteStore -> m ()
subscriber c :: AgentClient
c@AgentClient {TBQueue SMPServerTransmission
$sel:msgQ:AgentClient :: AgentClient -> TBQueue SMPServerTransmission
msgQ :: TBQueue SMPServerTransmission
msgQ} st :: SQLiteStore
st = m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
SMPServerTransmission
t <- STM SMPServerTransmission -> m SMPServerTransmission
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM SMPServerTransmission -> m SMPServerTransmission)
-> STM SMPServerTransmission -> m SMPServerTransmission
forall a b. (a -> b) -> a -> b
$ TBQueue SMPServerTransmission -> STM SMPServerTransmission
forall a. TBQueue a -> STM a
readTBQueue TBQueue SMPServerTransmission
msgQ
ExceptT AgentErrorType m () -> m (Either AgentErrorType ())
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (AgentClient
-> SQLiteStore
-> SMPServerTransmission
-> ExceptT AgentErrorType m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> SQLiteStore -> SMPServerTransmission -> m ()
processSMPTransmission AgentClient
c SQLiteStore
st SMPServerTransmission
t) m (Either AgentErrorType ())
-> (Either AgentErrorType () -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left e :: AgentErrorType
e -> IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ AgentErrorType -> IO ()
forall a. Show a => a -> IO ()
print AgentErrorType
e
Right _ -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
processSMPTransmission :: forall m. AgentMonad m => AgentClient -> SQLiteStore -> SMPServerTransmission -> m ()
processSMPTransmission :: AgentClient -> SQLiteStore -> SMPServerTransmission -> m ()
processSMPTransmission c :: AgentClient
c@AgentClient {TBQueue (ATransmission 'Agent)
sndQ :: TBQueue (ATransmission 'Agent)
$sel:sndQ:AgentClient :: AgentClient -> TBQueue (ATransmission 'Agent)
sndQ} st :: SQLiteStore
st (srv :: SMPServer
srv, rId :: ByteString
rId, cmd :: Command 'Broker
cmd) = do
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' SomeConn)
-> m SomeConn
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore (SQLiteStore -> SMPServer -> ByteString -> m' SomeConn
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> SMPServer -> ByteString -> m SomeConn
getRcvConn SQLiteStore
st SMPServer
srv ByteString
rId) m SomeConn -> (SomeConn -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
SomeConn SCDuplex (DuplexConnection _ rq :: RcvQueue
rq _) -> SConnType 'CDuplex -> RcvQueue -> m ()
forall (c :: ConnType). SConnType c -> RcvQueue -> m ()
processSMP SConnType 'CDuplex
SCDuplex RcvQueue
rq
SomeConn SCRcv (RcvConnection _ rq :: RcvQueue
rq) -> SConnType 'CRcv -> RcvQueue -> m ()
forall (c :: ConnType). SConnType c -> RcvQueue -> m ()
processSMP SConnType 'CRcv
SCRcv RcvQueue
rq
_ -> STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ()) -> STM () -> m ()
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission 'Agent) -> ATransmission 'Agent -> STM ()
forall a. TBQueue a -> a -> STM ()
writeTBQueue TBQueue (ATransmission 'Agent)
sndQ ("", "", AgentErrorType -> ACommand 'Agent
ERR (AgentErrorType -> ACommand 'Agent)
-> AgentErrorType -> ACommand 'Agent
forall a b. (a -> b) -> a -> b
$ ConnectionErrorType -> AgentErrorType
CONN ConnectionErrorType
SIMPLEX)
where
processSMP :: SConnType c -> RcvQueue -> m ()
processSMP :: SConnType c -> RcvQueue -> m ()
processSMP cType :: SConnType c
cType rq :: RcvQueue
rq@RcvQueue {ByteString
$sel:connAlias:RcvQueue :: RcvQueue -> ByteString
connAlias :: ByteString
connAlias, QueueStatus
$sel:status:RcvQueue :: RcvQueue -> QueueStatus
status :: QueueStatus
status} =
case Command 'Broker
cmd of
SMP.MSG srvMsgId :: ByteString
srvMsgId srvTs :: UTCTime
srvTs msgBody :: ByteString
msgBody -> do
ByteString
msg <- RcvQueue -> ByteString -> m ByteString
forall (m :: * -> *).
AgentMonad m =>
RcvQueue -> ByteString -> m ByteString
decryptAndVerify RcvQueue
rq ByteString
msgBody
let msgHash :: ByteString
msgHash = ByteString -> ByteString
C.sha256Hash ByteString
msg
SMPMessage
agentMsg <- Either AgentErrorType SMPMessage -> m SMPMessage
forall e (m :: * -> *) a. MonadError e m => Either e a -> m a
liftEither (Either AgentErrorType SMPMessage -> m SMPMessage)
-> Either AgentErrorType SMPMessage -> m SMPMessage
forall a b. (a -> b) -> a -> b
$ ByteString -> Either AgentErrorType SMPMessage
parseSMPMessage ByteString
msg
case SMPMessage
agentMsg of
SMPConfirmation senderKey :: SenderPublicKey
senderKey -> SenderPublicKey -> m ()
smpConfirmation SenderPublicKey
senderKey
SMPMessage {AMessage
agentMessage :: AMessage
agentMessage :: SMPMessage -> AMessage
agentMessage, AgentMsgId
senderMsgId :: AgentMsgId
senderMsgId :: SMPMessage -> AgentMsgId
senderMsgId, UTCTime
senderTimestamp :: UTCTime
senderTimestamp :: SMPMessage -> UTCTime
senderTimestamp, ByteString
previousMsgHash :: ByteString
previousMsgHash :: SMPMessage -> ByteString
previousMsgHash} ->
case AMessage
agentMessage of
HELLO verifyKey :: SenderPublicKey
verifyKey _ -> SenderPublicKey -> ByteString -> m ()
helloMsg SenderPublicKey
verifyKey ByteString
msgBody
REPLY qInfo :: SMPQueueInfo
qInfo -> SMPQueueInfo -> m ()
replyMsg SMPQueueInfo
qInfo
A_MSG body :: ByteString
body -> ByteString
-> (AgentMsgId, UTCTime)
-> (ByteString, UTCTime)
-> ByteString
-> ByteString
-> m ()
agentClientMsg ByteString
previousMsgHash (AgentMsgId
senderMsgId, UTCTime
senderTimestamp) (ByteString
srvMsgId, UTCTime
srvTs) ByteString
body ByteString
msgHash
AgentClient -> RcvQueue -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> RcvQueue -> m ()
sendAck AgentClient
c RcvQueue
rq
() -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
SMP.END -> do
AgentClient -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> ByteString -> m ()
removeSubscription AgentClient
c ByteString
connAlias
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
logServer "<--" AgentClient
c SMPServer
srv ByteString
rId "END"
ACommand 'Agent -> m ()
notify ACommand 'Agent
END
_ -> do
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
logServer "<--" AgentClient
c SMPServer
srv ByteString
rId (ByteString -> m ()) -> ByteString -> m ()
forall a b. (a -> b) -> a -> b
$ "unexpected: " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Command 'Broker -> ByteString
forall a. Show a => a -> ByteString
bshow Command 'Broker
cmd
ACommand 'Agent -> m ()
notify (ACommand 'Agent -> m ())
-> (AgentErrorType -> ACommand 'Agent) -> AgentErrorType -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AgentErrorType -> ACommand 'Agent
ERR (AgentErrorType -> m ()) -> AgentErrorType -> m ()
forall a b. (a -> b) -> a -> b
$ BrokerErrorType -> AgentErrorType
BROKER BrokerErrorType
UNEXPECTED
where
notify :: ACommand 'Agent -> m ()
notify :: ACommand 'Agent -> m ()
notify msg :: ACommand 'Agent
msg = STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ()) -> STM () -> m ()
forall a b. (a -> b) -> a -> b
$ TBQueue (ATransmission 'Agent) -> ATransmission 'Agent -> STM ()
forall a. TBQueue a -> a -> STM ()
writeTBQueue TBQueue (ATransmission 'Agent)
sndQ ("", ByteString
connAlias, ACommand 'Agent
msg)
prohibited :: m ()
prohibited :: m ()
prohibited = ACommand 'Agent -> m ()
notify (ACommand 'Agent -> m ())
-> (AgentErrorType -> ACommand 'Agent) -> AgentErrorType -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AgentErrorType -> ACommand 'Agent
ERR (AgentErrorType -> m ()) -> AgentErrorType -> m ()
forall a b. (a -> b) -> a -> b
$ SMPAgentError -> AgentErrorType
AGENT SMPAgentError
A_PROHIBITED
smpConfirmation :: SenderPublicKey -> m ()
smpConfirmation :: SenderPublicKey -> m ()
smpConfirmation senderKey :: SenderPublicKey
senderKey = do
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
logServer "<--" AgentClient
c SMPServer
srv ByteString
rId "MSG <KEY>"
case QueueStatus
status of
New -> do
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> RcvQueue -> QueueStatus -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> RcvQueue -> QueueStatus -> m ()
setRcvQueueStatus SQLiteStore
st RcvQueue
rq QueueStatus
Confirmed
AgentClient -> RcvQueue -> SenderPublicKey -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> RcvQueue -> SenderPublicKey -> m ()
secureQueue AgentClient
c RcvQueue
rq SenderPublicKey
senderKey
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> RcvQueue -> QueueStatus -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> RcvQueue -> QueueStatus -> m ()
setRcvQueueStatus SQLiteStore
st RcvQueue
rq QueueStatus
Secured
_ -> m ()
prohibited
helloMsg :: SenderPublicKey -> ByteString -> m ()
helloMsg :: SenderPublicKey -> ByteString -> m ()
helloMsg verifyKey :: SenderPublicKey
verifyKey msgBody :: ByteString
msgBody = do
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
logServer "<--" AgentClient
c SMPServer
srv ByteString
rId "MSG <HELLO>"
case QueueStatus
status of
Active -> m ()
prohibited
_ -> do
m ByteString -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m ByteString -> m ()) -> m ByteString -> m ()
forall a b. (a -> b) -> a -> b
$ Maybe SenderPublicKey -> ByteString -> m ByteString
forall (m :: * -> *).
AgentMonad m =>
Maybe SenderPublicKey -> ByteString -> m ByteString
verifyMessage (SenderPublicKey -> Maybe SenderPublicKey
forall a. a -> Maybe a
Just SenderPublicKey
verifyKey) ByteString
msgBody
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> RcvQueue -> SenderPublicKey -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> RcvQueue -> SenderPublicKey -> m ()
setRcvQueueActive SQLiteStore
st RcvQueue
rq SenderPublicKey
verifyKey
case SConnType c
cType of
SCDuplex -> ACommand 'Agent -> m ()
notify ACommand 'Agent
CON
_ -> () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
replyMsg :: SMPQueueInfo -> m ()
replyMsg :: SMPQueueInfo -> m ()
replyMsg qInfo :: SMPQueueInfo
qInfo = do
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
logServer "<--" AgentClient
c SMPServer
srv ByteString
rId "MSG <REPLY>"
case SConnType c
cType of
SCRcv -> do
(sq :: SndQueue
sq, senderKey :: SenderPublicKey
senderKey, verifyKey :: SenderPublicKey
verifyKey) <- SMPQueueInfo
-> ByteString -> m (SndQueue, SenderPublicKey, SenderPublicKey)
forall (m :: * -> *).
(MonadUnliftIO m, MonadReader Env m) =>
SMPQueueInfo
-> ByteString -> m (SndQueue, SenderPublicKey, SenderPublicKey)
newSendQueue SMPQueueInfo
qInfo ByteString
connAlias
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> ByteString -> SndQueue -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> ByteString -> SndQueue -> m ()
upgradeRcvConnToDuplex SQLiteStore
st ByteString
connAlias SndQueue
sq
AgentClient
-> SQLiteStore
-> SndQueue
-> SenderPublicKey
-> SenderPublicKey
-> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient
-> SQLiteStore
-> SndQueue
-> SenderPublicKey
-> SenderPublicKey
-> m ()
connectToSendQueue AgentClient
c SQLiteStore
st SndQueue
sq SenderPublicKey
senderKey SenderPublicKey
verifyKey
ACommand 'Agent -> m ()
notify ACommand 'Agent
CON
_ -> m ()
prohibited
agentClientMsg :: PrevRcvMsgHash -> (ExternalSndId, ExternalSndTs) -> (BrokerId, BrokerTs) -> MsgBody -> MsgHash -> m ()
agentClientMsg :: ByteString
-> (AgentMsgId, UTCTime)
-> (ByteString, UTCTime)
-> ByteString
-> ByteString
-> m ()
agentClientMsg receivedPrevMsgHash :: ByteString
receivedPrevMsgHash senderMeta :: (AgentMsgId, UTCTime)
senderMeta brokerMeta :: (ByteString, UTCTime)
brokerMeta msgBody :: ByteString
msgBody msgHash :: ByteString
msgHash = do
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
forall (m :: * -> *).
AgentMonad m =>
ByteString
-> AgentClient -> SMPServer -> ByteString -> ByteString -> m ()
logServer "<--" AgentClient
c SMPServer
srv ByteString
rId "MSG <MSG>"
case QueueStatus
status of
Active -> do
UTCTime
internalTs <- IO UTCTime -> m UTCTime
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
(internalId :: InternalId
internalId, internalRcvId :: InternalRcvId
internalRcvId, prevExtSndId :: AgentMsgId
prevExtSndId, prevRcvMsgHash :: ByteString
prevRcvMsgHash) <- (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' (InternalId, InternalRcvId, AgentMsgId, ByteString))
-> m (InternalId, InternalRcvId, AgentMsgId, ByteString)
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' (InternalId, InternalRcvId, AgentMsgId, ByteString))
-> m (InternalId, InternalRcvId, AgentMsgId, ByteString))
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' (InternalId, InternalRcvId, AgentMsgId, ByteString))
-> m (InternalId, InternalRcvId, AgentMsgId, ByteString)
forall a b. (a -> b) -> a -> b
$ SQLiteStore
-> RcvQueue
-> m' (InternalId, InternalRcvId, AgentMsgId, ByteString)
forall s (m :: * -> *).
MonadAgentStore s m =>
s
-> RcvQueue
-> m (InternalId, InternalRcvId, AgentMsgId, ByteString)
updateRcvIds SQLiteStore
st RcvQueue
rq
let msgIntegrity :: MsgIntegrity
msgIntegrity = AgentMsgId
-> AgentMsgId -> ByteString -> ByteString -> MsgIntegrity
checkMsgIntegrity AgentMsgId
prevExtSndId ((AgentMsgId, UTCTime) -> AgentMsgId
forall a b. (a, b) -> a
fst (AgentMsgId, UTCTime)
senderMeta) ByteString
prevRcvMsgHash ByteString
receivedPrevMsgHash
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$
SQLiteStore -> RcvQueue -> RcvMsgData -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> RcvQueue -> RcvMsgData -> m ()
createRcvMsg SQLiteStore
st RcvQueue
rq (RcvMsgData -> m' ()) -> RcvMsgData -> m' ()
forall a b. (a -> b) -> a -> b
$
RcvMsgData :: InternalId
-> InternalRcvId
-> UTCTime
-> (AgentMsgId, UTCTime)
-> (ByteString, UTCTime)
-> ByteString
-> ByteString
-> ByteString
-> MsgIntegrity
-> RcvMsgData
RcvMsgData
{ InternalId
$sel:internalId:RcvMsgData :: InternalId
internalId :: InternalId
internalId,
InternalRcvId
$sel:internalRcvId:RcvMsgData :: InternalRcvId
internalRcvId :: InternalRcvId
internalRcvId,
UTCTime
$sel:internalTs:RcvMsgData :: UTCTime
internalTs :: UTCTime
internalTs,
(AgentMsgId, UTCTime)
$sel:senderMeta:RcvMsgData :: (AgentMsgId, UTCTime)
senderMeta :: (AgentMsgId, UTCTime)
senderMeta,
(ByteString, UTCTime)
$sel:brokerMeta:RcvMsgData :: (ByteString, UTCTime)
brokerMeta :: (ByteString, UTCTime)
brokerMeta,
ByteString
$sel:msgBody:RcvMsgData :: ByteString
msgBody :: ByteString
msgBody,
$sel:internalHash:RcvMsgData :: ByteString
internalHash = ByteString
msgHash,
$sel:externalPrevSndHash:RcvMsgData :: ByteString
externalPrevSndHash = ByteString
receivedPrevMsgHash,
MsgIntegrity
$sel:msgIntegrity:RcvMsgData :: MsgIntegrity
msgIntegrity :: MsgIntegrity
msgIntegrity
}
ACommand 'Agent -> m ()
notify
$WMSG :: (AgentMsgId, UTCTime)
-> (ByteString, UTCTime)
-> (AgentMsgId, UTCTime)
-> MsgIntegrity
-> ByteString
-> ACommand 'Agent
MSG
{ recipientMeta :: (AgentMsgId, UTCTime)
recipientMeta = (InternalId -> AgentMsgId
unId InternalId
internalId, UTCTime
internalTs),
(AgentMsgId, UTCTime)
senderMeta :: (AgentMsgId, UTCTime)
senderMeta :: (AgentMsgId, UTCTime)
senderMeta,
(ByteString, UTCTime)
brokerMeta :: (ByteString, UTCTime)
brokerMeta :: (ByteString, UTCTime)
brokerMeta,
ByteString
msgBody :: ByteString
msgBody :: ByteString
msgBody,
MsgIntegrity
msgIntegrity :: MsgIntegrity
msgIntegrity :: MsgIntegrity
msgIntegrity
}
_ -> m ()
prohibited
checkMsgIntegrity :: PrevExternalSndId -> ExternalSndId -> PrevRcvMsgHash -> ByteString -> MsgIntegrity
checkMsgIntegrity :: AgentMsgId
-> AgentMsgId -> ByteString -> ByteString -> MsgIntegrity
checkMsgIntegrity prevExtSndId :: AgentMsgId
prevExtSndId extSndId :: AgentMsgId
extSndId internalPrevMsgHash :: ByteString
internalPrevMsgHash receivedPrevMsgHash :: ByteString
receivedPrevMsgHash
| AgentMsgId
extSndId AgentMsgId -> AgentMsgId -> Bool
forall a. Eq a => a -> a -> Bool
== AgentMsgId
prevExtSndId AgentMsgId -> AgentMsgId -> AgentMsgId
forall a. Num a => a -> a -> a
+ 1 Bool -> Bool -> Bool
&& ByteString
internalPrevMsgHash ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
receivedPrevMsgHash = MsgIntegrity
MsgOk
| AgentMsgId
extSndId AgentMsgId -> AgentMsgId -> Bool
forall a. Ord a => a -> a -> Bool
< AgentMsgId
prevExtSndId = MsgErrorType -> MsgIntegrity
MsgError (MsgErrorType -> MsgIntegrity) -> MsgErrorType -> MsgIntegrity
forall a b. (a -> b) -> a -> b
$ AgentMsgId -> MsgErrorType
MsgBadId AgentMsgId
extSndId
| AgentMsgId
extSndId AgentMsgId -> AgentMsgId -> Bool
forall a. Eq a => a -> a -> Bool
== AgentMsgId
prevExtSndId = MsgErrorType -> MsgIntegrity
MsgError MsgErrorType
MsgDuplicate
| AgentMsgId
extSndId AgentMsgId -> AgentMsgId -> Bool
forall a. Ord a => a -> a -> Bool
> AgentMsgId
prevExtSndId AgentMsgId -> AgentMsgId -> AgentMsgId
forall a. Num a => a -> a -> a
+ 1 = MsgErrorType -> MsgIntegrity
MsgError (MsgErrorType -> MsgIntegrity) -> MsgErrorType -> MsgIntegrity
forall a b. (a -> b) -> a -> b
$ AgentMsgId -> AgentMsgId -> MsgErrorType
MsgSkipped (AgentMsgId
prevExtSndId AgentMsgId -> AgentMsgId -> AgentMsgId
forall a. Num a => a -> a -> a
+ 1) (AgentMsgId
extSndId AgentMsgId -> AgentMsgId -> AgentMsgId
forall a. Num a => a -> a -> a
- 1)
| ByteString
internalPrevMsgHash ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
receivedPrevMsgHash = MsgErrorType -> MsgIntegrity
MsgError MsgErrorType
MsgBadHash
| Bool
otherwise = MsgErrorType -> MsgIntegrity
MsgError MsgErrorType
MsgDuplicate
connectToSendQueue :: AgentMonad m => AgentClient -> SQLiteStore -> SndQueue -> SenderPublicKey -> VerificationKey -> m ()
connectToSendQueue :: AgentClient
-> SQLiteStore
-> SndQueue
-> SenderPublicKey
-> SenderPublicKey
-> m ()
connectToSendQueue c :: AgentClient
c st :: SQLiteStore
st sq :: SndQueue
sq senderKey :: SenderPublicKey
senderKey verifyKey :: SenderPublicKey
verifyKey = do
AgentClient -> SndQueue -> SenderPublicKey -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> SndQueue -> SenderPublicKey -> m ()
sendConfirmation AgentClient
c SndQueue
sq SenderPublicKey
senderKey
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> SndQueue -> QueueStatus -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> SndQueue -> QueueStatus -> m ()
setSndQueueStatus SQLiteStore
st SndQueue
sq QueueStatus
Confirmed
AgentClient -> SndQueue -> SenderPublicKey -> m ()
forall (m :: * -> *).
AgentMonad m =>
AgentClient -> SndQueue -> SenderPublicKey -> m ()
sendHello AgentClient
c SndQueue
sq SenderPublicKey
verifyKey
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall (m :: * -> *) a.
AgentMonad m =>
(forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' a)
-> m a
withStore ((forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ())
-> (forall (m' :: * -> *).
(MonadUnliftIO m', MonadError StoreError m') =>
m' ())
-> m ()
forall a b. (a -> b) -> a -> b
$ SQLiteStore -> SndQueue -> QueueStatus -> m' ()
forall s (m :: * -> *).
MonadAgentStore s m =>
s -> SndQueue -> QueueStatus -> m ()
setSndQueueStatus SQLiteStore
st SndQueue
sq QueueStatus
Active
newSendQueue ::
(MonadUnliftIO m, MonadReader Env m) => SMPQueueInfo -> ConnAlias -> m (SndQueue, SenderPublicKey, VerificationKey)
newSendQueue :: SMPQueueInfo
-> ByteString -> m (SndQueue, SenderPublicKey, SenderPublicKey)
newSendQueue (SMPQueueInfo smpServer :: SMPServer
smpServer senderId :: ByteString
senderId encryptKey :: SenderPublicKey
encryptKey) connAlias :: ByteString
connAlias = do
Int
size <- (Env -> Int) -> m Int
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks ((Env -> Int) -> m Int) -> (Env -> Int) -> m Int
forall a b. (a -> b) -> a -> b
$ AgentConfig -> Int
rsaKeySize (AgentConfig -> Int) -> (Env -> AgentConfig) -> Env -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env -> AgentConfig
config
(senderKey :: SenderPublicKey
senderKey, sndPrivateKey :: SenderPrivateKey
sndPrivateKey) <- IO (SenderPublicKey, SenderPrivateKey)
-> m (SenderPublicKey, SenderPrivateKey)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (SenderPublicKey, SenderPrivateKey)
-> m (SenderPublicKey, SenderPrivateKey))
-> IO (SenderPublicKey, SenderPrivateKey)
-> m (SenderPublicKey, SenderPrivateKey)
forall a b. (a -> b) -> a -> b
$ Int -> IO (SenderPublicKey, SenderPrivateKey)
forall k. PrivateKey k => Int -> IO (KeyPair k)
C.generateKeyPair Int
size
(verifyKey :: SenderPublicKey
verifyKey, signKey :: SenderPrivateKey
signKey) <- IO (SenderPublicKey, SenderPrivateKey)
-> m (SenderPublicKey, SenderPrivateKey)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (SenderPublicKey, SenderPrivateKey)
-> m (SenderPublicKey, SenderPrivateKey))
-> IO (SenderPublicKey, SenderPrivateKey)
-> m (SenderPublicKey, SenderPrivateKey)
forall a b. (a -> b) -> a -> b
$ Int -> IO (SenderPublicKey, SenderPrivateKey)
forall k. PrivateKey k => Int -> IO (KeyPair k)
C.generateKeyPair Int
size
let sndQueue :: SndQueue
sndQueue =
SndQueue :: SMPServer
-> ByteString
-> ByteString
-> SenderPrivateKey
-> SenderPublicKey
-> SenderPrivateKey
-> QueueStatus
-> SndQueue
SndQueue
{ $sel:server:SndQueue :: SMPServer
server = SMPServer
smpServer,
$sel:sndId:SndQueue :: ByteString
sndId = ByteString
senderId,
ByteString
$sel:connAlias:SndQueue :: ByteString
connAlias :: ByteString
connAlias,
SenderPrivateKey
$sel:sndPrivateKey:SndQueue :: SenderPrivateKey
sndPrivateKey :: SenderPrivateKey
sndPrivateKey,
SenderPublicKey
$sel:encryptKey:SndQueue :: SenderPublicKey
encryptKey :: SenderPublicKey
encryptKey,
SenderPrivateKey
$sel:signKey:SndQueue :: SenderPrivateKey
signKey :: SenderPrivateKey
signKey,
$sel:status:SndQueue :: QueueStatus
status = QueueStatus
New
}
(SndQueue, SenderPublicKey, SenderPublicKey)
-> m (SndQueue, SenderPublicKey, SenderPublicKey)
forall (m :: * -> *) a. Monad m => a -> m a
return (SndQueue
sndQueue, SenderPublicKey
senderKey, SenderPublicKey
verifyKey)