{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Network.Wai.Routing.Purescheme.Core.Basic
( GenericApplication
, Rejection(..)
, FromUri(..)
, HasResponseHeaders(..)
, alternatives
, handleException
, withDefaultExceptionHandler
, complete
, completeIO
, mapResponse
, withRequest
)
where
import Network.Wai.Routing.Purescheme.Core.Internal
import Control.Exception (Exception, catch)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as LBS
import Data.Int (Int32, Int64)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as LT
import Network.HTTP.Types (ResponseHeaders, hContentType)
import Network.Wai (Response, ResponseReceived, Request, responseLBS)
import qualified Network.Wai as Wai
type GenericApplication r = Request -> (r -> IO ResponseReceived) -> IO ResponseReceived
class FromUri a where
fromText :: T.Text -> a
fromByteString :: ByteString -> a
fromByteString = fromText . T.decodeUtf8
instance FromUri T.Text where
fromText = id
instance FromUri Bool where
fromText p = read $ T.unpack p
instance FromUri Int where
fromText p = read $ T.unpack p
instance FromUri Int32 where
fromText p = read $ T.unpack p
instance FromUri Int64 where
fromText p = read $ T.unpack p
instance FromUri LT.Text where
fromText = LT.fromStrict
class HasResponseHeaders a where
mapResponseHeaders :: (ResponseHeaders -> ResponseHeaders) -> a -> a
instance HasResponseHeaders Response where
mapResponseHeaders = Wai.mapResponseHeaders
alternatives :: [GenericApplication r] -> GenericApplication r
alternatives = alternatives' notFoundDefaultRejection
where
alternatives' :: Rejection -> [GenericApplication r] -> GenericApplication r
alternatives' rejection [] _ _ = reject' rejection
alternatives' rejection (x:xs) req respond =
x req respond `catch` \e -> alternatives' (chooseRejection rejection e) xs req respond
chooseRejection r1 r2 =
if priority r1 < priority r2
then r2
else r1
handleException :: Exception e => (e -> GenericApplication a) -> GenericApplication a -> GenericApplication a
handleException exceptionFunc innerApp req resp =
catch (innerApp req resp) (\e -> exceptionFunc e req resp)
withDefaultExceptionHandler :: GenericApplication Response -> GenericApplication Response
withDefaultExceptionHandler = handleException handleRejection
where
handleRejection :: Rejection -> GenericApplication Response
handleRejection Rejection{status, message} _ respond =
respond $ responseLBS status [(hContentType, "text/plain")] (LBS.fromStrict $ T.encodeUtf8 message)
complete :: a -> GenericApplication a
complete response _ respond = respond response
completeIO :: IO a -> GenericApplication a
completeIO responseIO _ respond = do
response <- responseIO
respond response
mapResponse :: (a -> b) -> GenericApplication a -> GenericApplication b
mapResponse mapf inner req respond = inner req (respond . mapf)
withRequest :: (Request -> GenericApplication a) -> GenericApplication a
withRequest reqFun req = reqFun req req