{-# LANGUAGE DataKinds, FlexibleContexts, LambdaCase, OverloadedStrings #-}

{- Defines a set of transactional commands, communicating via internal channels -}
module Pulsar.Core where

import           Control.Exception              ( throwIO )
import           Control.Monad.Catch            ( MonadThrow )
import           Control.Monad.IO.Class
import qualified Data.Binary                   as B
import           Data.Functor                   ( void )
import           Data.ProtoLens.Field           ( HasField )
import           Data.Text                      ( Text )
import           Lens.Family
import           Proto.PulsarApi
import qualified Proto.PulsarApi_Fields        as F
import           Pulsar.Connection
import           Pulsar.Internal.Logger
import qualified Pulsar.Protocol.Commands      as P
import           Pulsar.Protocol.Frame          ( Payload(..)
                                                , Response(..)
                                                , getCommand
                                                )
import           Pulsar.Types
import           UnliftIO.Chan

------ Simple commands ------

verifyResponse
  :: (HasField a "requestId" B.Word64, Show a)
  => ReqId
  -> Chan Response
  -> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
  -> IO (Maybe a)
verifyResponse :: ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
verifyResponse r :: ReqId
r@(ReqId req :: Word64
req) chan :: Chan Response
chan lens :: LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
lens = do
  Response
resp <- Chan Response -> IO Response
forall (m :: * -> *) a. MonadIO m => Chan a -> m a
readChan Chan Response
chan
  let cmd' :: Maybe a
cmd'    = Response -> BaseCommand
getCommand Response
resp BaseCommand
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a) -> Maybe a
forall s a t b. s -> FoldLike a s t a b -> a
^. LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
lens
      req' :: Maybe Word64
req'    = FoldLike Word64 a a Word64 Word64 -> a -> Word64
forall a s t b. FoldLike a s t a b -> s -> a
view FoldLike Word64 a a Word64 Word64
forall (f :: * -> *) s a.
(Functor f, HasField s "requestId" a) =>
LensLike' f s a
F.requestId (a -> Word64) -> Maybe a -> Maybe Word64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
cmd'
      rewrite :: IO ()
rewrite = Chan Response -> Response -> IO ()
forall (m :: * -> *) a. MonadIO m => Chan a -> a -> m ()
writeChan Chan Response
chan Response
resp
      loop :: IO (Maybe a)
loop    = ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
forall a.
(HasField a "requestId" Word64, Show a) =>
ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
verifyResponse ReqId
r Chan Response
chan LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
lens
      checkEq :: (a, Word64) -> IO (Maybe a)
checkEq (_, rq :: Word64
rq) | Word64
rq Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
req = Maybe a
cmd' Maybe a -> IO () -> IO (Maybe a)
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Response -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logResponse Response
resp
                      | Bool
otherwise = IO ()
rewrite IO () -> IO (Maybe a) -> IO (Maybe a)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO (Maybe a)
loop
  IO (Maybe a)
-> ((a, Word64) -> IO (Maybe a))
-> Maybe (a, Word64)
-> IO (Maybe a)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO (Maybe a)
loop (a, Word64) -> IO (Maybe a)
forall a. (a, Word64) -> IO (Maybe a)
checkEq (Maybe (a, Word64) -> IO (Maybe a))
-> Maybe (a, Word64) -> IO (Maybe a)
forall a b. (a -> b) -> a -> b
$ (,) (a -> Word64 -> (a, Word64))
-> Maybe a -> Maybe (Word64 -> (a, Word64))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
cmd' Maybe (Word64 -> (a, Word64)) -> Maybe Word64 -> Maybe (a, Word64)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Word64
req'

lookup :: Connection -> Chan Response -> ReqId -> Topic -> IO ()
lookup :: Connection -> Chan Response -> ReqId -> Topic -> IO ()
lookup (Conn s :: Socket
s) chan :: Chan Response
chan r :: ReqId
r@(ReqId req :: Word64
req) topic :: Topic
topic = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Topic -> BaseCommand
P.lookup Word64
req Topic
topic
  Socket -> BaseCommand -> IO ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Topic -> BaseCommand
