grapesy-1.0.0: src/Network/GRPC/Common/Headers.hs
-- | Utilities for working with headers
module Network.GRPC.Common.Headers (
HasRequiredHeaders(..)
, RequiredHeaders(..)
, verifyRequired
, verifyAll
, verifyAllIf
) where
import Data.Functor.Identity
import Data.Kind
import Data.Void
import Network.GRPC.Spec
import Network.GRPC.Spec.Util.HKD (Undecorated, Checked)
import Network.GRPC.Spec.Util.HKD qualified as HKD
{-------------------------------------------------------------------------------
Definition
-------------------------------------------------------------------------------}
-- | Required headers
--
-- Required headers are headers that @grapesy@ needs to know in order to
-- function. For example, we /need/ to know which compression algorithm the peer
-- is using for their messages to us.
class HKD.Traversable h => HasRequiredHeaders h where
data RequiredHeaders h :: Type
requiredHeaders :: h (Checked e) -> Either e (RequiredHeaders h)
-- | Like 'requiredHeaders', but for already verified headers
requiredHeadersVerified ::
HasRequiredHeaders h
=> h Undecorated -> RequiredHeaders h
requiredHeadersVerified =
either absurd id . requiredHeaders . HKD.map noError . HKD.decorate
where
noError :: Identity a -> Either Void a
noError = Right . runIdentity
-- | Validate only the required headers
--
-- By default, we only check those headers @grapesy@ needs to function.
verifyRequired ::
HasRequiredHeaders h
=> h (Checked (InvalidHeaders HandledSynthesized))
-> Either (InvalidHeaders HandledSynthesized) (RequiredHeaders h)
verifyRequired = requiredHeaders
-- | Validate /all/ headers
--
-- Validate all headers; we do this only if
-- 'Network.GRPC.Client.connVerifyHeaders' (on the client) or
-- 'Network.GRPC.Server.serverVerifyHeaders' (on the server) is enabled.
verifyAll :: forall h.
HasRequiredHeaders h
=> h (Checked (InvalidHeaders HandledSynthesized))
-> Either (InvalidHeaders HandledSynthesized) (h Undecorated, RequiredHeaders h)
verifyAll = fmap aux . HKD.sequence
where
aux :: h Undecorated -> (h Undecorated, RequiredHeaders h)
aux verifyd = (verifyd, requiredHeadersVerified verifyd)
-- | Convenience wrapper, conditionally verifying all headers
verifyAllIf ::
HasRequiredHeaders h
=> Bool
-> h (Checked (InvalidHeaders HandledSynthesized))
-> Either (InvalidHeaders HandledSynthesized) (RequiredHeaders h)
verifyAllIf False = verifyRequired
verifyAllIf True = fmap snd . verifyAll
{-------------------------------------------------------------------------------
Request
-------------------------------------------------------------------------------}
instance HasRequiredHeaders RequestHeaders_ where
data RequiredHeaders RequestHeaders_ = RequiredRequestHeaders {
requiredRequestCompression :: Maybe CompressionId
, requiredRequestTimeout :: Maybe Timeout
}
requiredHeaders requestHeaders =
RequiredRequestHeaders
<$> requestCompression requestHeaders
<*> requestTimeout requestHeaders
{-------------------------------------------------------------------------------
Response
-------------------------------------------------------------------------------}
instance HasRequiredHeaders ResponseHeaders_ where
data RequiredHeaders ResponseHeaders_ = RequiredResponseHeaders {
requiredResponseCompression :: Maybe CompressionId
}
requiredHeaders responseHeaders =
RequiredResponseHeaders
<$> responseCompression responseHeaders
{-------------------------------------------------------------------------------
Trailers-Only
-------------------------------------------------------------------------------}
instance HasRequiredHeaders TrailersOnly_ where
data RequiredHeaders TrailersOnly_ = NoRequiredTrailers
requiredHeaders _ = pure NoRequiredTrailers