{-# LANGUAGE OverloadedStrings, RankNTypes #-}
module Web.Scotty.Trans
(
scottyT, scottyAppT, scottyOptsT, Options(..)
, middleware, get, post, put, delete, patch, addroute, matchAny, notFound
, capture, regex, function, literal
, request, header, headers, body, param, params, jsonData, files
, status, addHeader, setHeader, redirect
, text, html, file, json, stream, source, raw
, raise, rescue, next, defaultHandler, ScottyError(..)
, Param, Parsable(..), readEither
, RoutePattern, File
, ScottyT, ActionT
) where
import Blaze.ByteString.Builder (Builder, fromByteString)
import Control.Monad (when)
import Control.Monad.State (execStateT, modify)
import Control.Monad.IO.Class
import Data.Conduit (Flush, Source)
import Data.Default (def)
import Network.HTTP.Types (status404)
import Network.Wai
import Network.Wai.Handler.Warp (Port, runSettings, setPort, getPort)
import Web.Scotty.Action hiding (source)
import qualified Web.Scotty.Action as Action
import Web.Scotty.Route
import Web.Scotty.Internal.Types hiding (Application, Middleware)
import qualified Web.Scotty.Internal.Types as Scotty
source :: (ScottyError e, Monad m) => Source IO (Flush Builder) -> ActionT e m ()
source = Action.source
{-# DEPRECATED source "Use 'stream' instead. This will be removed in the next release." #-}
scottyT :: (Monad m, MonadIO n)
=> Port
-> (forall a. m a -> n a)
-> (m Response -> IO Response)
-> ScottyT e m ()
-> n ()
scottyT p = scottyOptsT $ def { settings = setPort p (settings def) }
scottyOptsT :: (Monad m, MonadIO n)
=> Options
-> (forall a. m a -> n a)
-> (m Response -> IO Response)
-> ScottyT e m ()
-> n ()
scottyOptsT opts runM runActionToIO s = do
when (verbose opts > 0) $
liftIO $ putStrLn $ "Setting phasers to stun... (port " ++ show (getPort (settings opts)) ++ ") (ctrl-c to quit)"
liftIO . runSettings (settings opts) =<< scottyAppT runM runActionToIO s
scottyAppT :: (Monad m, Monad n)
=> (forall a. m a -> n a)
-> (m Response -> IO Response)
-> ScottyT e m ()
-> n Application
scottyAppT runM runActionToIO defs = do
s <- runM $ execStateT (runS defs) def
let rapp = \ req callback -> runActionToIO (foldl (flip ($)) notFoundApp (routes s) req) >>= callback
return $ foldl (flip ($)) rapp (middlewares s)
notFoundApp :: Monad m => Scotty.Application m
notFoundApp _ = return $ responseBuilder status404 [("Content-Type","text/html")]
$ fromByteString "<h1>404: File Not Found!</h1>"
defaultHandler :: Monad m => (e -> ActionT e m ()) -> ScottyT e m ()
defaultHandler f = ScottyT $ modify $ addHandler $ Just f
middleware :: Monad m => Middleware -> ScottyT e m ()
middleware = ScottyT . modify . addMiddleware