packages feed

grapesy-1.1.1: interop/Interop/Server/Common.hs

{-# LANGUAGE OverloadedStrings #-}

-- | Functionality required by many handlers
module Interop.Server.Common (
    constructResponseMetadata
  , echoStatus
  , checkInboundCompression
  ) where

import Control.Exception
import Data.ProtoLens.Labels ()

import Network.GRPC.Common
import Network.GRPC.Common.Protobuf
import Network.GRPC.Server
import Network.GRPC.Spec (toGrpcStatus)

import Interop.Util.Exceptions

import Proto.API.Interop

{-------------------------------------------------------------------------------
  Dealing with the test-suite's message types
-------------------------------------------------------------------------------}

-- | Construct response metadata
--
-- Sends the initial response metadata now, and returns the trailing metadata.
--
-- See <https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md#custom_metadata>
constructResponseMetadata ::
     Call (Protobuf TestService rpc)
  -> IO InteropRespTrailMeta
constructResponseMetadata call = do
    requestMetadata <- getRequestMetadata call

    let initMeta  :: InteropRespInitMeta
        trailMeta :: InteropRespTrailMeta

        initMeta  = InteropRespInitMeta  $ interopExpectInit  requestMetadata
        trailMeta = InteropRespTrailMeta $ interopExpectTrail requestMetadata

    -- Send initial metadata
    setResponseInitialMetadata call initMeta
    initiateResponse call

    -- Return the final metadata to be sent at the end of the call
    return trailMeta
  where

-- | Echo any non-OK status back to the client
--
-- Does nothing if @code@ is set to @0@ ('GrpcOk').
--
-- See <https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md#status_code_and_message>
echoStatus :: Proto EchoStatus -> IO ()
echoStatus status =
    case toGrpcStatus code of
      Just GrpcOk ->
        return ()
      Just (GrpcError err) ->
        throwIO $ GrpcException {
            grpcError         = err
          , grpcErrorMessage  = Just $ status ^. #message
          , grpcErrorDetails  = Nothing
          , grpcErrorMetadata = []
          }
      Nothing ->
        assertUnrecognized code
  where
    code :: Word
    code = fromIntegral $ status ^. #code

checkInboundCompression :: Bool -> InboundMeta -> IO ()
checkInboundCompression expectCompressed meta =
    case (expectCompressed, inboundCompressedSize meta) of
      (True, Just _) ->
        return ()
      (False, Nothing) ->
        return ()
      (True, Nothing) ->
        throwIO GrpcException {
            grpcError         = GrpcInvalidArgument
          , grpcErrorMessage  = Just "Expected compressed message"
          , grpcErrorDetails  = Nothing
          , grpcErrorMetadata = []
          }
      (False, Just _) ->
        throwIO GrpcException {
            grpcError         = GrpcInvalidArgument
          , grpcErrorMessage  = Just "Expected uncompressed message"
          , grpcErrorDetails  = Nothing
          , grpcErrorMetadata = []
          }