{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-}

module Simplex.Messaging.Agent.Store where

import Control.Concurrent.STM (TVar)
import Control.Exception (Exception)
import Crypto.Random (ChaChaDRG)
import Data.ByteString.Char8 (ByteString)
import Data.Int (Int64)
import Data.Kind (Type)
import Data.Time (UTCTime)
import Data.Type.Equality
import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Protocol
  ( MsgBody,
    MsgId,
    RecipientPrivateKey,
    SenderPrivateKey,
    SenderPublicKey,
  )
import qualified Simplex.Messaging.Protocol as SMP

-- * Store management

-- | Store class type. Defines store access methods for implementations.
class Monad m => MonadAgentStore s m where
  -- Queue and Connection management
  createRcvConn :: s -> TVar ChaChaDRG -> ConnData -> RcvQueue -> m ConnId
  createSndConn :: s -> TVar ChaChaDRG -> ConnData -> SndQueue -> m ConnId
  getConn :: s -> ConnId -> m SomeConn
  getAllConnIds :: s -> m [ConnId] -- TODO remove - hack for subscribing to all
  getRcvConn :: s -> SMPServer -> SMP.RecipientId -> m SomeConn
  deleteConn :: s -> ConnId -> m ()
  upgradeRcvConnToDuplex :: s -> ConnId -> SndQueue -> m ()
  upgradeSndConnToDuplex :: s -> ConnId -> RcvQueue -> m ()
  setRcvQueueStatus :: s -> RcvQueue -> QueueStatus -> m ()
  setRcvQueueActive :: s -> RcvQueue -> VerificationKey -> m ()
  setSndQueueStatus :: s -> SndQueue -> QueueStatus -> m ()
  updateSignKey :: s -> SndQueue -> SignatureKey -> m ()

  -- Confirmations
  createConfirmation :: s -> TVar ChaChaDRG -> NewConfirmation -> m ConfirmationId
  acceptConfirmation :: s -> ConfirmationId -> ConnInfo -> m AcceptedConfirmation
  getAcceptedConfirmation :: s -> ConnId -> m AcceptedConfirmation
  removeConfirmations :: s -> ConnId -> m ()

  -- Msg management
  updateRcvIds :: s -> ConnId -> m (InternalId, InternalRcvId, PrevExternalSndId, PrevRcvMsgHash)
  createRcvMsg :: s -> ConnId -> RcvMsgData -> m ()
  updateSndIds :: s -> ConnId -> m (InternalId, InternalSndId, PrevSndMsgHash)
  createSndMsg :: s -> ConnId -> SndMsgData -> m ()
  updateSndMsgStatus :: s -> ConnId -> InternalId -> SndMsgStatus -> m ()
  getPendingMsgData :: s -> ConnId -> InternalId -> m (SndQueue, MsgBody)
  getPendingMsgs :: s -> ConnId -> m [PendingMsg]
  getMsg :: s -> ConnId -> InternalId -> m Msg
  checkRcvMsg :: s -> ConnId -> InternalId -> m ()
  updateRcvMsgAck :: s -> ConnId -> InternalId -> m ()

-- * Queue types

-- | A receive queue. SMP queue through which the agent receives messages from a sender.
data RcvQueue = RcvQueue
  { RcvQueue -> SMPServer
server :: SMPServer,
    RcvQueue -> RecipientId
rcvId :: SMP.RecipientId,
    RcvQueue -> RecipientPrivateKey
rcvPrivateKey :: RecipientPrivateKey,
    RcvQueue -> Maybe RecipientId
sndId :: Maybe SMP.SenderId,
    RcvQueue -> RecipientPrivateKey
decryptKey :: DecryptionKey,
    RcvQueue -> Maybe VerificationKey
verifyKey :: Maybe VerificationKey,
    RcvQueue -> QueueStatus
status :: QueueStatus
  }
  deriving (RcvQueue -> RcvQueue -> Bool
(RcvQueue -> RcvQueue -> Bool)
-> (RcvQueue -> RcvQueue -> Bool) -> Eq RcvQueue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RcvQueue -> RcvQueue -> Bool
$c/= :: RcvQueue -> RcvQueue -> Bool
== :: RcvQueue -> RcvQueue -> Bool
$c== :: RcvQueue -> RcvQueue -> Bool
Eq, Int -> RcvQueue -> ShowS
[RcvQueue] -> ShowS
RcvQueue -> String
(Int -> RcvQueue -> ShowS)
-> (RcvQueue -> String) -> ([RcvQueue] -> ShowS) -> Show RcvQueue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RcvQueue] -> ShowS
$cshowList :: [RcvQueue] -> ShowS
show :: RcvQueue -> String
$cshow :: RcvQueue -> String
showsPrec :: Int -> RcvQueue -> ShowS
$cshowsPrec :: Int -> RcvQueue -> ShowS
Show)

