@@ -6,7 +6,7 @@
66{-# LANGUAGE MultiParamTypeClasses #-}
77{-# LANGUAGE OverloadedStrings #-}
88{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE TemplateHaskell #-}
9+{-# OPTIONS_GHC -fno-warn-orphans #-}
1010module Obelisk.Backend
1111 ( Backend (..)
1212 -- * Re-exports
@@ -42,7 +42,8 @@ import Obelisk.Route
4242import Obelisk.Snap.Extras (doNotCache, serveFileIfExistsAs)
4343import Reflex.Dom
4444import Snap (MonadSnap, Snap, commandLineConfig, defaultConfig, getsRequest, httpServe, modifyResponse
45− , rqPathInfo, rqQueryString, setContentType, writeBS, writeText)
45+ , rqPathInfo, rqQueryString, setContentType, writeBS, writeText
46+ , rqCookies, Cookie(..))
4647import Snap.Internal.Http.Server.Config (Config (accessLog, errorLog), ConfigLog (ConfigIoLog))
4748import System.IO (BufferMode (..), hSetBuffering, stderr, stdout)
4849
@@ -59,7 +60,15 @@ data GhcjsApp route = GhcjsApp
5960
6061-- | Serve a frontend, which must be the same frontend that Obelisk has built and placed in the default location
6162--TODO: The frontend should be provided together with the asset paths so that this isn't so easily breakable; that will probably make this function obsolete
62−serveDefaultObeliskApp :: MonadSnap m => (R appRoute -> Text) -> ([Text] -> m ()) -> Frontend (R appRoute) -> R (ObeliskRoute appRoute) -> m ()
63+serveDefaultObeliskApp
64+ :: (MonadSnap m, HasCookies m)
65+ => (R appRoute
66+ -> Text)
67+ -> ([Text]
68+ -> m ())
69+ -> Frontend (R appRoute)
70+ -> R (ObeliskRoute appRoute)
71+ -> m ()
6372serveDefaultObeliskApp urlEnc serveStaticAsset frontend = serveObeliskApp urlEnc serveStaticAsset frontendApp
6473 where frontendApp = GhcjsApp
6574 { _ghcjsApp_compiled = defaultFrontendGhcjsAssets
@@ -111,7 +120,13 @@ getRouteWith e = do
111120 pageName <- getPageName
112121 return $ tryDecode e pageName
113122
114−serveObeliskApp :: MonadSnap m => (R appRoute -> Text) -> ([Text] -> m ()) -> GhcjsApp (R appRoute) -> R (ObeliskRoute appRoute) -> m ()
123+serveObeliskApp
124+ :: (MonadSnap m, HasCookies m)
125+ => (R appRoute -> Text)
126+ -> ([Text] -> m ())
127+ -> GhcjsApp (R appRoute)
128+ -> R (ObeliskRoute appRoute)
129+ -> m ()
115130serveObeliskApp urlEnc serveStaticAsset frontendApp = \case
116131 ObeliskRoute_App appRouteComponent :=> Identity appRouteRest -> serveGhcjsApp urlEnc frontendApp $ GhcjsAppRoute_App appRouteComponent :/ appRouteRest
117132 ObeliskRoute_Resource resComponent :=> Identity resRest -> case resComponent :=> Identity resRest of
@@ -140,11 +155,16 @@ staticRenderContentType :: ByteString
140155staticRenderContentType = "text/html; charset=utf-8"
141156
142157--TODO: Don't assume we're being served at "/"
143−serveGhcjsApp :: MonadSnap m => (R appRouteComponent -> Text) -> GhcjsApp (R appRouteComponent) -> R (GhcjsAppRoute appRouteComponent) -> m ()
158+serveGhcjsApp
159+ :: (MonadSnap m, HasCookies m)
160+ => (R appRouteComponent -> Text)
161+ -> GhcjsApp (R appRouteComponent)
162+ -> R (GhcjsAppRoute appRouteComponent)
163+ -> m ()
144164serveGhcjsApp urlEnc app = \case
145165 GhcjsAppRoute_App appRouteComponent :=> Identity appRouteRest -> do
146166 modifyResponse $ setContentType staticRenderContentType
147− writeBS <=< liftIO $ renderGhcjsFrontend urlEnc (appRouteComponent :/ appRouteRest) $ _ghcjsApp_value app
167+ writeBS <=< renderGhcjsFrontend urlEnc (appRouteComponent :/ appRouteRest) $ _ghcjsApp_value app
148168 GhcjsAppRoute_Resource :=> Identity pathSegments -> serveStaticAssets (_ghcjsApp_compiled app) pathSegments
149169
150170runBackend :: Backend fullRoute frontendRoute -> Frontend (R frontendRoute) -> IO ()
@@ -163,11 +183,19 @@ mkRouteToUrl validFullEncoder =
163183 let pageNameEncoder' :: Encoder Identity (Either Text) PageName PathQuery = pageNameEncoder
164184 in \(k :/ v) -> T.pack . uncurry (<>) . encode pageNameEncoder' . encode validFullEncoder $ (InR $ ObeliskRoute_App k) :/ v
165185
166−
167−renderGhcjsFrontend :: MonadIO m => (route -> Text) -> route -> Frontend route -> m ByteString
186+renderGhcjsFrontend
187+ :: (MonadSnap m, HasCookies m)
188+ => (route -> Text)
189+ -> route
190+ -> Frontend route
191+ -> m ByteString
168192renderGhcjsFrontend urlEnc route f = do
169193 let ghcjsPreload = elAttr "link" ("rel" =: "preload" <> "as" =: "script" <> "href" =: "ghcjs/all.js") blank
170194 ghcjsScript = elAttr "script" ("language" =: "javascript" <> "src" =: "ghcjs/all.js" <> "defer" =: "defer") blank
171− liftIO $ renderFrontendHtml urlEnc route
195+ cookies <- askCookies
196+ renderFrontendHtml cookies urlEnc route
172197 (_frontend_head f >> ghcjsPreload)
173198 (_frontend_body f >> ghcjsScript)
199+
200+instance HasCookies Snap where
201+ askCookies = map (\c -> (cookieName c, cookieValue c)) <$> getsRequest rqCookies