P.lookup Word64
req Topic
topic
  -- TODO: we need to analyze it and might need to re-issue another lookup
  IO (Maybe CommandLookupTopicResponse) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Maybe CommandLookupTopicResponse) -> IO ())
-> IO (Maybe CommandLookupTopicResponse) -> IO ()
forall a b. (a -> b) -> a -> b
$ ReqId
-> Chan Response
-> LensLike'
     (Constant (Maybe CommandLookupTopicResponse))
     BaseCommand
     (Maybe CommandLookupTopicResponse)
-> IO (Maybe CommandLookupTopicResponse)
forall a.
(HasField a "requestId" Word64, Show a) =>
ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
verifyResponse ReqId
r Chan Response
chan LensLike'
  (Constant (Maybe CommandLookupTopicResponse))
  BaseCommand
  (Maybe CommandLookupTopicResponse)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'lookupTopicResponse" a) =>
LensLike' f s a
F.maybe'lookupTopicResponse

newProducer
  :: Connection -> Chan Response -> ReqId -> ProducerId -> Topic -> IO Text
newProducer :: Connection
-> Chan Response -> ReqId -> ProducerId -> Topic -> IO Text
newProducer (Conn s :: Socket
s) chan :: Chan Response
chan r :: ReqId
r@(ReqId req :: Word64
req) (PId pid :: Word64
pid) topic :: Topic
topic = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> Topic -> BaseCommand
P.producer Word64
req Word64
pid Topic
topic
  Socket -> BaseCommand -> IO ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> Topic -> BaseCommand
P.producer Word64
req Word64
pid Topic
topic
  ReqId
-> Chan Response
-> LensLike'
     (Constant (Maybe CommandProducerSuccess))
     BaseCommand
     (Maybe CommandProducerSuccess)
-> IO (Maybe CommandProducerSuccess)
forall a.
(HasField a "requestId" Word64, Show a) =>
ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
verifyResponse ReqId
r Chan Response
chan LensLike'
  (Constant (Maybe CommandProducerSuccess))
  BaseCommand
  (Maybe CommandProducerSuccess)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'producerSuccess" a) =>
LensLike' f s a
F.maybe'producerSuccess IO (Maybe CommandProducerSuccess)
-> (Maybe CommandProducerSuccess -> IO Text) -> IO Text
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Just ps :: CommandProducerSuccess
ps -> Text -> IO Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> IO Text) -> Text -> IO Text
forall a b. (a -> b) -> a -> b
$ CommandProducerSuccess
ps CommandProducerSuccess
-> FoldLike
     Text CommandProducerSuccess CommandProducerSuccess Text Text
-> Text
forall s a t b. s -> FoldLike a s t a b -> a
^. FoldLike
  Text CommandProducerSuccess CommandProducerSuccess Text Text
forall (f :: * -> *) s a.
(Functor f, HasField s "producerName" a) =>
LensLike' f s a
F.producerName
    Nothing -> Text -> IO Text
forall (m :: * -> *) a. Monad m => a -> m a
return ""

closeProducer :: Connection -> Chan Response -> ReqId -> ProducerId -> IO ()
closeProducer :: Connection -> Chan Response -> ReqId -> ProducerId -> IO ()
closeProducer (Conn s :: Socket
s) chan :: Chan Response
chan r :: ReqId
r@(ReqId req :: Word64
req) (PId pid :: Word64
pid) = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> BaseCommand
P.closeProducer Word64
req Word64
pid
  Socket -> BaseCommand -> IO ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> BaseCommand
P.closeProducer Word64
req Word64
pid
  IO (Maybe CommandSuccess) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Maybe CommandSuccess) -> IO ())
-> IO (Maybe CommandSuccess) -> IO ()
forall a b. (a -> b) -> a -> b
$ ReqId
-> Chan Response
-> LensLike'
     (Constant (Maybe CommandSuccess))
     BaseCommand
     (Maybe CommandSuccess)
