{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE StandaloneDeriving #-}
module Database.EventStore.Internal.Operation where
import Prelude (String)
import Data.ProtocolBuffers
import Data.Serialize (runPut, runGet)
import Database.EventStore.Internal.Command
import Database.EventStore.Internal.Control
import Database.EventStore.Internal.Prelude hiding ((.), id)
import Database.EventStore.Internal.Stream
import Database.EventStore.Internal.Types
newtype Mailbox = Mailbox (Chan (Either OperationError Package))
mailboxSendPkg :: MonadBase IO m => Mailbox -> Package -> m ()
mailboxSendPkg (Mailbox chan) pkg = writeChan chan (Right pkg)
mailboxFail :: MonadBase IO m => Mailbox -> OperationError -> m ()
mailboxFail (Mailbox chan) e = writeChan chan (Left e)
mailboxRead :: MonadBase IO m => Mailbox -> m (Either OperationError Package)
mailboxRead (Mailbox chan) = readChan chan
mailboxReadDecoded
:: (MonadBase IO m, Decode resp)
=> Mailbox
-> m (Either OperationError resp)
mailboxReadDecoded (Mailbox chan)
= fmap (decodePkg =<<) $ readChan chan
mailboxNew :: MonadBase IO m => m Mailbox
mailboxNew = Mailbox <$> newChan
createPkg
:: (Encode msg, MonadIO m)
=> Command
-> Maybe Credentials
-> msg
-> m Package
createPkg cmd creds msg
= do pkgId <- freshUUID
let dat = runPut $ encodeMessage msg
pkg
= Package
{ packageCmd = cmd
, packageCorrelation = pkgId
, packageData = dat
, packageCred = creds
}
pure pkg
decodePkg :: Decode msg => Package -> Either OperationError msg
decodePkg pkg
= case runGet decodeMessage (packageData pkg) of
Left e -> Left $ ProtobufDecodingError e
Right resp -> Right resp
data OperationError
= WrongExpectedVersion !Text !ExpectedVersion
| StreamDeleted !StreamName
| InvalidTransaction
| forall t. AccessDenied !(StreamId t)
| InvalidServerResponse !Command !Command
| ProtobufDecodingError !String
| ServerError !(Maybe Text)
| InvalidOperation !Text
| StreamNotFound !StreamName
| NotAuthenticatedOp
| Aborted
| ConnectionHasDropped
deriving Typeable
deriving instance Show OperationError
instance Exception OperationError
data OpResult
= OP_SUCCESS
| OP_PREPARE_TIMEOUT
| OP_COMMIT_TIMEOUT
| OP_FORWARD_TIMEOUT
| OP_WRONG_EXPECTED_VERSION
| OP_STREAM_DELETED
| OP_INVALID_TRANSACTION
| OP_ACCESS_DENIED
deriving (Eq, Enum, Show)
data Lifetime
= OneTime
| KeepAlive !Command
data Loop a
= Loop
| Break !a
data LoopS s a
= LoopS !s
| BreakS !a
keepLooping :: Monad m => m (Loop a) -> m a
keepLooping action
= go
where
go = do result <- action
case result of
Loop -> go
Break a -> pure a
keepLoopingS :: Monad m => s -> (s -> m (LoopS s a)) -> m a
keepLoopingS seed action
= go seed
where
go cur
= do result <- action cur
case result of
LoopS next
-> go next
BreakS a
-> pure a