on master help sign in
WIP existential request/response

basic test passes

commit26ff2259d43988c5f9850d79700b1778922ef56f authorAgentM <agentm@themactionfaction.com> dateSun 29 Nov 2020, 21:25 (6 years ago) parent08578c1
4 files changed+218−129
README.markdown+2−2 src/Network/RPC/Curryer/Client.hs+50−55 src/Network/RPC/Curryer/Server.hs+146−60 test/Curryer/Test/Basic.hs+20−12
README.markdown+2−2
@@ -1,6 +1,6 @@
11# Curryer - Fast Haskell-to-Haskell RPC
22
3−Curryer (pun intended) is a fast, Haskell-exclusive RPC (remote procedure call) library. By using the latest Haskell serialization and streaming libraries, curryer aims to the fastest and easiest means of communicating between Haskell-based processes.
3+Curryer (pun intended) is a fast, Haskell-exclusive RPC (remote procedure call) library. By using the latest Haskell serialization and streaming libraries, curryer aims to be the fastest and easiest means of communicating between Haskell-based processes.
44
55Curryer is inspired by the now unmaintained [distributed-process](https://hackage.haskell.org/package/distributed-process) library.
66
@@ -9,4 +9,4 @@ Curryer is inspired by the now unmaintained [distributed-process](https://hackag
99* blocking and non-blocking remote function calls
1010* asynchronous server-to-client callbacks (for server-initiated notifications)
1111* timeouts
12−* utilizes versionable shared ADT instead of shared function `StaticPtr`s
12+* utilizes versionable shared ADT for communication instead of shared function `StaticPtr`s
src/Network/RPC/Curryer/Client.hs+50−55
@@ -11,28 +11,24 @@ import Control.Concurrent.MVar
1111import GHC.Conc
1212import Data.Time.Clock
1313import System.Timeout
14−import Data.Proxy
1514
16−type SyncMap a = STMMap.Map UUID (MVar (Either ConnectionError a), UTCTime)
15+type SyncMap = STMMap.Map UUID (MVar (Either ConnectionError BinaryMessage), UTCTime)
16+
1717-- the request map holds
18−data Connection a = Connection { _conn_sockLock :: Locking Socket,
19− _conn_asyncThread :: Async (),
20− _conn_syncmap :: SyncMap a
21− }
18+data Connection = Connection { _conn_sockLock :: Locking Socket,
19+ _conn_asyncThread :: Async (),
20+ _conn_syncmap :: SyncMap
21+ }
2222
23−connect :: forall clientmsg. (Serialise clientmsg) =>
24− AsyncMessageHandler clientmsg ->
23+connect ::
24+ --AsyncMessageHandler ->
2525 HostAddr ->
2626 PortNumber ->
27− IO (Connection clientmsg)
28−connect notificationCallback hostAddr portNum = do
27+ IO Connection
28+connect hostAddr portNum = do
2929 sock <- TCP.connect hostAddr portNum
3030 syncmap <- STMMap.newIO
31− let decoder :: Decoder (Message clientmsg)
32− decoder = case getDecoder (schema (Proxy @(Message clientmsg))) of
33− Left err -> error (show err)
34− Right dec -> dec
35− asyncThread <- async (clientAsync sock syncmap decoder notificationCallback)
31+ asyncThread <- async (clientAsync sock syncmap)
3632 sockLock <- newLock sock
3733 pure (Connection {
3834 _conn_sockLock = sockLock,
@@ -40,63 +36,56 @@ connect notificationCallback hostAddr portNum = do
4036 _conn_syncmap = syncmap
4137 })
4238
43−close :: Connection a -> IO ()
39+close :: Connection -> IO ()
4440close conn = do
4541 withLock (_conn_sockLock conn) $ \sock ->
4642 Socket.close sock
4743 cancel (_conn_asyncThread conn)
4844
4945-- async thread for handling client-side incoming messages- dispatch to proper waiting thread or handler asynchronous notifications
50−clientAsync :: forall b. Serialise b =>
46+clientAsync ::
5147 Socket ->
52− SyncMap b ->
53− Decoder (Message b) ->
54− AsyncMessageHandler b ->
48+ SyncMap ->
49+ --AsyncMessageHandler ->
5550 IO ()
56−clientAsync sock syncmap decoder asyncHandler = do
57− -- ping proper thread to continue
58− let findRequest requestId =
59− atomically $ do
60− val' <- STMMap.lookup requestId syncmap
61− STMMap.delete requestId syncmap
62− pure val'
51+clientAsync sock syncmap = do
52+ lsock <- newLock sock
53+ drainSocketMessages sock (clientEnvelopeHandler lsock syncmap)
54+
55+--handles envelope responses from server
56+clientEnvelopeHandler ::
57+ Locking Socket
58+ -> SyncMap
59+ -> Envelope
60+ -> IO ()
61+clientEnvelopeHandler _ _ (Envelope _ RequestMessage _ _) = error "client received request"
62+clientEnvelopeHandler _ syncMap (Envelope _ ResponseMessage msgId binaryMessage) = do
63+ --find a matching response item
64+ match <- atomically $ do
65+ val' <- STMMap.lookup msgId syncMap
66+ STMMap.delete msgId syncMap
67+ pure val'
68+ case match of
69+ Nothing -> error ("dropping unrequested response " <> show msgId)
70+ Just (mVar, _) ->
71+ putMVar mVar (Right binaryMessage)
6372
64− let responseHandler responseMsg = do
65− --putStrLn "client-side message handler"
66− case responseMsg of
67− Response requestId val -> do
68− varval <- findRequest requestId
69− case varval of
70− Nothing -> error "dumped unrequested response"
71− Just (mVar,_) -> putMVar mVar (Right val)
72− AsyncRequest _ asyncMsg ->
73− asyncHandler asyncMsg
74− ResponseExpectedRequest{} -> error "dumped response expected request"
75− ExceptionResponse requestId excString -> do
76− varval <- findRequest requestId
77− case varval of
78− Nothing -> error "dumped unrequested exception response"
79− Just (mVar,_) -> putMVar mVar (Left (ExceptionError excString))
80− TimedOutResponse requestId -> do
81− varval <- findRequest requestId
82− case varval of
83− Nothing -> error "dumped unrequested timeout response"
84− Just (mVar,_) -> putMVar mVar (Left TimeoutError)
85− drainSocketMessages sock decoder responseHandler
8673
87−call :: (Serialise request, Serialise response) => Connection response -> request -> IO (Either ConnectionError response)
74+call :: (Serialise request, Serialise response) => Connection -> request -> IO (Either ConnectionError response)
8875call = callTimeout Nothing
8976
9077-- | Send a request to the remote server and returns a response.
91−callTimeout :: (Serialise request, Serialise response) => Maybe Int -> Connection response -> request -> IO (Either ConnectionError response)
78+callTimeout :: (Serialise request, Serialise response) => Maybe Int -> Connection -> request -> IO (Either ConnectionError response)
9279callTimeout mTimeout conn msg = do
80+ requestID <- UUID <$> UUIDBase.nextRandom
9381 let mVarMap = _conn_syncmap conn
94− requestID <- UUID <$> UUIDBase.nextRandom
82+ envelope = Envelope fprint RequestMessage requestID (serialise msg)
83+ fprint = fingerprint msg
9584 -- setup mvar to wait for response
9685 responseMVar <- newEmptyMVar
9786 now <- getCurrentTime
9887 atomically $ STMMap.insert (responseMVar, now) requestID mVarMap
99− sendMessage (ResponseExpectedRequest requestID mTimeout msg) (_conn_sockLock conn)
88+ sendEnvelope envelope (_conn_sockLock conn)
10089 let timeoutMicroseconds =
10190 case mTimeout of
10291 Just timeout' -> timeout' + 100 --add 100 ms to account for unknown network latency
@@ -107,11 +96,17 @@ callTimeout mTimeout conn msg = do
10796 --timeout
10897 Nothing ->
10998 pure (Left TimeoutError)
110− Just res -> pure res
111−
99+ Just (Left exc) -> error ("exception in client from server: " <> show exc)
100+ Just (Right binmsg) ->
101+ --TODO use decoder instead
102+ case deserialise binmsg of
103+ Left err -> error ("deserialise client error " <> show err)
104+ Right m -> pure (Right m)
105+{-
112106asyncCall :: (Serialise request, Serialise response) => Connection response -> request -> IO (Either ConnectionError ())
113107asyncCall conn msg = do
114108 requestID <- UUID <$> UUIDBase.nextRandom
115109 sendMessage (AsyncRequest requestID msg) (_conn_sockLock conn)
116110 pure (Right ())
117111
112+-}
src/Network/RPC/Curryer/Server.hs+146−60
@@ -1,4 +1,5 @@
1−{-# LANGUAGE DerivingVia, DeriveGeneric, RankNTypes, ScopedTypeVariables, MultiParamTypeClasses, OverloadedStrings, GeneralizedNewtypeDeriving, TypeApplications, CPP #-}
1+{-# LANGUAGE DerivingVia, DeriveGeneric, RankNTypes, ScopedTypeVariables, MultiParamTypeClasses, OverloadedStrings, GeneralizedNewtypeDeriving, TypeApplications, CPP, ExistentialQuantification, StandaloneDeriving #-}
2+{-# OPTIONS_GHC -fno-warn-orphans #-}
23{- HLINT ignore "Use lambda-case" -}
34module Network.RPC.Curryer.Server where
45import Streamly
@@ -7,11 +8,13 @@ import Streamly.Network.Socket
78import Streamly.Internal.Network.Socket (handleWithM)
89import Network.Socket as Socket
910import Network.Socket.ByteString as Socket
10−import Streamly.Internal.Data.Parser as P
11+import Streamly.Internal.Data.Parser as P hiding (concatMap)
1112import Codec.Winery
1213import Codec.Winery.Internal (varInt, decodeVarInt, getBytes)
1314import Codec.Winery.Class (mkExtractor)
1415import GHC.Generics
16+import GHC.Fingerprint
17+import Data.Typeable
1518import Control.Concurrent.MVar (MVar, newMVar, withMVar)
1619import Control.Exception
1720import Data.Function ((&))
@@ -23,14 +26,12 @@ import Streamly.Data.Fold as FL
2326import qualified Streamly.Internal.Data.Stream.IsStream as S
2427import qualified Data.Binary as B
2528import qualified Data.UUID as UUIDBase
26−import qualified Data.UUID.V4 as UUIDBase
2729
2830import qualified Network.RPC.Curryer.StreamlyAdditions as SA
29−import Control.Monad
31+--import Control.Monad
3032import Data.Hashable
31−import System.Timeout
33+--import System.Timeout
3234import qualified Network.ByteOrder as BO
33−import Data.Proxy
3435
3536-- for toArrayS conversion
3637{-import qualified Data.ByteString.Internal as BSI
@@ -39,6 +40,7 @@ import Foreign.ForeignPtr (plusForeignPtr)
3940import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
4041import GHC.Ptr (plusPtr)
4142-}
43+-- #define CURRYER_SHOW_BYTES 1
4244#if CURRYER_SHOW_BYTES == 1
4345import Debug.Trace
4446#endif
@@ -66,7 +68,28 @@ lockless (Locking _ a) = a
6668
6769type Timeout = Int
6870
69−data Message a = Response UUID a
71+type BinaryMessage = BS.ByteString
72+
73+--includes the fingerprint of the incoming data type (held in the BinaryMessage) to determine how to dispatch the message.
74+--add another envelope type for unencoded binary messages for any easy optimization for in-process communication
75+data Envelope = Envelope !Fingerprint !MessageType !UUID !BinaryMessage
76+ deriving (Generic, Show)
77+ deriving Serialise via WineryVariant Envelope
78+
79+deriving instance Generic Fingerprint
80+deriving via WineryVariant Fingerprint instance Serialise Fingerprint
81+
82+data MessageType = RequestMessage
83+ | ResponseMessage
84+ deriving (Generic, Show)
85+ deriving Serialise via WineryVariant MessageType
86+
87+data MessageHandlers =
88+ forall a b. (Show a, Serialise a, Serialise b) => MessageHandlers [RequestHandler a b]
89+
90+type RequestHandler a b = a -> IO b
91+
92+{-data Message a = Response UUID a
7093 | AsyncRequest UUID a
7194 | ResponseExpectedRequest UUID (Maybe Timeout) a
7295 | TimedOutResponse UUID
@@ -75,12 +98,13 @@ data Message a = Response UUID a
7598 deriving Serialise via WineryVariant (Message a)
7699
77100-- | The response type
101+
78102data HandlerResponse a = NoResponse
79103 | HandlerResponse a
80104 | HandlerException String
81105 deriving Generic
82106 deriving Serialise via WineryVariant (HandlerResponse a)
83−
107+-}
84108--avoid orphan instance
85109newtype UUID = UUID { _unUUID :: UUIDBase.UUID }
86110 deriving (Show, Eq, B.Binary, Hashable)
@@ -113,56 +137,121 @@ allHostAddrs = (0,0,0,0)
113137localHostAddr = (127,0,0,1)
114138
115139-- Each message is length-prefixed by a 32-bit unsigned length.
116−messageBoundaryP :: Parser IO Word8 BS.ByteString
117−messageBoundaryP = do
140+envelopeP :: Parser IO Word8 Envelope
141+envelopeP = do
142+ let s = FL.toList
143+ msgTypeP = (P.satisfy (== 0) *> pure RequestMessage) `P.alt`
144+ (P.satisfy (== 1) *> pure ResponseMessage)
145+ lenPrefixedByteStringP = do
146+ c <- fromIntegral <$> word32P
147+ BS.pack <$> P.takeEQ c s
148+ Envelope <$> fingerprintP <*> msgTypeP <*> uuidP <*> lenPrefixedByteStringP
149+
150+encodeEnvelope :: Envelope -> BS.ByteString
151+encodeEnvelope (Envelope (Fingerprint fp1 fp2) msgType msgId bs) =
152+ fingerprintBs <> msgTypeBs <> msgIdBs <> lenPrefixedBs
153+ where
154+ fingerprintBs = BO.bytestring64 fp1 <> BO.bytestring64 fp2
155+ msgTypeBs = case msgType of
156+ RequestMessage -> BS.singleton 0
157+ ResponseMessage -> BS.singleton 1
158+ msgIdBs =
159+ case UUIDBase.toWords (_unUUID msgId) of
160+ (u1, u2, u3, u4) -> foldr (<>) BS.empty (map BO.bytestring32 [u1, u2, u3, u4])
161+ msgLen = fromIntegral (BS.length bs)
162+ lenPrefixedBs = BO.bytestring32 msgLen <> bs
163+
164+fingerprintP :: Parser IO Word8 Fingerprint
165+fingerprintP = do
166+ f1 <- word64P
167+ f2 <- word64P
168+ pure (Fingerprint f1 f2)
169+
170+word64P :: Parser IO Word8 Word64
171+word64P = do
118172 let s = FL.toList
119− w4x8 <- P.take 4 s
120− --traceShowM ("w4x8"::String, w4x8)
121− let c = fromIntegral (BO.word32 (BS.pack w4x8))
122− --traceShowM ("c"::String, c)
123− vals <- P.take c s
124− let bytes = BS.pack vals
125− --traceShowM ("parsedBytes"::String, c, BS.length bytes, bytes)
126− pure bytes
173+ b <- P.takeEQ 8 s
174+ pure (BO.word64 (BS.pack b))
175+
176+--parse a 32-bit integer from network byte order
177+word32P :: Parser IO Word8 Word32
178+word32P = do
179+ let s = FL.toList
180+ w4x8 <- P.takeEQ 4 s
181+ pure (BO.word32 (BS.pack w4x8))
182+
183+-- uuid is encode as 4 32-bit words because of its convenient 32-bit tuple encoding
184+uuidP :: Parser IO Word8 UUID
185+uuidP = do
186+ u1 <- word32P
187+ u2 <- word32P
188+ u3 <- word32P
189+ u4 <- word32P
190+ pure (UUID (UUIDBase.fromWords u1 u2 u3 u4))
127191
128192type NewConnectionHandler msg = IO (Maybe msg)
129193
130−type NewMessageHandler req resp = req -> IO (HandlerResponse resp)
194+type NewMessageHandler req resp = req -> IO resp
131195
132−serve :: forall req resp. (Show req, Serialise req, Serialise resp) =>
133− NewConnectionHandler resp ->
134− NewMessageHandler req resp ->
196+serve ::
197+ MessageHandlers ->
135198 HostAddr ->
136199 PortNumber ->
137200 Maybe (MVar SockAddr) ->
138201 IO Bool
139−serve connhandler userMsgHandler hostaddr port mSockLock = do
202+serve userMsgHandler hostaddr port mSockLock = do
140203 let
141− decoder :: NewMessageHandler req resp -> Decoder (Message req)
142− decoder _ =
143− case getDecoder (schema (Proxy @(Message req))) of
144− Left exc -> error (show exc)
145− Right dec -> dec
146204 handleSock sock = do
147− mResp <- connhandler
148205 lockingSocket <- newLock sock
149− case mResp of
150− Nothing -> pure ()
151− Just resp -> do
152− requestID <- UUID <$> UUIDBase.nextRandom
153− sendMessage (AsyncRequest requestID resp) lockingSocket
154− drainSocketMessages sock (decoder userMsgHandler) (serverMessageHandler lockingSocket userMsgHandler)
206+ drainSocketMessages sock (serverEnvelopeHandler lockingSocket userMsgHandler)
207+
155208 serially (S.unfold (SA.acceptOnAddrWith [(ReuseAddr,1)] mSockLock) (hostaddr, port)) & parallely . S.mapM (handleWithM handleSock) & S.drain
156209 pure True
157210
158−serverMessageHandler :: forall req resp. (Show req,
159− Serialise req,
160− Serialise resp)
161− => Locking Socket
162− -> NewMessageHandler req resp
163− -> Message req
211+{-serverEnvelopeHandler :: Locking Socket -> MessageHandlers s -> Envelope -> IO ()
212+serverEnvelopeHandler sockLock (Envelope fprint RequestMessage msgId messagebs) = do
213+ error "spam"
214+serverEnvelopeHandler sockLock (Envelope fprint ResponseMessage msgId messagebs) = do
215+ error "spam2"
216+-}
217+
218+openEnvelope :: forall s. (Serialise s, Typeable s) => Envelope -> Maybe s
219+openEnvelope (Envelope eprint _ _ bytes) = do
220+ {-let decoder = case getDecoder (schema (Proxy :: Proxy s)) of
221+ Left err -> error (show err)
222+ Right dec -> dec-}
223+ if eprint == fingerprint (undefined :: s) then
224+ case deserialise bytes of
225+ Left err -> error (show err)
226+ Right v -> Just v
227+ --Just (evalDecoder decoder bytes)
228+ else
229+ Nothing
230+
231+serverEnvelopeHandler ::
232+ Locking Socket
233+ -> MessageHandlers
234+ -> Envelope
164235 -> IO ()
165−serverMessageHandler sockLock requestMessageHandler msg = do
236+serverEnvelopeHandler sockLock (MessageHandlers msgHandlers) envelope@(Envelope _ RequestMessage msgId _) = do
237+ --find first matching handler
238+ let firstMatch = foldr firstMatcher Nothing msgHandlers
239+ firstMatcher :: forall a b. (Serialise a, Serialise b) => RequestHandler a b -> Maybe (RequestHandler a b, a) -> Maybe (RequestHandler a b, a)
240+ firstMatcher msghandler Nothing =
241+ case openEnvelope envelope :: Maybe a of
242+ Just decoded -> Just (msghandler, decoded)
243+ Nothing -> Nothing
244+ firstMatcher _ acc = acc
245+ case firstMatch of
246+ Nothing -> error "failed to handle msg"
247+ Just (msghandler, decoded) -> do
248+ --TODO add exception handling
249+ response <- msghandler decoded
250+ sendEnvelope (Envelope (fingerprint response) ResponseMessage msgId (serialise response)) sockLock
251+serverEnvelopeHandler _ _ (Envelope _ ResponseMessage _ _) = error "server received response message"
252+{-
253+
254+
166255 --putStrLn $ "GOT MSG " ++ show msg
167256 let --runTimeout :: IO (HandlerResponse resp) -> IO (Maybe (HandlerResponse resp))
168257 runTimeout mTimeout m = case mTimeout of
@@ -190,32 +279,29 @@ serverMessageHandler sockLock requestMessageHandler msg = do
190279 --no response necessary
191280 ExceptionResponse{} -> putStrLn "client sent exception response"
192281 TimedOutResponse{} -> putStrLn "client sent timed out response"
282+-}
193283
194284--add callback to allow for responses via socket
195−type MessageHandler a = Message a -> IO ()
196−
197−type AsyncMessageHandler a = a -> IO ()
285+--type MessageHandler a = Message a -> IO ()
198286
287+type EnvelopeHandler = Envelope -> IO ()
199288
289+type AsyncMessageHandler a = a -> IO ()
200290
201−drainSocketMessages :: Serialise msg => Socket -> Decoder (Message msg) -> MessageHandler msg -> IO ()
202−drainSocketMessages sock decoder msgHandler = do
291+drainSocketMessages :: Socket -> EnvelopeHandler -> IO ()
292+drainSocketMessages sock envelopeHandler = do
203293 let sockStream = S.unfold readWithBufferOf (1024 * 4, sock)
204− handler bs = do
205− let decoded = evalDecoder decoder bs
206− msgHandler decoded
207− S.drain $ serially $ S.parseMany messageBoundaryP sockStream & S.mapM handler
294+ S.drain $ serially $ S.parseMany envelopeP sockStream & S.mapM envelopeHandler
208295
209296--send length-tagged bytestring, perhaps should be in network byte order?
210−sendMessage :: Serialise a => Message a -> Locking Socket -> IO ()
211−sendMessage msg sockLock = do
212− let
213− msgbytes = serialiseOnly msg
214− fullbytes = lenbytes <> msgbytes
215− len = BS.length msgbytes
216− lenbytes = BO.bytestring32 (fromIntegral len)
217−
297+sendEnvelope :: Envelope -> Locking Socket -> IO ()
298+sendEnvelope envelope sockLock = do
299+ let envelopebytes = encodeEnvelope envelope
300+ fullbytes = envelopebytes
218301 --Socket.sendAll syscalls send() on a loop until all the bytes are sent, so we need socket locking here to account for serialized messages of size > PIPE_BUF
219302 withLock sockLock $ \socket' ->
220303 Socket.sendAll socket' fullbytes
221− traceBytes "sendMessage" fullbytes
304+ traceBytes "sendEnvelope" fullbytes
305+
306+fingerprint :: Typeable a => a -> Fingerprint
307+fingerprint = typeRepFingerprint . typeOf
test/Curryer/Test/Basic.hs+20−12
@@ -14,13 +14,17 @@ import Data.List
1414import Network.RPC.Curryer.Server
1515import Network.RPC.Curryer.Client
1616
17+import Debug.Trace
18+
19+-- TODO: add test for nested calls
20+
1721testTree :: TestTree
18−testTree = testGroup "basic" [testCase "simple" testSimpleCall,
19− testCase "client async" testAsyncServerCall,
22+testTree = testGroup "basic" [testCase "simple" testSimpleCall
23+ {-testCase "client async" testAsyncServerCall,
2024 testCase "server async" testAsyncClientCall,
2125 testCase "client sync timeout" testSyncClientCallTimeout,
2226 testCase "server-side exception" testSyncException,
23− testCase "multi-threaded client" testMultithreadedClient
27+ testCase "multi-threaded client" testMultithreadedClient-}
2428 ]
2529
2630--client-to-server request
@@ -41,12 +45,14 @@ data TestResponse = AddTwoNumbersResp Int
4145 deriving (Generic, Show, Eq)
4246 deriving Serialise via WineryVariant TestResponse
4347
44−testServerMessageHandler :: Maybe (MVar String) -> TestRequest -> IO (HandlerResponse TestResponse)
45−testServerMessageHandler mAsyncMVar msg =
46− --print msg
48+testServerMessageHandlers :: Maybe (MVar String) -> MessageHandlers
49+testServerMessageHandlers mAsyncMVar =
50+ MessageHandlers [\(AddTwoNumbersReq x y) ->
51+ pure (AddTwoNumbersResp (x + y))]
52+{- --print msg
4753 case msg of
4854 --round-trip request to add two Ints
49− AddTwoNumbersReq x y -> pure (HandlerResponse (AddTwoNumbersResp (x+y)))
55+ AddTwoNumbersReq x y -> pure (AddTwoNumbersResp (x+y))
5056 --respond to a request for an async callback
5157 TestCallMeBackReq s -> do
5258 case mAsyncMVar of
@@ -54,24 +60,24 @@ testServerMessageHandler mAsyncMVar msg =
5460 Just mvar -> putMVar mvar s
5561 pure NoResponse
5662 TestAsyncReq _ -> pure NoResponse
57− RoundtripStringReq s -> pure (HandlerResponse (RoundtripStringResp s))
63+ RoundtripStringReq s -> pure (RoundtripStringResp s)
5864 DelayMicrosecondsReq ms -> do
5965 threadDelay ms
6066 pure (HandlerResponse DelayMicrosecondsResp)
6167 ThrowServerSideExceptionReq -> error "test server exception"
62−
68+-}
6369-- test a simple client-to-server round-trip function execution
6470testSimpleCall :: Assertion
6571testSimpleCall = do
6672 readyVar <- newEmptyMVar
6773
68− server <- async (serve (pure Nothing) (testServerMessageHandler Nothing) localHostAddr 0 (Just readyVar))
74+ server <- async (serve (testServerMessageHandlers Nothing) localHostAddr 0 (Just readyVar))
6975 --wait for server to be ready
7076 (SockAddrInet port _) <- takeMVar readyVar
7177 let clientHandler :: AsyncMessageHandler TestResponse
7278 clientHandler _ = error "async handler called"
73− mkConn :: IO (Connection TestResponse)
74− mkConn = connect clientHandler localHostAddr port
79+ mkConn :: IO Connection
80+ mkConn = connect localHostAddr port
7581 conn <- mkConn
7682 let c :: IO (Either ConnectionError TestResponse)
7783 c = call conn (AddTwoNumbersReq 1 1)
@@ -81,6 +87,7 @@ testSimpleCall = do
8187 close conn
8288 cancel server
8389
90+{-
8491--test that the client can proces a server-initiated asynchronous callback from the server
8592testAsyncServerCall :: Assertion
8693testAsyncServerCall = do
@@ -179,3 +186,4 @@ testMultithreadedClient = do
179186 close conn
180187 cancel server
181188
189+-}