-> IO (Maybe CommandSuccess)
forall a.
(HasField a "requestId" Word64, Show a) =>
ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
verifyResponse ReqId
r Chan Response
chan LensLike'
  (Constant (Maybe CommandSuccess))
  BaseCommand
  (Maybe CommandSuccess)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'success" a) =>
LensLike' f s a
F.maybe'success

newSubscriber
  :: Connection
  -> Chan Response
  -> ReqId
  -> ConsumerId
  -> Topic
  -> SubscriptionName
  -> IO ()
newSubscriber :: Connection
-> Chan Response
-> ReqId
-> ConsumerId
-> Topic
-> SubscriptionName
-> IO ()
newSubscriber (Conn s :: Socket
s) chan :: Chan Response
chan r :: ReqId
r@(ReqId req :: Word64
req) (CId cid :: Word64
cid) topic :: Topic
topic subs :: SubscriptionName
subs = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> Topic -> SubscriptionName -> BaseCommand
P.subscribe Word64
req Word64
cid Topic
topic SubscriptionName
subs
  Socket -> BaseCommand -> IO ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> Topic -> SubscriptionName -> BaseCommand
P.subscribe Word64
req Word64
cid Topic
topic SubscriptionName
subs
  -- TODO: we may need to check for failure too
  IO (Maybe CommandSuccess) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Maybe CommandSuccess) -> IO ())
-> IO (Maybe CommandSuccess) -> IO ()
forall a b. (a -> b) -> a -> b
$ ReqId
-> Chan Response
-> LensLike'
     (Constant (Maybe CommandSuccess))
     BaseCommand
     (Maybe CommandSuccess)
-> IO (Maybe CommandSuccess)
forall a.
(HasField a "requestId" Word64, Show a) =>
ReqId
-> Chan Response
-> LensLike' (Constant (Maybe a)) BaseCommand (Maybe a)
-> IO (Maybe a)
verifyResponse ReqId
r Chan Response
chan LensLike'
  (Constant (Maybe CommandSuccess))
  BaseCommand
  (Maybe CommandSuccess)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'success" a) =>
LensLike' f s a
F.maybe'success

flow :: Connection -> ConsumerId -> IO ()
flow :: Connection -> ConsumerId -> IO ()
flow (Conn s :: Socket
s) (CId cid :: Word64
cid) = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> BaseCommand
P.flow Word64
cid
  Socket -> BaseCommand -> IO ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> BaseCommand
P.flow Word64
cid

ack :: MonadIO m => Connection -> ConsumerId -> MessageIdData -> m ()
ack :: Connection -> ConsumerId -> MessageIdData -> m ()
ack (Conn s :: Socket
s) (CId cid :: Word64
cid) msgId :: MessageIdData
msgId = do
  BaseCommand -> m ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> m ()) -> BaseCommand -> m ()
forall a b. (a -> b) -> a -> b
$ Word64 -> MessageIdData -> BaseCommand
P.ack Word64
cid MessageIdData
msgId
  Socket -> BaseCommand -> m ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> m ()) -> BaseCommand -> m ()
forall a b. (a -> b) -> a -> b
$ Word64 -> MessageIdData -> BaseCommand
P.ack Word64
cid MessageIdData
msgId

closeConsumer :: Connection -> Chan Response -> ReqId -> ConsumerId -> IO ()
closeConsumer :: Connection -> Chan Response -> ReqId -> ConsumerId -> IO ()
closeConsumer (Conn s :: Socket
s) _ (ReqId req :: Word64
req) (CId cid :: Word64
cid) = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> BaseCommand
P.closeConsumer Word64
req Word64
cid
  Socket -> BaseCommand -> IO ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> BaseCommand
P.closeConsumer Word64
req Word64
cid
  -- FIXME: this is a workaround but the problem is the response for close consumer never comes on a SIGTERM when consuming
  -- from the Chan, since the writer gets interrupted and no messages come in.
  Response
