{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.GRPC.HTTP2.Types where
import Control.Exception (Exception)
import Data.ProtoLens.Service.Types (Service(..), HasMethod, HasMethodImpl(..))
import Data.Proxy (Proxy(..))
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as ByteString
import GHC.TypeLits (Symbol, symbolVal)
type HeaderKey = ByteString
type HeaderValue = ByteString
grpcTimeoutH :: HeaderKey
grpcTimeoutH = "grpc-timeout"
grpcEncodingH :: HeaderKey
grpcEncodingH = "grpc-encoding"
grpcAcceptEncodingH :: HeaderKey
grpcAcceptEncodingH = "grpc-accept-encoding"
grpcAcceptEncodingHVdefault :: HeaderValue
grpcAcceptEncodingHVdefault = "identity,gzip"
grpcStatusH :: HeaderKey
grpcStatusH = "grpc-status"
grpcMessageH :: HeaderKey
grpcMessageH = "grpc-message"
grpcContentTypeHV :: HeaderValue
grpcContentTypeHV = "application/grpc+proto"
grpcStatusHV :: HeaderValue
grpcStatusHV = "Grpc-Status"
grpcMessageHV :: HeaderValue
grpcMessageHV = "Grpc-Message"
data GRPCStatusCode =
OK
| CANCELLED
| UNKNOWN
| INVALID_ARGUMENT
| DEADLINE_EXCEEDED
| NOT_FOUND
| ALREADY_EXISTS
| PERMISSION_DENIED
| UNAUTHENTICATED
| RESOURCE_EXHAUSTED
| FAILED_PRECONDITION
| ABORTED
| OUT_OF_RANGE
| UNIMPLEMENTED
| INTERNAL
| UNAVAILABLE
| DATA_LOSS
deriving (Show, Eq, Ord)
trailerForStatusCode :: GRPCStatusCode -> ByteString
trailerForStatusCode = \case
OK
-> "0"
CANCELLED
-> "1"
UNKNOWN
-> "2"
INVALID_ARGUMENT
-> "3"
DEADLINE_EXCEEDED
-> "4"
NOT_FOUND
-> "5"
ALREADY_EXISTS
-> "6"
PERMISSION_DENIED
-> "7"
UNAUTHENTICATED
-> "16"
RESOURCE_EXHAUSTED
-> "8"
FAILED_PRECONDITION
-> "9"
ABORTED
-> "10"
OUT_OF_RANGE
-> "11"
UNIMPLEMENTED
-> "12"
INTERNAL
-> "13"
UNAVAILABLE
-> "14"
DATA_LOSS
-> "15"
type GRPCStatusMessage = ByteString
data GRPCStatus = GRPCStatus !GRPCStatusCode !GRPCStatusMessage
deriving (Show, Eq, Ord)
instance Exception GRPCStatus
trailers :: GRPCStatus -> [(ByteString, ByteString)]
trailers (GRPCStatus s msg) =
if ByteString.null msg then [status] else [status, message]
where
status = ("grpc-status", trailerForStatusCode s)
message = ("grpc-message", msg)
data RPC (s :: *) (m :: Symbol) = RPC
path :: (Service s, HasMethod s m) => RPC s m -> ByteString
{-# INLINE path #-}
path rpc = "/" <> pkg rpc Proxy <> "." <> srv rpc Proxy <> "/" <> meth rpc Proxy
where
pkg :: (Service s) => RPC s m -> Proxy (ServicePackage s) -> ByteString
pkg _ p = ByteString.pack $ symbolVal p
srv :: (Service s) => RPC s m -> Proxy (ServiceName s) -> ByteString
srv _ p = ByteString.pack $ symbolVal p
meth :: (Service s, HasMethod s m) => RPC s m -> Proxy (MethodName s m) -> ByteString
meth _ p = ByteString.pack $ symbolVal p
newtype Timeout = Timeout Int
showTimeout :: Timeout -> ByteString
showTimeout (Timeout n) = ByteString.pack $ show n ++ "S"
type Authority = ByteString.ByteString