-- | A send queue. SMP queue through which the agent sends messages to a recipient.
data SndQueue = SndQueue
  { SndQueue -> SMPServer
server :: SMPServer,
    SndQueue -> RecipientId
sndId :: SMP.SenderId,
    SndQueue -> RecipientPrivateKey
sndPrivateKey :: SenderPrivateKey,
    SndQueue -> VerificationKey
encryptKey :: EncryptionKey,
    SndQueue -> SignatureKey
signKey :: SignatureKey,
    SndQueue -> QueueStatus
status :: QueueStatus
  }
  deriving (SndQueue -> SndQueue -> Bool
(SndQueue -> SndQueue -> Bool)
-> (SndQueue -> SndQueue -> Bool) -> Eq SndQueue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SndQueue -> SndQueue -> Bool
$c/= :: SndQueue -> SndQueue -> Bool
== :: SndQueue -> SndQueue -> Bool
$c== :: SndQueue -> SndQueue -> Bool
Eq, Int -> SndQueue -> ShowS
[SndQueue] -> ShowS
SndQueue -> String
(Int -> SndQueue -> ShowS)
-> (SndQueue -> String) -> ([SndQueue] -> ShowS) -> Show SndQueue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SndQueue] -> ShowS
$cshowList :: [SndQueue] -> ShowS
show :: SndQueue -> String
$cshow :: SndQueue -> String
showsPrec :: Int -> SndQueue -> ShowS
$cshowsPrec :: Int -> SndQueue -> ShowS
Show)

-- * Connection types

-- | Type of a connection.
data ConnType = CRcv | CSnd | CDuplex deriving (ConnType -> ConnType -> Bool
(ConnType -> ConnType -> Bool)
-> (ConnType -> ConnType -> Bool) -> Eq ConnType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ConnType -> ConnType -> Bool
$c/= :: ConnType -> ConnType -> Bool
== :: ConnType -> ConnType -> Bool
$c== :: ConnType -> ConnType -> Bool
Eq, Int -> ConnType -> ShowS
[ConnType] -> ShowS
ConnType -> String
(Int -> ConnType -> ShowS)
-> (ConnType -> String) -> ([ConnType] -> ShowS) -> Show ConnType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ConnType] -> ShowS
$cshowList :: [ConnType] -> ShowS
show :: ConnType -> String
$cshow :: ConnType -> String
showsPrec :: Int -> ConnType -> ShowS
$cshowsPrec :: Int -> ConnType -> ShowS
Show)

-- | Connection of a specific type.
--
-- - RcvConnection is a connection that only has a receive queue set up,
--   typically created by a recipient initiating a duplex connection.
--
-- - SndConnection is a connection that only has a send queue set up, typically
--   created by a sender joining a duplex connection through a recipient's invitation.
--
-- - DuplexConnection is a connection that has both receive and send queues set up,
--   typically created by upgrading a receive or a send connection with a missing queue.
data Connection (d :: ConnType) where
  RcvConnection :: ConnData -> RcvQueue -> Connection CRcv
  SndConnection :: ConnData -> SndQueue -> Connection CSnd
  DuplexConnection :: ConnData -> RcvQueue -> SndQueue -> Connection CDuplex

deriving instance Eq (Connection d)

deriving instance Show (Connection d)

data SConnType :: ConnType -> Type where
  SCRcv :: SConnType CRcv
  SCSnd :: SConnType CSnd
  SCDuplex :: SConnType CDuplex

connType :: SConnType c -> ConnType
connType :: SConnType c -> ConnType
connType SConnType c
SCRcv = ConnType
CRcv
connType SConnType c
SCSnd = ConnType
CSnd
connType SConnType c
SCDuplex = ConnType
CDuplex

deriving instance Eq (SConnType d)

deriving instance Show (SConnType d)

instance TestEquality SConnType where
  testEquality :: SConnType a -> SConnType b -> Maybe (a :~: b)
