Skip to content

Commit db4b27e

Browse files
authored
agent: create user with option to enable client service (#1684)
* agent: create user with option to enable client service * handle HTTP2 errors * do not catch async exceptions
1 parent 9e813c2 commit db4b27e

File tree

8 files changed

+57
-32
lines changed

8 files changed

+57
-32
lines changed

src/Simplex/FileTransfer/Client.hs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import Simplex.Messaging.Client
4747
transportClientConfig,
4848
clientSocksCredentials,
4949
unexpectedResponse,
50+
clientHandlers,
5051
useWebPort,
5152
)
5253
import qualified Simplex.Messaging.Crypto as C
@@ -61,7 +62,6 @@ import Simplex.Messaging.Protocol
6162
SenderId,
6263
pattern NoEntity,
6364
NetworkError (..),
64-
toNetworkError,
6565
)
6666
import Simplex.Messaging.Transport (ALPN, CertChainPubKey (..), HandshakeError (..), THandleAuth (..), THandleParams (..), TransportError (..), TransportPeer (..), defaultSupportedParams)
6767
import Simplex.Messaging.Transport.Client (TransportClientConfig (..), TransportHost)
@@ -70,8 +70,10 @@ import Simplex.Messaging.Transport.HTTP2.Client
7070
import Simplex.Messaging.Transport.HTTP2.File
7171
import Simplex.Messaging.Util (liftEitherWith, liftError', tshow, whenM)
7272
import Simplex.Messaging.Version
73-
import UnliftIO
73+
import System.IO (IOMode (..), SeekMode (..), hSeek, withFile)
74+
import System.Timeout (timeout)
7475
import UnliftIO.Directory
76+
import UnliftIO.STM
7577

7678
data XFTPClient = XFTPClient
7779
{ http2Client :: HTTP2Client,
@@ -261,13 +263,11 @@ downloadXFTPChunk g c@XFTPClient {config} rpKey fId chunkSpec@XFTPRcvChunkSpec {
261263
let dhSecret = C.dh' sDhKey rpDhKey
262264
cbState <- liftEither . first PCECryptoError $ LC.cbInit dhSecret cbNonce
263265
let t = chunkTimeout config chunkSize
264-
ExceptT (sequence <$> (t `timeout` (download cbState `catches` errors))) >>= maybe (throwE PCEResponseTimeout) pure
266+
ExceptT (sequence <$> (t `timeout` (download cbState `E.catches` handlers))) >>= maybe (throwE PCEResponseTimeout) pure
265267
where
266-
errors =
267-
[ Handler $ \(e :: H.HTTP2Error) -> pure $ Left $ PCENetworkError $ NEConnectError $ displayException e,
268-
Handler $ \(e :: IOException) -> pure $ Left $ PCEIOError $ E.displayException e,
269-
Handler $ \(e :: SomeException) -> pure $ Left $ PCENetworkError $ toNetworkError e
270-
]
268+
handlers =
269+
E.Handler (\(e :: H.HTTP2Error) -> pure $ Left $ PCENetworkError $ NEConnectError $ E.displayException e)
270+
: clientHandlers
271271
download cbState =
272272
runExceptT . withExceptT PCEResponseError $
273273
receiveEncFile chunkPart cbState chunkSpec `catchError` \e ->

src/Simplex/Messaging/Agent.hs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,8 @@ resumeAgentClient :: AgentClient -> IO ()
337337
resumeAgentClient c = atomically $ writeTVar (active c) True
338338
{-# INLINE resumeAgentClient #-}
339339

340-
createUser :: AgentClient -> NonEmpty (ServerCfg 'PSMP) -> NonEmpty (ServerCfg 'PXFTP) -> AE UserId
341-
createUser c = withAgentEnv c .: createUser' c
340+
createUser :: AgentClient -> Bool -> NonEmpty (ServerCfg 'PSMP) -> NonEmpty (ServerCfg 'PXFTP) -> AE UserId
341+
createUser c = withAgentEnv c .:. createUser' c
342342
{-# INLINE createUser #-}
343343

344344
-- | Delete user record optionally deleting all user's connections on SMP servers
@@ -754,14 +754,23 @@ logConnection c connected =
754754
let event = if connected then "connected to" else "disconnected from"
755755
in logInfo $ T.unwords ["client", tshow (clientId c), event, "Agent"]
756756

757-
createUser' :: AgentClient -> NonEmpty (ServerCfg 'PSMP) -> NonEmpty (ServerCfg 'PXFTP) -> AM UserId
758-
createUser' c smp xftp = do
757+
createUser' :: AgentClient -> Bool -> NonEmpty (ServerCfg 'PSMP) -> NonEmpty (ServerCfg 'PXFTP) -> AM UserId
758+
createUser' c useService smp xftp = do
759759
liftIO $ checkUserServers "createUser SMP" smp
760760
liftIO $ checkUserServers "createUser XFTP" xftp
761761
userId <- withStore' c createUserRecord
762-
atomically $ TM.insert userId (mkUserServers smp) $ smpServers c
763-
atomically $ TM.insert userId (mkUserServers xftp) $ xftpServers c
764-
atomically $ TM.insert userId False $ useClientServices c
762+
ok <- atomically $ do
763+
(cfg, _) <- readTVar $ useNetworkConfig c
764+
if useService && sessionMode cfg == TSMEntity
765+
then pure False
766+
else do
767+
TM.insert userId (mkUserServers smp) $ smpServers c
768+
TM.insert userId (mkUserServers xftp) $ xftpServers c
769+
TM.insert userId useService $ useClientServices c
770+
pure True
771+
unless ok $ do
772+
withStore c (`deleteUserRecord` userId)
773+
throwE $ CMD PROHIBITED "createUser'"
765774
pure userId
766775

767776
deleteUser' :: AgentClient -> UserId -> Bool -> AM ()

src/Simplex/Messaging/Client.hs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ module Simplex.Messaging.Client
107107
smpProxyError,
108108
smpErrorClientNotice,
109109
textToHostMode,
110+
clientHandlers,
110111
ServerTransmissionBatch,
111112
ServerTransmission (..),
112113
ClientCommand,
@@ -129,7 +130,7 @@ import Control.Applicative ((<|>))
129130
import Control.Concurrent (ThreadId, forkFinally, forkIO, killThread, mkWeakThreadId)
130131
import Control.Concurrent.Async
131132
import Control.Concurrent.STM
132-
import Control.Exception (Exception, SomeException)
133+
import Control.Exception (Exception, Handler (..), IOException, SomeAsyncException, SomeException)
133134
import qualified Control.Exception as E
134135
import Control.Logger.Simple
135136
import Control.Monad
@@ -567,7 +568,7 @@ getProtocolClient g nm transportSession@(_, srv, _) cfg@ProtocolClientConfig {qS
567568
case chooseTransportHost networkConfig (host srv) of
568569
Right useHost ->
569570
(getCurrentTime >>= mkProtocolClient useHost >>= runClient useTransport useHost)
570-
`E.catch` \(e :: SomeException) -> pure $ Left $ PCEIOError $ E.displayException e
571+
`E.catches` clientHandlers
571572
Left e -> pure $ Left e
572573
where
573574
NetworkConfig {tcpConnectTimeout, tcpTimeout, smpPingInterval} = networkConfig
@@ -719,6 +720,13 @@ getProtocolClient g nm transportSession@(_, srv, _) cfg@ProtocolClientConfig {qS
719720
Left e -> logError $ "SMP client error: " <> tshow e
720721
Right _ -> logWarn "SMP client unprocessed event"
721722

723+
clientHandlers :: [Handler (Either (ProtocolClientError e) a)]
724+
clientHandlers =
725+
[ Handler $ \(e :: IOException) -> pure $ Left $ PCEIOError $ E.displayException e,
726+
Handler $ \(e :: SomeAsyncException) -> E.throwIO e,
727+
Handler $ \(e :: SomeException) -> pure $ Left $ PCENetworkError $ toNetworkError e
728+
]
729+
722730
useWebPort :: NetworkConfig -> [HostName] -> ProtocolServer p -> Bool
723731
useWebPort cfg presetDomains ProtocolServer {host = h :| _} = case smpWebPortServers cfg of
724732
SWPAll -> True

src/Simplex/Messaging/Client/Agent.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ where
3737
import Control.Concurrent (forkIO)
3838
import Control.Concurrent.Async (Async, uninterruptibleCancel)
3939
import Control.Concurrent.STM (retry)
40+
import qualified Control.Exception as E
4041
import Control.Logger.Simple
4142
import Control.Monad
4243
import Control.Monad.Except
@@ -83,7 +84,6 @@ import Simplex.Messaging.Transport
8384
import Simplex.Messaging.Util (catchAll_, ifM, safeDecodeUtf8, toChunks, tshow, whenM, ($>>=), (<$$>))
8485
import System.Timeout (timeout)
8586
import UnliftIO (async)
86-
import qualified UnliftIO.Exception as E
8787
import UnliftIO.STM
8888

8989
type SMPClientVar = SessionVar (Either (SMPClientError, Maybe UTCTime) (OwnServer, SMPClient))
@@ -226,7 +226,7 @@ getSMPServerClient'' ca@SMPClientAgent {agentCfg, smpClients, smpSessions, worke
226226

227227
newSMPClient :: SMPClientVar -> IO (Either SMPClientError (OwnServer, SMPClient))
228228
newSMPClient v = do
229-
r <- connectClient ca srv v `E.catch` \(e :: E.SomeException) -> pure $ Left $ PCEIOError $ E.displayException e
229+
r <- connectClient ca srv v `E.catches` clientHandlers
230230
case r of
231231
Right smp -> do
232232
logInfo . decodeUtf8 $ "Agent connected to " <> showServer srv
@@ -324,7 +324,7 @@ reconnectClient ca@SMPClientAgent {active, agentCfg, smpSubWorkers, workerSeq} s
324324
(Just <$> getSessVar workerSeq srv smpSubWorkers ts)
325325
newSubWorker :: SessionVar (Async ()) -> IO ()
326326
newSubWorker v = do
327-
a <- async $ void (E.tryAny runSubWorker) >> atomically (cleanup v)
327+
a <- async $ void (E.try @E.SomeException runSubWorker) >> atomically (cleanup v)
328328
atomically $ putTMVar (sessionVar v) a
329329
runSubWorker =
330330
withRetryInterval (reconnectInterval agentCfg) $ \_ loop -> do

src/Simplex/Messaging/Notifications/Server/Store/Postgres.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ removeServiceAndAssociations st srv = do
586586
withDB "removeServiceAndAssociations" st $ \db -> runExceptT $ do
587587
srvId <- ExceptT $ getServerId db
588588
subsCount <- liftIO $ removeServiceAssociation_ db srvId
589-
liftIO $ removeServerService db srvId
589+
liftIO $ void $ removeServerService db srvId
590590
pure (srvId, fromIntegral subsCount)
591591
where
592592
getServerId db =

src/Simplex/Messaging/Server.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ import Network.Socket (ServiceName, Socket, socketToHandle)
9797
import qualified Network.TLS as TLS
9898
import Numeric.Natural (Natural)
9999
import Simplex.Messaging.Agent.Lock
100-
import Simplex.Messaging.Client (ProtocolClient (thParams), ProtocolClientError (..), SMPClient, SMPClientError, forwardSMPTransmission, smpProxyError, temporaryClientError)
100+
import Simplex.Messaging.Client (ProtocolClient (thParams), ProtocolClientError (..), SMPClient, SMPClientError, clientHandlers, forwardSMPTransmission, smpProxyError, temporaryClientError)
101101
import Simplex.Messaging.Client.Agent (OwnServer, SMPClientAgent (..), SMPClientAgentEvent (..), closeSMPClientAgent, getSMPServerClient'', isOwnServer, lookupSMPServerClient, getConnectedSMPServerClient)
102102
import qualified Simplex.Messaging.Crypto as C
103103
import Simplex.Messaging.Encoding
@@ -1386,7 +1386,7 @@ client
13861386
Just r -> Just <$> proxyServerResponse a r
13871387
Nothing ->
13881388
forkProxiedCmd $
1389-
liftIO (runExceptT (getSMPServerClient'' a srv) `E.catch` (\(e :: SomeException) -> pure $ Left $ PCEIOError $ E.displayException e))
1389+
liftIO (runExceptT (getSMPServerClient'' a srv) `E.catches` clientHandlers)
13901390
>>= proxyServerResponse a
13911391
proxyServerResponse :: SMPClientAgent 'Sender -> Either SMPClientError (OwnServer, SMPClient) -> M s BrokerMsg
13921392
proxyServerResponse a smp_ = do
@@ -1423,7 +1423,7 @@ client
14231423
inc own pRequests
14241424
if v >= sendingProxySMPVersion
14251425
then forkProxiedCmd $ do
1426-
liftIO (runExceptT (forwardSMPTransmission smp corrId fwdV pubKey encBlock) `E.catch` (\(e :: SomeException) -> pure $ Left $ PCEIOError $ E.displayException e)) >>= \case
1426+
liftIO (runExceptT (forwardSMPTransmission smp corrId fwdV pubKey encBlock) `E.catches` clientHandlers) >>= \case
14271427
Right r -> PRES r <$ inc own pSuccesses
14281428
Left e -> ERR (smpProxyError e) <$ case e of
14291429
PCEProtocolError {} -> inc own pSuccesses

src/Simplex/Messaging/Transport/HTTP2/Client.hs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
module Simplex.Messaging.Transport.HTTP2.Client where
1212

1313
import Control.Concurrent.Async
14+
import Control.Exception (Handler (..), IOException, SomeAsyncException, SomeException)
1415
import qualified Control.Exception as E
1516
import Control.Monad
1617
import Data.Functor (($>))
@@ -92,6 +93,13 @@ defaultHTTP2ClientConfig =
9293
data HTTP2ClientError = HCResponseTimeout | HCNetworkError NetworkError | HCIOError String
9394
deriving (Show)
9495

96+
httpClientHandlers :: [Handler (Either HTTP2ClientError a)]
97+
httpClientHandlers =
98+
[ Handler $ \(e :: IOException) -> pure $ Left $ HCIOError $ E.displayException e,
99+
Handler $ \(e :: SomeAsyncException) -> E.throwIO e,
100+
Handler $ \(e :: SomeException) -> pure $ Left $ HCNetworkError $ toNetworkError e
101+
]
102+
95103
getHTTP2Client :: HostName -> ServiceName -> Maybe XS.CertificateStore -> HTTP2ClientConfig -> IO () -> IO (Either HTTP2ClientError HTTP2Client)
96104
getHTTP2Client host port = getVerifiedHTTP2Client Nothing (THDomainName host) port Nothing
97105

@@ -110,7 +118,7 @@ attachHTTP2Client config host port disconnected bufferSize tls = getVerifiedHTTP
110118
getVerifiedHTTP2ClientWith :: forall p. TransportPeerI p => HTTP2ClientConfig -> TransportHost -> ServiceName -> IO () -> ((TLS p -> H.Client HTTP2Response) -> IO HTTP2Response) -> IO (Either HTTP2ClientError HTTP2Client)
111119
getVerifiedHTTP2ClientWith config host port disconnected setup =
112120
(mkHTTPS2Client >>= runClient)
113-
`E.catch` \(e :: E.SomeException) -> pure $ Left $ HCIOError $ E.displayException e
121+
`E.catches` httpClientHandlers
114122
where
115123
mkHTTPS2Client :: IO HClient
116124
mkHTTPS2Client = do
@@ -176,9 +184,9 @@ sendRequest HTTP2Client {client_ = HClient {config, reqQ}} req reqTimeout_ = do
176184
sendRequestDirect :: HTTP2Client -> Request -> Maybe Int -> IO (Either HTTP2ClientError HTTP2Response)
177185
sendRequestDirect HTTP2Client {client_ = HClient {config, disconnected}, sendReq} req reqTimeout_ = do
178186
let reqTimeout = http2RequestTimeout config reqTimeout_
179-
reqTimeout `timeout` E.try (sendReq req process) >>= \case
187+
reqTimeout `timeout` ((Right <$> sendReq req process) `E.catches` httpClientHandlers) >>= \case
180188
Just (Right r) -> pure $ Right r
181-
Just (Left (e :: E.SomeException)) -> disconnected $> Left (HCIOError $ E.displayException e)
189+
Just (Left e) -> disconnected $> Left e
182190
Nothing -> pure $ Left HCResponseTimeout
183191
where
184192
process r = do

tests/AgentTests/FunctionalAPITests.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ testUpdateConnectionUserId :: HasCallStack => IO ()
10181018
testUpdateConnectionUserId =
10191019
withAgentClients2 $ \alice bob -> runRight_ $ do
10201020
(connId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe
1021-
newUserId <- createUser alice [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
1021+
newUserId <- createUser alice False [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
10221022
_ <- changeConnectionUser alice 1 connId newUserId
10231023
aliceId <- A.prepareConnectionToJoin bob 1 True qInfo PQSupportOn
10241024
sqSecured' <- A.joinConnection bob NRMInteractive 1 aliceId True qInfo "bob's connInfo" PQSupportOn SMSubscribe
@@ -3001,7 +3001,7 @@ testUsers =
30013001
withAgentClients2 $ \a b -> runRight_ $ do
30023002
(aId, bId) <- makeConnection a b
30033003
exchangeGreetings a bId b aId
3004-
auId <- createUser a [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
3004+
auId <- createUser a False [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
30053005
(aId', bId') <- makeConnectionForUsers a auId b 1
30063006
exchangeGreetings a bId' b aId'
30073007
deleteUser a auId True
@@ -3016,7 +3016,7 @@ testDeleteUserQuietly =
30163016
withAgentClients2 $ \a b -> runRight_ $ do
30173017
(aId, bId) <- makeConnection a b
30183018
exchangeGreetings a bId b aId
3019-
auId <- createUser a [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
3019+
auId <- createUser a False [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
30203020
(aId', bId') <- makeConnectionForUsers a auId b 1
30213021
exchangeGreetings a bId' b aId'
30223022
deleteUser a auId False
@@ -3028,7 +3028,7 @@ testUsersNoServer ps = withAgentClientsCfg2 aCfg agentCfg $ \a b -> do
30283028
(aId, bId, auId, _aId', bId') <- withSmpServerStoreLogOn ps testPort $ \_ -> runRight $ do
30293029
(aId, bId) <- makeConnection a b
30303030
exchangeGreetings a bId b aId
3031-
auId <- createUser a [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
3031+
auId <- createUser a False [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
30323032
(aId', bId') <- makeConnectionForUsers a auId b 1
30333033
exchangeGreetings a bId' b aId'
30343034
pure (aId, bId, auId, aId', bId')
@@ -3628,7 +3628,7 @@ testTwoUsers = withAgentClients2 $ \a b -> do
36283628
("", "", UP _ _) <- nGet a
36293629
a `hasClients` 1
36303630

3631-
aUserId2 <- createUser a [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
3631+
aUserId2 <- createUser a False [noAuthSrvCfg testSMPServer] [noAuthSrvCfg testXFTPServer]
36323632
(aId2, bId2) <- makeConnectionForUsers a aUserId2 b 1
36333633
exchangeGreetings a bId2 b aId2
36343634
(aId2', bId2') <- makeConnectionForUsers a aUserId2 b 1

0 commit comments

Comments
 (0)