resp <- Socket -> IO Response
forall (m :: * -> *). MonadIO m => Socket -> m Response
receive Socket
s
  case Response -> BaseCommand
getCommand Response
resp BaseCommand
-> LensLike'
     (Constant (Maybe CommandSuccess))
     BaseCommand
     (Maybe CommandSuccess)
-> Maybe CommandSuccess
forall s a t b. s -> FoldLike a s t a b -> a
^. LensLike'
  (Constant (Maybe CommandSuccess))
  BaseCommand
  (Maybe CommandSuccess)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'success" a) =>
LensLike' f s a
F.maybe'success of
    Just _  -> Response -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logResponse Response
resp
    Nothing -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

------ Keep Alive -------

ping :: (MonadThrow m, MonadIO m) => Connection -> Chan Response -> m ()
ping :: Connection -> Chan Response -> m ()
ping (Conn s :: Socket
s) chan :: Chan Response
chan = do
  BaseCommand -> m ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest BaseCommand
P.ping
  Socket -> BaseCommand -> m ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s BaseCommand
P.ping
  BaseCommand
cmd <- Response -> BaseCommand
getCommand (Response -> BaseCommand) -> m Response -> m BaseCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Chan Response -> m Response
forall (m :: * -> *) a. MonadIO m => Chan a -> m a
readChan Chan Response
chan
  case BaseCommand
cmd BaseCommand
-> FoldLike
     (Maybe CommandPong)
     BaseCommand
     BaseCommand
     (Maybe CommandPong)
     (Maybe CommandPong)
-> Maybe CommandPong
forall s a t b. s -> FoldLike a s t a b -> a
^. FoldLike
  (Maybe CommandPong)
  BaseCommand
  BaseCommand
  (Maybe CommandPong)
  (Maybe CommandPong)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'pong" a) =>
LensLike' f s a
F.maybe'pong of
    Just p :: CommandPong
p  -> CommandPong -> m ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logResponse CommandPong
p
    Nothing -> IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (IOError -> IO ()) -> IOError -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IOError -> IO ()
forall e a. Exception e => e -> IO a
throwIO (IOError -> m ()) -> IOError -> m ()
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError "Failed to get PONG"

pong :: MonadIO m => Connection -> m ()
pong :: Connection -> m ()
pong (Conn s :: Socket
s) = do
  BaseCommand -> m ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest BaseCommand
P.pong
  Socket -> BaseCommand -> m ()
forall (m :: * -> *). MonadIO m => Socket -> BaseCommand -> m ()
sendSimpleCmd Socket
s BaseCommand
P.pong

------ Payload commands ------

send
  :: Connection
  -> Chan Response
  -> ProducerId
  -> SeqId
  -> PulsarMessage
  -> IO ()
send :: Connection
-> Chan Response -> ProducerId -> SeqId -> PulsarMessage -> IO ()
send (Conn s :: Socket
s) chan :: Chan Response
chan (PId pid :: Word64
pid) (SeqId sid :: Word64
sid) (PulsarMessage msg :: ByteString
msg) = do
  BaseCommand -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logRequest (BaseCommand -> IO ()) -> BaseCommand -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> BaseCommand
P.send Word64
pid Word64
sid
  Socket -> BaseCommand -> MessageMetadata -> Maybe Payload -> IO ()
forall (m :: * -> *).
MonadIO m =>
Socket -> BaseCommand -> MessageMetadata -> Maybe Payload -> m ()
sendPayloadCmd Socket
s (Word64 -> Word64 -> BaseCommand
P.send Word64
pid Word64
sid) MessageMetadata
P.messageMetadata (Payload -> Maybe Payload
forall a. a -> Maybe a
Just (Payload -> Maybe Payload) -> Payload -> Maybe Payload
forall a b. (a -> b) -> a -> b
$ ByteString -> Payload
Payload ByteString
msg)
  IO ()
confirmReception
 where
  confirmReception :: IO ()
confirmReception = do
    Response