testEquality SConnType a
SCRcv SConnType b
SCRcv = (a :~: a) -> Maybe (a :~: a)
forall a. a -> Maybe a
Just a :~: a
forall k (a :: k). a :~: a
Refl
  testEquality SConnType a
SCSnd SConnType b
SCSnd = (a :~: a) -> Maybe (a :~: a)
forall a. a -> Maybe a
Just a :~: a
forall k (a :: k). a :~: a
Refl
  testEquality SConnType a
SCDuplex SConnType b
SCDuplex = (a :~: a) -> Maybe (a :~: a)
forall a. a -> Maybe a
Just a :~: a
forall k (a :: k). a :~: a
Refl
  testEquality SConnType a
_ SConnType b
_ = Maybe (a :~: b)
forall a. Maybe a
Nothing

-- | Connection of an unknown type.
-- Used to refer to an arbitrary connection when retrieving from store.
data SomeConn = forall d. SomeConn (SConnType d) (Connection d)

instance Eq SomeConn where
  SomeConn SConnType d
d Connection d
c == :: SomeConn -> SomeConn -> Bool
== SomeConn SConnType d
d' Connection d
c' = case SConnType d -> SConnType d -> Maybe (d :~: d)
forall k (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality SConnType d
d SConnType d
d' of
    Just d :~: d
Refl -> Connection d
c Connection d -> Connection d -> Bool
forall a. Eq a => a -> a -> Bool
== Connection d
Connection d
c'
    Maybe (d :~: d)
_ -> Bool
False

deriving instance Show SomeConn

newtype ConnData = ConnData {ConnData -> RecipientId
connId :: ConnId}
  deriving (ConnData -> ConnData -> Bool
(ConnData -> ConnData -> Bool)
-> (ConnData -> ConnData -> Bool) -> Eq ConnData
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ConnData -> ConnData -> Bool
$c/= :: ConnData -> ConnData -> Bool
== :: ConnData -> ConnData -> Bool
$c== :: ConnData -> ConnData -> Bool
Eq, Int -> ConnData -> ShowS
[ConnData] -> ShowS
ConnData -> String
(Int -> ConnData -> ShowS)
-> (ConnData -> String) -> ([ConnData] -> ShowS) -> Show ConnData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ConnData] -> ShowS
$cshowList :: [ConnData] -> ShowS
show :: ConnData -> String
$cshow :: ConnData -> String
showsPrec :: Int -> ConnData -> ShowS
$cshowsPrec :: Int -> ConnData -> ShowS
Show)

-- * Confirmation types

data NewConfirmation = NewConfirmation
  { NewConfirmation -> RecipientId
connId :: ConnId,
    NewConfirmation -> VerificationKey
senderKey :: SenderPublicKey,
    NewConfirmation -> RecipientId
senderConnInfo :: ConnInfo
  }

data AcceptedConfirmation = AcceptedConfirmation
  { AcceptedConfirmation -> RecipientId
confirmationId :: ConfirmationId,
    AcceptedConfirmation -> RecipientId
connId :: ConnId,
    AcceptedConfirmation -> VerificationKey
senderKey :: SenderPublicKey,
    AcceptedConfirmation -> RecipientId
senderConnInfo :: ConnInfo,
    AcceptedConfirmation -> RecipientId
ownConnInfo :: ConnInfo
  }

-- * Message integrity validation types

-- | Corresponds to `last_external_snd_msg_id` in `connections` table
type PrevExternalSndId = Int64

-- | Corresponds to `last_rcv_msg_hash` in `connections` table
type PrevRcvMsgHash = MsgHash

-- | Corresponds to `last_snd_msg_hash` in `connections` table
type PrevSndMsgHash = MsgHash

-- ? merge/replace these with RcvMsg and SndMsg

-- * Message data containers - used on Msg creation to reduce number of parameters

data RcvMsgData = RcvMsgData
  { RcvMsgData -> MsgMeta
msgMeta :: MsgMeta,
    RcvMsgData -> RecipientId
msgBody :: MsgBody,
    RcvMsgData -> InternalRcvId
internalRcvId :: InternalRcvId,
    RcvMsgData -> RecipientId
internalHash :: MsgHash,
    RcvMsgData -> RecipientId
externalPrevSndHash :: MsgHash
  }

