SMPClient returns errors via ExceptT (#13)

This commit is contained in:
Evgeny Poberezkin
2021-01-13 19:49:45 +00:00
committed by GitHub
parent c72deeda28
commit 3ad0bffaab
3 changed files with 25 additions and 27 deletions
+1
View File
@@ -27,6 +27,7 @@ dependencies:
- template-haskell == 2.15.*
- text == 1.2.*
- time == 1.9.*
- transformers == 0.5.*
- unliftio == 0.2.*
- unliftio-core == 0.1.*
+12 -17
View File
@@ -14,6 +14,7 @@ import Control.Monad.Except
import Control.Monad.IO.Unlift
import Control.Monad.Reader
import Crypto.Random
import Data.Bifunctor (first)
import qualified Data.Map as M
import Simplex.Messaging.Agent.Env.SQLite
import Simplex.Messaging.Agent.Store
@@ -79,6 +80,15 @@ withStore action = do
handleInternal :: (MonadError StoreError m') => SomeException -> m' a
handleInternal _ = throwError SEInternal
liftSMP :: (MonadUnliftIO m, MonadError ErrorType m) => ExceptT SMPClientError IO a -> m a
liftSMP action =
liftIO (first smpClientError <$> runExceptT action) >>= liftEither
where
smpClientError :: SMPClientError -> ErrorType
smpClientError = \case
SMPServerError e -> SMP e
_ -> INTERNAL -- TODO handle other errors
processCommand ::
forall m.
(MonadUnliftIO m, MonadReader Env m, MonadError ErrorType m) =>
@@ -97,10 +107,7 @@ processCommand AgentClient {sndQ, smpClients} (corrId, connAlias, cmd) =
g <- asks idsDrg
recipientKey <- atomically $ randomBytes 16 g -- TODO replace with cryptographic key pair
let rcvPrivateKey = recipientKey
(recipientId, senderId) <-
liftIO (createSMPQueue c recipientKey)
`E.catch` smpClientError
`E.catch` replyError INTERNAL
(recipientId, senderId) <- liftSMP $ createSMPQueue c recipientKey
encryptKey <- atomically $ randomBytes 16 g -- TODO replace with cryptographic key pair
let decryptKey = encryptKey
withStore $ \st ->
@@ -140,22 +147,10 @@ processCommand AgentClient {sndQ, smpClients} (corrId, connAlias, cmd) =
status = New,
ackMode = AckMode On
}
liftIO (sendSMPMessage c "" senderId msg)
`E.catch` smpClientError
-- `E.catch` replyError INTERNAL
-- TODO the problem here is that while the intention of the 2nd catch was to catch
-- all other exceptions, because smpClientError "throwError" via left channel
-- and of how ExceptT instance of UnliftIO is implemented, the second `catch` catches
-- Left channel... The only solution is to use runtime exceptions and not ExceptT
liftSMP $ sendSMPMessage c "" senderId msg
withStore $ \st -> updateQueueStatus st connAlias SND Confirmed
respond OK
smpClientError :: SMPClientError -> m a
smpClientError = \case
SMPServerError e -> throwError $ SMP e
_ -> throwError INTERNAL
-- TODO
replyError :: ErrorType -> SomeException -> m a
replyError err e = do
liftIO . putStrLn $ "Exception: " ++ show e -- TODO remove
+12 -10
View File
@@ -21,6 +21,7 @@ import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Exception
import Control.Monad
import Control.Monad.Trans.Except
import qualified Data.ByteString.Char8 as B
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
@@ -84,7 +85,10 @@ getSMPClient SMPServer {host, port} SMPClientConfig {qSize, defaultPort} = do
modifyTVar sentCommands $ M.delete corrId
putTMVar responseVar $
if queueId == qId
then either (Left . SMPResponseError) Right respOrErr
then case respOrErr of
Left e -> Left $ SMPResponseError e
Right (Cmd _ (ERR e)) -> Left $ SMPServerError e
Right r -> Right r
else Left SMPQueueIdError
data SMPClientError
@@ -96,25 +100,23 @@ data SMPClientError
| SMPClientError
deriving (Eq, Show, Exception)
createSMPQueue :: SMPClient -> RecipientKey -> IO (RecipientId, SenderId)
createSMPQueue :: SMPClient -> RecipientKey -> ExceptT SMPClientError IO (RecipientId, SenderId)
createSMPQueue c rKey = do
sendSMPCommand c "" "" (Cmd SRecipient $ NEW rKey) >>= \case
Cmd _ (IDS rId sId) -> return (rId, sId)
Cmd _ (ERR e) -> throwIO $ SMPServerError e
_ -> throwIO SMPUnexpectedResponse
_ -> throwE SMPUnexpectedResponse
sendSMPMessage :: SMPClient -> SenderKey -> QueueId -> MsgBody -> IO ()
sendSMPMessage :: SMPClient -> SenderKey -> QueueId -> MsgBody -> ExceptT SMPClientError IO ()
sendSMPMessage c sKey qId msg = do
sendSMPCommand c sKey qId (Cmd SSender $ SEND msg) >>= \case
Cmd _ OK -> return ()
Cmd _ (ERR e) -> throwIO $ SMPServerError e
_ -> throwIO SMPUnexpectedResponse
_ -> throwE SMPUnexpectedResponse
sendSMPCommand :: SMPClient -> PrivateKey -> QueueId -> Cmd -> IO Cmd
sendSMPCommand SMPClient {sndQ, sentCommands, clientCorrId} pKey qId cmd = do
sendSMPCommand :: SMPClient -> PrivateKey -> QueueId -> Cmd -> ExceptT SMPClientError IO Cmd
sendSMPCommand SMPClient {sndQ, sentCommands, clientCorrId} pKey qId cmd = ExceptT $ do
corrId <- atomically getNextCorrId
t <- signTransmission (corrId, qId, cmd)
atomically (send corrId t) >>= atomically . takeTMVar >>= either throwIO return
atomically (send corrId t) >>= atomically . takeTMVar
where
getNextCorrId :: STM CorrId
getNextCorrId = do