{-# LANGUAGE OverloadedStrings #-}

module Network.GRPC.Spec.Serialization.Headers.PseudoHeaders (
    RawResourceHeaders(..)
  , InvalidResourceHeaders(..)
  , buildResourceHeaders
  , parseResourceHeaders
  ) where

import Control.Monad.Except
import Data.ByteString qualified as BS.Strict
import Data.ByteString qualified as Strict (ByteString)

import Network.GRPC.Spec
import Network.GRPC.Spec.Util.ByteString

{-------------------------------------------------------------------------------
  Serialization
-------------------------------------------------------------------------------}

-- | Raw (serialized) form of t'ResourceHeaders'
data RawResourceHeaders = RawResourceHeaders {
      RawResourceHeaders -> ByteString
rawPath   :: Strict.ByteString  -- ^ Serialized 'resourcePath'
    , RawResourceHeaders -> ByteString
rawMethod :: Strict.ByteString  -- ^ Serialized 'resourceMethod'
    }
  deriving (Int -> RawResourceHeaders -> ShowS
[RawResourceHeaders] -> ShowS
RawResourceHeaders -> String
(Int -> RawResourceHeaders -> ShowS)
-> (RawResourceHeaders -> String)
-> ([RawResourceHeaders] -> ShowS)
-> Show RawResourceHeaders
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RawResourceHeaders -> ShowS
showsPrec :: Int -> RawResourceHeaders -> ShowS
$cshow :: RawResourceHeaders -> String
show :: RawResourceHeaders -> String
$cshowList :: [RawResourceHeaders] -> ShowS
showList :: [RawResourceHeaders] -> ShowS
Show)

-- | Invalid resource headers
--
-- See 'parseResourceHeaders'
data InvalidResourceHeaders =
    InvalidMethod Strict.ByteString
  | InvalidPath Strict.ByteString
  deriving stock (Int -> InvalidResourceHeaders -> ShowS
[InvalidResourceHeaders] -> ShowS
InvalidResourceHeaders -> String
(Int -> InvalidResourceHeaders -> ShowS)
-> (InvalidResourceHeaders -> String)
-> ([InvalidResourceHeaders] -> ShowS)
-> Show InvalidResourceHeaders
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InvalidResourceHeaders -> ShowS
showsPrec :: Int -> InvalidResourceHeaders -> ShowS
$cshow :: InvalidResourceHeaders -> String
show :: InvalidResourceHeaders -> String
$cshowList :: [InvalidResourceHeaders] -> ShowS
showList :: [InvalidResourceHeaders] -> ShowS
Show)

-- | Serialize t'ResourceHeaders' (pseudo headers)
buildResourceHeaders :: ResourceHeaders -> RawResourceHeaders
buildResourceHeaders :: ResourceHeaders -> RawResourceHeaders
buildResourceHeaders ResourceHeaders{Path
resourcePath :: ResourceHeaders -> Path
resourcePath :: Path
resourcePath, Method
resourceMethod :: ResourceHeaders -> Method
resourceMethod :: Method
resourceMethod} =
    RawResourceHeaders {
        rawMethod :: ByteString
rawMethod = case Method
resourceMethod of Method
Post -> ByteString
"POST"
      , rawPath :: ByteString
rawPath   = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat [
                        ByteString
"/"
                      , Path -> ByteString
pathService Path
resourcePath
                      , ByteString
"/"
                      , Path -> ByteString
pathMethod Path
resourcePath
                      ]
      }

-- | Parse t'ResourceHeaders' (pseudo headers)
parseResourceHeaders ::
     RawResourceHeaders
  -> Either InvalidResourceHeaders ResourceHeaders
parseResourceHeaders :: RawResourceHeaders -> Either InvalidResourceHeaders ResourceHeaders
parseResourceHeaders RawResourceHeaders{ByteString
rawMethod :: RawResourceHeaders -> ByteString
rawMethod :: ByteString
rawMethod, ByteString
rawPath :: RawResourceHeaders -> ByteString
rawPath :: ByteString
rawPath} = do
    resourceMethod <-
      case ByteString
rawMethod of
        ByteString
"POST"     -> Method -> Either InvalidResourceHeaders Method
forall a. a -> Either InvalidResourceHeaders a
forall (m :: * -> *) a. Monad m => a -> m a
return Method
Post
        ByteString
_otherwise -> InvalidResourceHeaders -> Either InvalidResourceHeaders Method
forall a. InvalidResourceHeaders -> Either InvalidResourceHeaders a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (InvalidResourceHeaders -> Either InvalidResourceHeaders Method)
-> InvalidResourceHeaders -> Either InvalidResourceHeaders Method
forall a b. (a -> b) -> a -> b
$ ByteString -> InvalidResourceHeaders
InvalidMethod ByteString
rawMethod

    resourcePath <-
      case BS.Strict.split (ascii '/') rawPath of
        [ByteString
"", ByteString
service, ByteString
method] ->
          Path -> Either InvalidResourceHeaders Path
forall a. a -> Either InvalidResourceHeaders a
forall (m :: * -> *) a. Monad m => a -> m a
return (Path -> Either InvalidResourceHeaders Path)
-> Path -> Either InvalidResourceHeaders Path
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> Path
Path ByteString
service ByteString
method
        [ByteString]
_otherwise ->
          InvalidResourceHeaders -> Either InvalidResourceHeaders Path
forall a. InvalidResourceHeaders -> Either InvalidResourceHeaders a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (InvalidResourceHeaders -> Either InvalidResourceHeaders Path)
-> InvalidResourceHeaders -> Either InvalidResourceHeaders Path
forall a b. (a -> b) -> a -> b
$ ByteString -> InvalidResourceHeaders
InvalidPath ByteString
rawPath

    return ResourceHeaders{resourceMethod, resourcePath}