data SndMsgData = SndMsgData
  { SndMsgData -> InternalId
internalId :: InternalId,
    SndMsgData -> InternalSndId
internalSndId :: InternalSndId,
    SndMsgData -> InternalTs
internalTs :: InternalTs,
    SndMsgData -> RecipientId
msgBody :: MsgBody,
    SndMsgData -> RecipientId
internalHash :: MsgHash,
    SndMsgData -> RecipientId
previousMsgHash :: MsgHash
  }

data PendingMsg = PendingMsg
  { PendingMsg -> RecipientId
connId :: ConnId,
    PendingMsg -> InternalId
msgId :: InternalId
  }
  deriving (Int -> PendingMsg -> ShowS
[PendingMsg] -> ShowS
PendingMsg -> String
(Int -> PendingMsg -> ShowS)
-> (PendingMsg -> String)
-> ([PendingMsg] -> ShowS)
-> Show PendingMsg
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PendingMsg] -> ShowS
$cshowList :: [PendingMsg] -> ShowS
show :: PendingMsg -> String
$cshow :: PendingMsg -> String
showsPrec :: Int -> PendingMsg -> ShowS
$cshowsPrec :: Int -> PendingMsg -> ShowS
Show)

-- * Broadcast types

type BroadcastId = ByteString

-- * Message types

-- | A message in either direction that is stored by the agent.
data Msg = MRcv RcvMsg | MSnd SndMsg
  deriving (Msg -> Msg -> Bool
(Msg -> Msg -> Bool) -> (Msg -> Msg -> Bool) -> Eq Msg
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Msg -> Msg -> Bool
$c/= :: Msg -> Msg -> Bool
== :: Msg -> Msg -> Bool
$c== :: Msg -> Msg -> Bool
Eq, Int -> Msg -> ShowS
[Msg] -> ShowS
Msg -> String
(Int -> Msg -> ShowS)
-> (Msg -> String) -> ([Msg] -> ShowS) -> Show Msg
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Msg] -> ShowS
$cshowList :: [Msg] -> ShowS
show :: Msg -> String
$cshow :: Msg -> String
showsPrec :: Int -> Msg -> ShowS
$cshowsPrec :: Int -> Msg -> ShowS
Show)

-- | A message received by the agent from a sender.
data RcvMsg = RcvMsg
  { RcvMsg -> MsgBase
msgBase :: MsgBase,
    RcvMsg -> InternalRcvId
internalRcvId :: InternalRcvId,
    -- | Id of the message at sender, corresponds to `internalSndId` from the sender's side.
    -- Sender Id is made sequential for detection of missing messages. For redundant / parallel queues,
    -- it also allows to keep track of duplicates and restore the original order before delivery to the client.
    RcvMsg -> ExternalSndId
externalSndId :: ExternalSndId,
    RcvMsg -> InternalTs
externalSndTs :: ExternalSndTs,
    -- | Id of the message at broker, although it is not sequential (to avoid metadata leakage for potential observer),
    -- it is needed to track repeated deliveries in case of connection loss - this logic is not implemented yet.
    RcvMsg -> RecipientId
brokerId :: BrokerId,
    RcvMsg -> InternalTs
brokerTs :: BrokerTs,
    RcvMsg -> RcvMsgStatus
rcvMsgStatus :: RcvMsgStatus,
    -- | Timestamp of acknowledgement to broker, corresponds to `AcknowledgedToBroker` status.
    -- Do not mix up with `brokerTs` - timestamp created at broker after it receives the message from sender.
    RcvMsg -> InternalTs
ackBrokerTs :: AckBrokerTs,
    -- | Timestamp of acknowledgement to sender, corresponds to `AcknowledgedToSender` status.
    -- Do not mix up with `externalSndTs` - timestamp created at sender before sending,
    -- which in its turn corresponds to `internalTs` in sending agent.
    RcvMsg -> InternalTs
ackSenderTs :: AckSenderTs,
    -- | Hash of previous message as received from sender - stored for integrity forensics.
    RcvMsg -> RecipientId
externalPrevSndHash :: MsgHash,
    RcvMsg -> MsgIntegrity
msgIntegrity :: MsgIntegrity
  }
  deriving (RcvMsg -> RcvMsg -> Bool
(RcvMsg -> RcvMsg -> Bool)
-> (RcvMsg -> RcvMsg -> Bool) -> Eq RcvMsg
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RcvMsg -> RcvMsg -> Bool
$c/= :: RcvMsg -> RcvMsg -> Bool
== :: RcvMsg -> RcvMsg -> Bool
$c== :: RcvMsg -> RcvMsg -> Bool
Eq, Int -> RcvMsg -> ShowS
[RcvMsg] -> ShowS
RcvMsg -> String
(Int -> RcvMsg -> ShowS)
-> (RcvMsg -> String) -> ([RcvMsg] -> ShowS) -> Show RcvMsg
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RcvMsg] -> ShowS
$cshowList :: [RcvMsg] -> ShowS
show :: RcvMsg -> String
$cshow :: RcvMsg -> String
showsPrec :: Int -> RcvMsg -> ShowS
$cshowsPrec :: Int -> RcvMsg -> ShowS
Show)

