gRPC-haskell/src/Network/GRPC/HighLevel/Server/Unregistered.hs
Connor Clark 01fac2d5a6 add option to set logging function (#71)
* add option to set logging function

* Add documentation to ServerOptions
2016-08-17 14:12:22 -07:00

99 lines
4.0 KiB
Haskell

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Network.GRPC.HighLevel.Server.Unregistered where
import Control.Arrow
import Control.Concurrent
import Control.Concurrent.Async (async, wait)
import qualified Control.Exception as CE
import Control.Monad
import Data.Foldable (find)
import Data.Protobuf.Wire.Class
import Network.GRPC.HighLevel.Server
import Network.GRPC.LowLevel
import qualified Network.GRPC.LowLevel.Call.Unregistered as U
import qualified Network.GRPC.LowLevel.Server.Unregistered as U
dispatchLoop :: Server
-> (String -> IO ())
-> MetadataMap
-> [Handler 'Normal]
-> [Handler 'ClientStreaming]
-> [Handler 'ServerStreaming]
-> [Handler 'BiDiStreaming]
-> IO ()
dispatchLoop s logger md hN hC hS hB =
forever $ U.withServerCallAsync s $ \sc ->
case findHandler sc allHandlers of
Just (AnyHandler ah) -> case ah of
UnaryHandler _ h -> unaryHandler sc h
ClientStreamHandler _ h -> csHandler sc h
ServerStreamHandler _ h -> ssHandler sc h
BiDiStreamHandler _ h -> bdHandler sc h
Nothing -> unknownHandler sc
where
allHandlers = map AnyHandler hN ++ map AnyHandler hC
++ map AnyHandler hS ++ map AnyHandler hB
findHandler sc = find ((== U.callMethod sc) . anyHandlerMethodName)
unaryHandler :: (Message a, Message b) => U.ServerCall -> ServerHandler a b -> IO ()
unaryHandler sc h =
handleError $
U.serverHandleNormalCall' s sc md $ \_sc' bs ->
convertServerHandler h (const bs <$> U.convertCall sc)
csHandler :: (Message a, Message b) => U.ServerCall -> ServerReaderHandler a b -> IO ()
csHandler sc = handleError . U.serverReader s sc md . convertServerReaderHandler
ssHandler :: (Message a, Message b) => U.ServerCall -> ServerWriterHandler a b -> IO ()
ssHandler sc = handleError . U.serverWriter s sc md . convertServerWriterHandler
bdHandler :: (Message a, Message b) => U.ServerCall -> ServerRWHandler a b -> IO ()
bdHandler sc = handleError . U.serverRW s sc md . convertServerRWHandler
unknownHandler :: U.ServerCall -> IO ()
unknownHandler sc = void $ U.serverHandleNormalCall' s sc md $ \_ _ ->
return (mempty, mempty, StatusNotFound, StatusDetails "unknown method")
handleError :: IO a -> IO ()
handleError = (handleCallError logger . left herr =<<) . CE.try
where herr (e :: CE.SomeException) = GRPCIOHandlerException (show e)
serverLoop :: ServerOptions -> IO ()
serverLoop ServerOptions{..} = do
-- We run the loop in a new thread so that we can kill the serverLoop thread.
-- Without this fork, we block on a foreign call, which can't be interrupted.
tid <- async $ withGRPC $ \grpc ->
withServer grpc config $ \server -> do
dispatchLoop server
optLogger
optInitialMetadata
optNormalHandlers
optClientStreamHandlers
optServerStreamHandlers
optBiDiStreamHandlers
wait tid
where
config = ServerConfig
{ host = "localhost"
, port = optServerPort
, methodsToRegisterNormal = []
, methodsToRegisterClientStreaming = []
, methodsToRegisterServerStreaming = []
, methodsToRegisterBiDiStreaming = []
, serverArgs =
[CompressionAlgArg GrpcCompressDeflate | optUseCompression]
++
[ UserAgentPrefix optUserAgentPrefix
, UserAgentSuffix optUserAgentSuffix
]
, sslConfig = optSSLConfig
}