@@ -1,4 +1,4 @@
1−{-# LANGUAGE DerivingVia, DeriveGeneric, RankNTypes, ScopedTypeVariables, MultiParamTypeClasses, OverloadedStrings, GeneralizedNewtypeDeriving, CPP, ExistentialQuantification, StandaloneDeriving, GADTs, RecordWildCards #-}
1+{-# LANGUAGE DerivingVia, DeriveGeneric, RankNTypes, ScopedTypeVariables, MultiParamTypeClasses, OverloadedStrings, GeneralizedNewtypeDeriving, TypeApplications, CPP, ExistentialQuantification, StandaloneDeriving, GADTs #-}
22{-# OPTIONS_GHC -fno-warn-orphans #-}
33{- HLINT ignore "Use lambda-case" -}
44module Network.RPC.Curryer.Server where
@@ -27,7 +27,6 @@ import qualified Data.Binary as B
2727import qualified Data.UUID as UUIDBase
2828import qualified Data.UUID.V4 as UUIDBase
2929import Control.Monad
30−import Data.Functor
3130
3231import qualified Network.RPC.Curryer.StreamlyAdditions as SA
3332--import Control.Monad
@@ -35,14 +34,14 @@ import Data.Hashable
3534import System.Timeout
3635import qualified Network.ByteOrder as BO
3736
38−
3937-- for toArrayS conversion
40−import qualified Data.ByteString.Internal as BSI
41−import qualified Streamly.Internal.Data.Array.Storable.Foreign.Types as Arr
38+{-import qualified Data.ByteString.Internal as BSI
39+import qualified Streamly.Internal.Data.Array.Storable.Foreign.Types as SA
40+import Foreign.ForeignPtr (plusForeignPtr)
4241import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
43−import GHC.Ptr (minusPtr)
44−
45−-- define CURRYER_SHOW_BYTES 1
42+import GHC.Ptr (plusPtr)
43+-}
44+-- #define CURRYER_SHOW_BYTES 1
4645#if CURRYER_SHOW_BYTES == 1
4746import Debug.Trace
4847#endif
@@ -98,7 +97,7 @@ data MessageType = RequestMessage TimeoutMicroseconds
9897-- | A list of `RequestHandler`s.
9998type RequestHandlers serverState = [RequestHandler serverState]
10099
101−-- | Data types for server-side request handlers, in synchronous (client waits for return value) and asynchronous (client does not wait for return value) forms.
100+-- |
102101data RequestHandler serverState where
103102 -- | create a request handler with a response
104103 RequestHandler :: forall a b serverState. (Serialise a, Serialise b) => (ConnectionState serverState -> a -> IO b) -> RequestHandler serverState
@@ -111,14 +110,13 @@ data ConnectionState a = ConnectionState {
111110 connectionSocket :: Locking Socket
112111 }
113112
114−-- | Used by server-side request handlers to send additional messages to the client. This is useful for sending asynchronous responses to the client outside of the normal request-response flow. The locking socket can be found in the ConnectionState when a request handler is called.
115−sendMessage :: Serialise a => Locking Socket -> a -> IO ()
116−sendMessage lockSock msg = do
113+-- | Used by server-side request handlers to send additional messages to the client. This is useful for sending asynchronous responses to the client outside of the normal request-response flow.
114+sendMessage :: Serialise a => ConnectionState s -> a -> IO ()
115+sendMessage sState msg = do
117116 requestID <- UUID <$> UUIDBase.nextRandom
118117 let env =
119− Envelope (fingerprint msg) (RequestMessage timeout') requestID (serialise msg)
120− timeout' = 0
121− sendEnvelope env lockSock
118+ Envelope (fingerprint msg) (RequestMessage 0) requestID (serialise msg)
119+ sendEnvelope env (connectionSocket sState)
122120
123121--avoid orphan instance
124122newtype UUID = UUID { _unUUID :: UUIDBase.UUID }
@@ -145,11 +143,6 @@ data ConnectionError = CodecError String -- show of WineryException from excepti
145143 deriving (Generic, Show, Eq)
146144 deriving Serialise via WineryVariant ConnectionError
147145
148−data TimeoutException = TimeoutException
149− deriving Show
150−
151−instance Exception TimeoutException
152−
153146type HostAddr = (Word8, Word8, Word8, Word8)
154147
155148allHostAddrs,localHostAddr :: HostAddr
@@ -159,18 +152,15 @@ localHostAddr = (127,0,0,1)
159152-- Each message is length-prefixed by a 32-bit unsigned length.
160153envelopeP :: Parser IO Word8 Envelope
161154envelopeP = do
162− let msgTypeP = (P.satisfy (== 0) *>
155+ let s = FL.toList
156+ msgTypeP = (P.satisfy (== 0) *>
163157 (RequestMessage . fromIntegral <$> word32P)) `P.alt`
164− (P.satisfy (== 1) $> ResponseMessage) `P.alt`
165− (P.satisfy (== 2) $> TimeoutResponseMessage) `P.alt`
166− (P.satisfy (== 3) $> ExceptionResponseMessage)
158+ (P.satisfy (== 1) *> pure ResponseMessage) `P.alt`
159+ (P.satisfy (== 2) *> pure TimeoutResponseMessage) `P.alt`
160+ (P.satisfy (== 3) *> pure ExceptionResponseMessage)
167161 lenPrefixedByteStringP = do
168162 c <- fromIntegral <$> word32P
169− --streamly can't handle takeEQ 0, so add special handling
170− if c == 0 then
171− pure BS.empty
172− else
173− fromArray <$> P.takeEQ c (Arr.writeN c)
163+ BS.pack <$> P.takeEQ c s
174164 Envelope <$> fingerprintP <*> msgTypeP <*> uuidP <*> lenPrefixedByteStringP
175165
176166encodeEnvelope :: Envelope -> BS.ByteString
@@ -185,13 +175,15 @@ encodeEnvelope (Envelope (Fingerprint fp1 fp2) msgType msgId bs) =
185175 ExceptionResponseMessage -> BS.singleton 3
186176 msgIdBs =
187177 case UUIDBase.toWords (_unUUID msgId) of
188− (u1, u2, u3, u4) -> foldr ((<>) . BO.bytestring32) BS.empty [u1, u2, u3, u4]
178+ (u1, u2, u3, u4) -> foldr (<>) BS.empty (map BO.bytestring32 [u1, u2, u3, u4])
189179 msgLen = fromIntegral (BS.length bs)
190180 lenPrefixedBs = BO.bytestring32 msgLen <> bs
191181
192182fingerprintP :: Parser IO Word8 Fingerprint
193−fingerprintP =
194− Fingerprint <$> word64P <*> word64P
183+fingerprintP = do
184+ f1 <- word64P
185+ f2 <- word64P
186+ pure (Fingerprint f1 f2)
195187
196188word64P :: Parser IO Word8 Word64
197189word64P = do
@@ -212,10 +204,8 @@ uuidP = do
212204 u1 <- word32P
213205 u2 <- word32P
214206 u3 <- word32P
215− --u4 <- word32P
216− --pure (UUID (UUIDBase.fromWords u1 u2 u3 u4))-}
217− --(UUID . UUIDBase.fromWords) <$> word32P <*> word32P <*> word32P <*> word32P
218− UUID . UUIDBase.fromWords u1 u2 u3 <$> word32P
207+ u4 <- word32P
208+ pure (UUID (UUIDBase.fromWords u1 u2 u3 u4))
219209
220210type NewConnectionHandler msg = IO (Maybe msg)
221211
@@ -239,7 +229,7 @@ serve userMsgHandlers serverState hostaddr port mSockLock = do
239229 pure True
240230
241231openEnvelope :: forall s. (Serialise s, Typeable s) => Envelope -> Maybe s
242−openEnvelope (Envelope eprint _ _ bytes) =
232+openEnvelope (Envelope eprint _ _ bytes) = do
243233 if eprint == fingerprint (undefined :: s) then
244234 case deserialise bytes of
245235 Left err -> error (show err)
@@ -271,13 +261,10 @@ serverEnvelopeHandler sockLock msgHandlers serverState envelope@(Envelope _ (Req
271261 let runTimeout :: IO b -> IO (Maybe b)
272262 runTimeout m =
273263 if timeoutms == 0 then
274− (Just <$> m) `catch` timeoutExcHandler
264+ Just <$> m
275265 else
276− (timeout (fromIntegral timeoutms) m) `catch` timeoutExcHandler
277− --allow server-side function to throw TimeoutError which is caught here and becomes TimeoutError value
278− timeoutExcHandler :: TimeoutException -> IO (Maybe b)
279− timeoutExcHandler _ = pure Nothing
280−
266+ timeout (fromIntegral timeoutms) m
267+
281268 sState = ConnectionState {
282269 connectionServerState = serverState,
283270 connectionSocket = sockLock
@@ -293,8 +280,8 @@ serverEnvelopeHandler sockLock msgHandlers serverState envelope@(Envelope _ (Req
293280 case mResponse of
294281 Just response ->
295282 Envelope (fingerprint response) ResponseMessage msgId (serialise response)
296− Nothing ->
297− Envelope (fingerprint TimeoutError) TimeoutResponseMessage msgId BS.empty
283+ Nothing ->
284+ Envelope (fingerprint TimeoutError) (TimeoutResponseMessage) msgId (BS.empty)
298285 sendEnvelope envelopeResponse sockLock
299286 pure (Just ())
300287 firstMatcher (AsyncRequestHandler msghandler) Nothing =
@@ -327,16 +314,8 @@ sendEnvelope envelope sockLock = do
327314 --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
328315 withLock sockLock $ \socket' ->
329316 Socket.sendAll socket' fullbytes
330− --traceShowM ("sendEnvelope", envelope)
331317 traceBytes "sendEnvelope" fullbytes
332318
333319fingerprint :: Typeable a => a -> Fingerprint
334320fingerprint = typeRepFingerprint . typeOf
335321
336−fromArray :: Arr.Array Word8 -> BSI.ByteString
337−fromArray Arr.Array {..}
338− | aLen == 0 = mempty
339− | otherwise = BSI.PS aStart 0 aLen
340− where
341− aStartPtr = unsafeForeignPtrToPtr aStart
342− aLen = aEnd `minusPtr` aStartPtr