-- internal Ids are newtypes to prevent mixing them up
newtype InternalRcvId = InternalRcvId {InternalRcvId -> ExternalSndId
unRcvId :: Int64} deriving (InternalRcvId -> InternalRcvId -> Bool
(InternalRcvId -> InternalRcvId -> Bool)
-> (InternalRcvId -> InternalRcvId -> Bool) -> Eq InternalRcvId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InternalRcvId -> InternalRcvId -> Bool
$c/= :: InternalRcvId -> InternalRcvId -> Bool
== :: InternalRcvId -> InternalRcvId -> Bool
$c== :: InternalRcvId -> InternalRcvId -> Bool
Eq, Int -> InternalRcvId -> ShowS
[InternalRcvId] -> ShowS
InternalRcvId -> String
(Int -> InternalRcvId -> ShowS)
-> (InternalRcvId -> String)
-> ([InternalRcvId] -> ShowS)
-> Show InternalRcvId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InternalRcvId] -> ShowS
$cshowList :: [InternalRcvId] -> ShowS
show :: InternalRcvId -> String
$cshow :: InternalRcvId -> String
showsPrec :: Int -> InternalRcvId -> ShowS
$cshowsPrec :: Int -> InternalRcvId -> ShowS
Show)

type ExternalSndId = Int64

type ExternalSndTs = UTCTime

type BrokerId = MsgId

type BrokerTs = UTCTime

data RcvMsgStatus
  = Received
  | AcknowledgedToBroker
  | AcknowledgedToSender
  deriving (RcvMsgStatus -> RcvMsgStatus -> Bool
(RcvMsgStatus -> RcvMsgStatus -> Bool)
-> (RcvMsgStatus -> RcvMsgStatus -> Bool) -> Eq RcvMsgStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RcvMsgStatus -> RcvMsgStatus -> Bool
$c/= :: RcvMsgStatus -> RcvMsgStatus -> Bool
== :: RcvMsgStatus -> RcvMsgStatus -> Bool
$c== :: RcvMsgStatus -> RcvMsgStatus -> Bool
Eq, Int -> RcvMsgStatus -> ShowS
[RcvMsgStatus] -> ShowS
RcvMsgStatus -> String
(Int -> RcvMsgStatus -> ShowS)
-> (RcvMsgStatus -> String)
-> ([RcvMsgStatus] -> ShowS)
-> Show RcvMsgStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RcvMsgStatus] -> ShowS
$cshowList :: [RcvMsgStatus] -> ShowS
show :: RcvMsgStatus -> String
$cshow :: RcvMsgStatus -> String
showsPrec :: Int -> RcvMsgStatus -> ShowS
$cshowsPrec :: Int -> RcvMsgStatus -> ShowS
Show)

type AckBrokerTs = UTCTime

type AckSenderTs = UTCTime

