module Web.Routes.Wai where import qualified Data.ByteString.Char8 as S import qualified Data.ByteString.Lazy.Char8 as L import Data.Enumerator (Iteratee) import Network.Wai ( Application, Request, Response, rawPathInfo , responseLBS) import Network.HTTP.Types (status404) import Web.Routes.Base (decodePathInfo, encodePathInfo) import Web.Routes.PathInfo (PathInfo(..), fromPathInfo, stripOverlap , toPathInfoParams) import Web.Routes.RouteT (RouteT, unRouteT) import Web.Routes.Site (Site(..)) -- | a low-level function for convert a parser, printer, and routing function into an 'Application' handleWaiError :: (url -> [(String, String)] -> String) -- ^ function to convert a 'url' + params into path info + query string -> (String -> Either String url) -- ^ function to parse path info into 'url' -> String -- ^ app root -> (String -> Application) -- ^ function to call if there is a decoding error, argument is the parse error -> ((url -> [(String, String)] -> String) -> url -> Application) -- ^ routing function -> Application handleWaiError fromUrl toUrl approot handleError handler = \request -> do let fUrl = toUrl $ stripOverlap approot $ S.unpack $ rawPathInfo request case fUrl of (Left parseError) -> handleError parseError request (Right url) -> handler (\url params -> showString approot $ fromUrl url params) url request -- | a low-level function for convert a parser, printer, and routing function into an 'Application' -- -- returns 404 if the url parse fails. handleWai_ :: (url -> [(String, String)] -> String) -- ^ function to convert a 'url' + params into path info + query string -> (String -> Either String url) -- ^ function to parse path info into 'url' -> String -- ^ app root -> ((url -> [(String, String)] -> String) -> url -> Application) -- ^ routing function -> Application handleWai_ fromUrl toUrl approot handler = handleWaiError fromUrl toUrl approot handleError handler where handleError :: String -> Application handleError parseError = \_request -> return $ responseLBS status404 [] (L.pack parseError) -- | function to convert a routing function into an Application by -- leveraging 'PathInfo' to do the url conversion handleWai :: (PathInfo url) => String -- ^ approot -> ((url -> [(String, String)] -> String) -> url -> Application) -- ^ routing function -> Application handleWai approot handler = handleWai_ toPathInfoParams fromPathInfo approot handler -- | a function to convert a parser, printer and routing function into an 'Application'. -- -- This is similar to 'handleWai_' expect that it expects the routing function to use 'RouteT'. handleWaiRouteT_ :: (url -> [(String, String)] -> String) -- ^ function to convert a 'url' + params into path info + query string -> (String -> Either String url) -- ^ function to parse path info into 'url' -> String -- ^ app root -> (url -> Request -> RouteT url (Iteratee S.ByteString IO) Response) -- ^ routing function -> Application handleWaiRouteT_ toPathInfo fromPathInfo approot handler = handleWai_ toPathInfo fromPathInfo approot (\toPathInfo' url request -> unRouteT (handler url request) toPathInfo') -- | convert a 'RouteT' based routing function into an 'Application' using 'PathInfo' to do the url conversion handleWaiRouteT :: (PathInfo url) => String -- ^ app root -> (url -> Request -> RouteT url (Iteratee S.ByteString IO) Response) -- ^ routing function -> Application handleWaiRouteT approot handler = handleWaiRouteT_ toPathInfoParams fromPathInfo approot handler -- |convert a 'Site url Application' into a plain-old 'Application' waiSite :: Site url Application -- ^ Site -> String -- ^ approot, e.g. http://www.example.org/app -> Application waiSite site approot = handleWai_ formatURL (parsePathSegments site . decodePathInfo) approot (handleSite site) where formatURL url params = let (paths, moreParams) = formatPathSegments site url in encodePathInfo paths (params ++ moreParams)