{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Rollbar.Item.MissingHeaders
( MissingHeaders(..)
, RemoveHeaders
) where
import Data.Aeson
(FromJSON, KeyValue, ToJSON, object, parseJSON, toJSON, (.=))
import Data.Bifunctor (bimap)
import Data.CaseInsensitive (mk, original)
import Data.Maybe (catMaybes)
import Data.Proxy (Proxy(Proxy))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import Network.HTTP.Types (Header, RequestHeaders)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC8
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
newtype MissingHeaders (headers :: [Symbol])
= MissingHeaders RequestHeaders
deriving (Eq, Show)
class RemoveHeaders (headers :: [Symbol]) where
removeHeaders :: MissingHeaders headers -> RequestHeaders
instance RemoveHeaders '[] where
removeHeaders (MissingHeaders rhs) = rhs
instance (KnownSymbol header, RemoveHeaders headers)
=> RemoveHeaders (header ': headers) where
removeHeaders (MissingHeaders rhs) =
removeHeaders (MissingHeaders $ filter go rhs :: MissingHeaders headers)
where
go (rh, _) =
rh /= (mk . BSC8.pack $ symbolVal (Proxy :: Proxy header))
instance FromJSON (MissingHeaders headers) where
parseJSON v = MissingHeaders . fmap (bimap (mk . BS.pack) BS.pack) <$> parseJSON v
instance RemoveHeaders headers => ToJSON (MissingHeaders headers) where
toJSON = object . catMaybes . requestHeadersKVs . removeHeaders
requestHeadersKVs :: forall kv. KeyValue kv => RequestHeaders -> [Maybe kv]
requestHeadersKVs = fmap go
where
go :: Header -> Maybe kv
go (key', val') = do
key <- myDecodeUtf8 $ original key'
val <- myDecodeUtf8 val'
pure (key .= val)
myDecodeUtf8 :: BS.ByteString -> Maybe T.Text
myDecodeUtf8 = either (const Nothing) Just . TE.decodeUtf8'