-- | A message sent by the agent to a recipient.
data SndMsg = SndMsg
  { SndMsg -> MsgBase
msgBase :: MsgBase,
    -- | Id of the message sent / to be sent, as in its number in order of sending.
    SndMsg -> InternalSndId
internalSndId :: InternalSndId,
    SndMsg -> SndMsgStatus
sndMsgStatus :: SndMsgStatus,
    -- | Timestamp of the message received by broker, corresponds to `Sent` status.
    SndMsg -> InternalTs
sentTs :: SentTs,
    -- | Timestamp of the message received by recipient, corresponds to `Delivered` status.
    SndMsg -> InternalTs
deliveredTs :: DeliveredTs
  }
  deriving (SndMsg -> SndMsg -> Bool
(SndMsg -> SndMsg -> Bool)
-> (SndMsg -> SndMsg -> Bool) -> Eq SndMsg
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SndMsg -> SndMsg -> Bool
$c/= :: SndMsg -> SndMsg -> Bool
== :: SndMsg -> SndMsg -> Bool
$c== :: SndMsg -> SndMsg -> Bool
Eq, Int -> SndMsg -> ShowS
[SndMsg] -> ShowS
SndMsg -> String
(Int -> SndMsg -> ShowS)
-> (SndMsg -> String) -> ([SndMsg] -> ShowS) -> Show SndMsg
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SndMsg] -> ShowS
$cshowList :: [SndMsg] -> ShowS
show :: SndMsg -> String
$cshow :: SndMsg -> String
showsPrec :: Int -> SndMsg -> ShowS
$cshowsPrec :: Int -> SndMsg -> ShowS
Show)

newtype InternalSndId = InternalSndId {InternalSndId -> ExternalSndId
unSndId :: Int64} deriving (InternalSndId -> InternalSndId -> Bool
(InternalSndId -> InternalSndId -> Bool)
-> (InternalSndId -> InternalSndId -> Bool) -> Eq InternalSndId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InternalSndId -> InternalSndId -> Bool
$c/= :: InternalSndId -> InternalSndId -> Bool
== :: InternalSndId -> InternalSndId -> Bool
$c== :: InternalSndId -> InternalSndId -> Bool
Eq, Int -> InternalSndId -> ShowS
[InternalSndId] -> ShowS
InternalSndId -> String
(Int -> InternalSndId -> ShowS)
-> (InternalSndId -> String)
-> ([InternalSndId] -> ShowS)
-> Show InternalSndId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InternalSndId] -> ShowS
$cshowList :: [InternalSndId] -> ShowS
show :: InternalSndId -> String
$cshow :: InternalSndId -> String
showsPrec :: Int -> InternalSndId -> ShowS
$cshowsPrec :: Int -> InternalSndId -> ShowS
Show)

data SndMsgStatus
  = SndMsgCreated
  | SndMsgSent
  | SndMsgDelivered
  deriving (SndMsgStatus -> SndMsgStatus -> Bool
(SndMsgStatus -> SndMsgStatus -> Bool)
-> (SndMsgStatus -> SndMsgStatus -> Bool) -> Eq SndMsgStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SndMsgStatus -> SndMsgStatus -> Bool
$c/= :: SndMsgStatus -> SndMsgStatus -> Bool
== :: SndMsgStatus -> SndMsgStatus -> Bool
$c== :: SndMsgStatus -> SndMsgStatus -> Bool
Eq, Int -> SndMsgStatus -> ShowS
[SndMsgStatus] -> ShowS
SndMsgStatus -> String
(Int -> SndMsgStatus -> ShowS)
-> (SndMsgStatus -> String)
-> ([SndMsgStatus] -> ShowS)
-> Show SndMsgStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SndMsgStatus] -> ShowS
$cshowList :: [SndMsgStatus] -> ShowS
show :: SndMsgStatus -> String
$cshow :: SndMsgStatus -> String
showsPrec :: Int -> SndMsgStatus -> ShowS
$cshowsPrec :: Int -> SndMsgStatus -> ShowS
Show)

type SentTs = UTCTime

type DeliveredTs = UTCTime

-- | Base message data independent of direction.
data MsgBase = MsgBase
  { MsgBase -> RecipientId
connAlias :: ConnId,
    -- | Monotonically increasing id of a message per connection, internal to the agent.
    -- Internal Id preserves ordering between both received and sent messages, and is needed
    -- to track the order of the conversation (which can be different for the sender / receiver)
    -- and address messages in commands. External [sender] Id cannot be used for this purpose
    -- due to a possibility of implementation errors in different agents.
    MsgBase -> InternalId
internalId :: InternalId,
    MsgBase -> InternalTs
internalTs :: InternalTs,
    MsgBase -> RecipientId
msgBody :: MsgBody,
    -- | Hash of the message as computed by agent.
    MsgBase -> RecipientId
internalHash :: MsgHash
  }
  deriving (MsgBase -> MsgBase -> Bool
(MsgBase -> MsgBase -> Bool)
-> (MsgBase -> MsgBase -> Bool) -> Eq MsgBase
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MsgBase -> MsgBase -> Bool
$c/= :: MsgBase -> MsgBase -> Bool
== :: MsgBase -> MsgBase -> Bool
$c== :: MsgBase -> MsgBase -> Bool
Eq, Int -> MsgBase -> ShowS
[MsgBase] -> ShowS
MsgBase -> String
(Int -> MsgBase -> ShowS)
-> (MsgBase -> String) -> ([MsgBase] -> ShowS) -> Show MsgBase
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MsgBase] -> ShowS
$cshowList :: [MsgBase] -> ShowS
show :: MsgBase -> String
$cshow :: MsgBase -> String
showsPrec :: Int -> MsgBase -> ShowS
$cshowsPrec :: Int -> MsgBase -> ShowS
Show)

