packages feed

grapesy-1.0.0: src/Network/GRPC/Server/Session.hs

module Network.GRPC.Server.Session (
    ServerSession(..)
  , ServerInbound
  , ServerOutbound
  , Headers(..)
    -- * Exceptions
  , CallSetupFailure(..)
  ) where

import Control.Exception
import Data.Proxy
import Data.Void

import Network.GRPC.Server.Context
import Network.GRPC.Spec
import Network.GRPC.Spec.Serialization
import Network.GRPC.Util.Session

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

data ServerSession rpc = ServerSession {
      serverSessionContext :: ServerContext
    }

{-------------------------------------------------------------------------------
  Instances
-------------------------------------------------------------------------------}

data ServerInbound rpc
data ServerOutbound rpc

instance IsRPC rpc => DataFlow (ServerInbound rpc) where
  data Headers (ServerInbound rpc) = InboundHeaders {
        inbHeaders     :: RequestHeaders' HandledSynthesized
      , inbCompression :: Compression
      }
    deriving (Show)

  type Message  (ServerInbound rpc) = (InboundMeta, Input rpc)
  type Trailers (ServerInbound rpc) = NoMetadata

  -- gRPC does not support request trailers
  type NoMessages (ServerInbound rpc) = Void

instance IsRPC rpc => DataFlow (ServerOutbound rpc) where
  data Headers (ServerOutbound rpc) = OutboundHeaders {
        outHeaders     :: ResponseHeaders
      , outCompression :: Compression
      }
    deriving (Show)

  type Message    (ServerOutbound rpc) = (OutboundMeta, Output rpc)
  type Trailers   (ServerOutbound rpc) = ProperTrailers
  type NoMessages (ServerOutbound rpc) = TrailersOnly

instance SupportsServerRpc rpc => IsSession (ServerSession rpc) where
  type Inbound  (ServerSession rpc) = ServerInbound rpc
  type Outbound (ServerSession rpc) = ServerOutbound rpc

  parseInboundTrailers  _ = \_ -> return NoMetadata
  buildOutboundTrailers _ = buildProperTrailers

  parseMsg _ = parseInput  (Proxy @rpc) . inbCompression
  buildMsg _ = buildOutput (Proxy @rpc) . outCompression

{-------------------------------------------------------------------------------
  Exceptions
-------------------------------------------------------------------------------}

-- | We failed to setup the call from the client
data CallSetupFailure =
    -- | Client sent resource headers that were not conform the gRPC spec
    CallSetupInvalidResourceHeaders InvalidResourceHeaders

    -- | Invalid request headers
    --
    -- 'CallSetupInvalidResourceHeaders' refers to an invalid method (anything
    -- other than POST) or an invalid path; 'CallSetupInvalidRequestHeaders'
    -- means we could not parse the HTTP headers according to the gRPC spec.
  | CallSetupInvalidRequestHeaders (InvalidHeaders HandledSynthesized)

    -- | Client chose unsupported compression algorithm
    --
    -- This is indicative of a misbehaving peer: a client should not use a
    -- compression algorithm unless they have evidence that the server supports
    -- it. The server cannot process such a request, as it has no way of
    -- decompression messages sent by the client.
  | CallSetupUnsupportedCompression CompressionId

    -- | No registered handler for the specified path
    --
    -- Note on terminology: HTTP has \"methods\" such as POST, GET, etc; gRPC
    -- supports only POST, and when another HTTP method is chosen, this will
    -- result in 'CallSetupInvalidResourceHeaders'. However, gRPC itself also
    -- has the concept of a "method" (a method, or gRPC call, supported by a
    -- particular service); it's these methods that
    -- 'CallSetupUnimplementedMethod' is referring to.
  | CallSetupUnimplementedMethod Path

    -- | An exception arose while we tried to look up the handler
    --
    -- This can arise when the list of handlers /itself/ is @undefined@.
  | CallSetupHandlerLookupException SomeException

deriving stock    instance Show      CallSetupFailure
deriving anyclass instance Exception CallSetupFailure