resp <- Chan Response -> IO Response
forall (m :: * -> *) a. MonadIO m => Chan a -> m a
readChan Chan Response
chan
    let cmd' :: Maybe CommandSendReceipt
cmd'    = Response -> BaseCommand
getCommand Response
resp BaseCommand
-> FoldLike
     (Maybe CommandSendReceipt)
     BaseCommand
     BaseCommand
     (Maybe CommandSendReceipt)
     (Maybe CommandSendReceipt)
-> Maybe CommandSendReceipt
forall s a t b. s -> FoldLike a s t a b -> a
^. FoldLike
  (Maybe CommandSendReceipt)
  BaseCommand
  BaseCommand
  (Maybe CommandSendReceipt)
  (Maybe CommandSendReceipt)
forall (f :: * -> *) s a.
(Functor f, HasField s "maybe'sendReceipt" a) =>
LensLike' f s a
F.maybe'sendReceipt
        pid' :: Maybe Word64
pid'    = FoldLike Word64 CommandSendReceipt CommandSendReceipt Word64 Word64
-> CommandSendReceipt -> Word64
forall a s t b. FoldLike a s t a b -> s -> a
view FoldLike Word64 CommandSendReceipt CommandSendReceipt Word64 Word64
forall (f :: * -> *) s a.
(Functor f, HasField s "producerId" a) =>
LensLike' f s a
F.producerId (CommandSendReceipt -> Word64)
-> Maybe CommandSendReceipt -> Maybe Word64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe CommandSendReceipt
cmd'
        sid' :: Maybe Word64
sid'    = FoldLike Word64 CommandSendReceipt CommandSendReceipt Word64 Word64
-> CommandSendReceipt -> Word64
forall a s t b. FoldLike a s t a b -> s -> a
view FoldLike Word64 CommandSendReceipt CommandSendReceipt Word64 Word64
forall (f :: * -> *) s a.
(Functor f, HasField s "sequenceId" a) =>
LensLike' f s a
F.sequenceId (CommandSendReceipt -> Word64)
-> Maybe CommandSendReceipt -> Maybe Word64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe CommandSendReceipt
cmd'
        rewrite :: IO ()
rewrite = Chan Response -> Response -> IO ()
forall (m :: * -> *) a. MonadIO m => Chan a -> a -> m ()
writeChan Chan Response
chan Response
resp
        loop :: IO ()
loop    = IO ()
confirmReception
        checkEq :: (a, Word64, Word64) -> IO ()
checkEq (_, pd :: Word64
pd, sd :: Word64
sd) | Word64
pd Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
pid Bool -> Bool -> Bool
&& Word64
sd Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
sid = Response -> IO ()
forall (m :: * -> *) a. (MonadIO m, Show a) => a -> m ()
logResponse Response
resp
                            | Bool
otherwise              = IO ()
rewrite IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
loop
    IO ()
-> ((CommandSendReceipt, Word64, Word64) -> IO ())
-> Maybe (CommandSendReceipt, Word64, Word64)
-> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO ()
loop (CommandSendReceipt, Word64, Word64) -> IO ()
forall a. (a, Word64, Word64) -> IO ()
checkEq (Maybe (CommandSendReceipt, Word64, Word64) -> IO ())
-> Maybe (CommandSendReceipt, Word64, Word64) -> IO ()
forall a b. (a -> b) -> a -> b
$ (,,) (CommandSendReceipt
 -> Word64 -> Word64 -> (CommandSendReceipt, Word64, Word64))
-> Maybe CommandSendReceipt
-> Maybe (Word64 -> Word64 -> (CommandSendReceipt, Word64, Word64))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe CommandSendReceipt
cmd' Maybe (Word64 -> Word64 -> (CommandSendReceipt, Word64, Word64))
-> Maybe Word64
-> Maybe (Word64 -> (CommandSendReceipt, Word64, Word64))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Word64
pid' Maybe (Word64 -> (CommandSendReceipt, Word64, Word64))
-> Maybe Word64 -> Maybe (CommandSendReceipt, Word64, Word64)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Word64
sid'