newtype InternalId = InternalId {InternalId -> ExternalSndId
unId :: Int64} deriving (InternalId -> InternalId -> Bool
(InternalId -> InternalId -> Bool)
-> (InternalId -> InternalId -> Bool) -> Eq InternalId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InternalId -> InternalId -> Bool
$c/= :: InternalId -> InternalId -> Bool
== :: InternalId -> InternalId -> Bool
$c== :: InternalId -> InternalId -> Bool
Eq, Int -> InternalId -> ShowS
[InternalId] -> ShowS
InternalId -> String
(Int -> InternalId -> ShowS)
-> (InternalId -> String)
-> ([InternalId] -> ShowS)
-> Show InternalId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InternalId] -> ShowS
$cshowList :: [InternalId] -> ShowS
show :: InternalId -> String
$cshow :: InternalId -> String
showsPrec :: Int -> InternalId -> ShowS
$cshowsPrec :: Int -> InternalId -> ShowS
Show)

type InternalTs = UTCTime

-- * Store errors

-- | Agent store error.
data StoreError
  = -- | IO exceptions in store actions.
    SEInternal ByteString
  | -- | failed to generate unique random ID
    SEUniqueID
  | -- | Connection alias not found (or both queues absent).
    SEConnNotFound
  | -- | Connection alias already used.
    SEConnDuplicate
  | -- | Wrong connection type, e.g. "send" connection when "receive" or "duplex" is expected, or vice versa.
    -- 'upgradeRcvConnToDuplex' and 'upgradeSndConnToDuplex' do not allow duplex connections - they would also return this error.
    SEBadConnType ConnType
  | -- | Confirmation not found.
    SEConfirmationNotFound
  | -- | Message not found
    SEMsgNotFound
  | -- | Currently not used. The intention was to pass current expected queue status in methods,
    -- as we always know what it should be at any stage of the protocol,
    -- and in case it does not match use this error.
    SEBadQueueStatus
  | -- | Used in `getMsg` that is not implemented/used. TODO remove.
    SENotImplemented
  deriving (StoreError -> StoreError -> Bool
(StoreError -> StoreError -> Bool)
-> (StoreError -> StoreError -> Bool) -> Eq StoreError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: StoreError -> StoreError -> Bool
$c/= :: StoreError -> StoreError -> Bool
== :: StoreError -> StoreError -> Bool
$c== :: StoreError -> StoreError -> Bool
Eq, Int -> StoreError -> ShowS
[StoreError] -> ShowS
StoreError -> String
(Int -> StoreError -> ShowS)
-> (StoreError -> String)
-> ([StoreError] -> ShowS)
-> Show StoreError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [StoreError] -> ShowS
$cshowList :: [StoreError] -> ShowS
show :: StoreError -> String
$cshow :: StoreError -> String
showsPrec :: Int -> StoreError -> ShowS
$cshowsPrec :: Int -> StoreError -> ShowS
Show, Show StoreError
Typeable StoreError
Typeable StoreError
-> Show StoreError
-> (StoreError -> SomeException)
-> (SomeException -> Maybe StoreError)
-> (StoreError -> String)
-> Exception StoreError
SomeException -> Maybe StoreError
StoreError -> String
StoreError -> SomeException
forall e.
Typeable e
-> Show e
-> (e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> String)
-> Exception e
displayException :: StoreError -> String
$cdisplayException :: StoreError -> String
fromException :: SomeException -> Maybe StoreError
$cfromException :: SomeException -> Maybe StoreError
toException :: StoreError -> SomeException
$ctoException :: StoreError -> SomeException
$cp2Exception :: Show StoreError
$cp1Exception :: Typeable StoreError
Exception)