on master help sign in
Get routing to work with `ob run` when reloading
commitce602880097e3e63ab2eb91fd352713f158ae2d5 authorRyan Trinkle <ryan.trinkle@gmail.com> dateFri 29 Jun 2018, 22:47 (8 years ago) parent59440af
6 files changed+68−24
dep/reflex-platform/github.json+3−3 lib/asset/manifest/src/Obelisk/Asset/Promoted.hs+8−2 lib/backend/src/Obelisk/Backend.hs+1−1 lib/route/src/Obelisk/Route.hs+9−6 lib/run/obelisk-run.cabal+5 lib/run/src/Obelisk/Run.hs+42−12
dep/reflex-platform/github.json+3−3
@@ -1,7 +1,7 @@
11{
22 "owner": "reflex-frp",
33 "repo": "reflex-platform",
4− "branch": "develop",
5− "rev": "a4d679629b52f80ecae857864591d79d902a5c5d",
6− "sha256": "1p34qc3ryar81jh01g4jm0svr05yri83vlswm2jbxiabigy47652"
4+ "branch": "bump-jsaddle",
5+ "rev": "a83ef44e06121b3352e79a8a88324a0df82e63fb",
6+ "sha256": "1cr9r3isfihg638hxc8faayg9k40kw8bvlqrzc7r8haxvhhxn8ly"
77}
lib/asset/manifest/src/Obelisk/Asset/Promoted.hs+8−2
@@ -63,11 +63,17 @@ staticModuleFile moduleName paths = do
6363 , "{-# LANGUAGE FlexibleInstances #-}"
6464 , "{-# LANGUAGE KindSignatures #-}"
6565 , "{-# LANGUAGE OverloadedStrings #-}"
66+ , "{-# LANGUAGE ScopedTypeVariables #-}"
67+ , "{-# LANGUAGE TypeApplications #-}"
6668 , "module " <> moduleName <> " where"
6769 , ""
6870 , "import qualified GHC.Types"
69− , "import Data.Text ()"
71+ , "import Data.Text (Text)"
7072 , "import qualified Data.Text.Internal"
73+ , "import Data.Monoid ((<>))"
74+ , ""
75+ , "static :: forall a. StaticFile a => Text"
76+ , "static = \"static/\" <> hashedPath @a" --TODO: Use obelisk-route to generate this in a more consistent way
7177 , ""
7278 , T.pack $ pprint decs
7379 ]
@@ -96,7 +102,7 @@ staticClass :: WriterT (Seq Dec) Q StaticContext
96102staticClass = do
97103 let n x = Name (OccName x) NameS
98104 className = n "StaticFile"
99− methodName = n "static"
105+ methodName = n "hashedPath"
100106 cls = ClassD [] className [KindedTV (n "s") (ConT ''Symbol)] [] [SigD methodName (ConT ''Text)]
101107 tell $ Seq.singleton cls
102108 return $ StaticContext
lib/backend/src/Obelisk/Backend.hs+1−1
@@ -45,5 +45,5 @@ backend cfg = do
4545 httpServe httpConf $ route
4646 [ ("", serveApp "" appCfg)
4747 , ("", serveAssets "frontend.jsexe.assets" "frontend.jsexe") --TODO: Can we prevent naming conflicts between frontend.jsexe and static?
48− , ("", serveAssets "static.assets" "static")
48+ , ("static", serveAssets "static.assets" "static")
4949 ]
lib/route/src/Obelisk/Route.hs+9−6
@@ -44,6 +44,9 @@ module Obelisk.Route
4444 , ObeliskRoute (..)
4545 , _ObeliskRoute_App
4646 , _ObeliskRoute_Resource
47+ , ResourceRoute (..)
48+ , JSaddleWarpRoute (..)
49+ , jsaddleWarpRouteEncoder
4750 ) where
4851
4952import Prelude hiding ((.), id)
@@ -480,7 +483,7 @@ resourceComponentEncoder = enum1Encoder $ \case
480483resourceRouteEncoder :: (MonadError Text check, MonadError Text parse) => ResourceRoute a -> Encoder check parse a PageName
481484resourceRouteEncoder = \case
482485 ResourceRoute_Static -> Encoder $ pure pathOnlyValidEncoder
483− ResourceRoute_JSaddleWarp -> jsaddleWarpEncoder
486+ ResourceRoute_JSaddleWarp -> jsaddleWarpRouteEncoder
484487
485488data JSaddleWarpRoute :: * -> * where
486489 JSaddleWarpRoute_JavaScript :: JSaddleWarpRoute ()
@@ -494,14 +497,14 @@ instance Universe (Some JSaddleWarpRoute) where
494497 , Some.This JSaddleWarpRoute_Sync
495498 ]
496499
497−jsaddleWarpComponentEncoder :: (MonadError Text check, MonadError Text parse) => Encoder check parse (Some JSaddleWarpRoute) (Maybe Text)
498−jsaddleWarpComponentEncoder = enum1Encoder $ \case
500+jsaddleWarpRouteComponentEncoder :: (MonadError Text check, MonadError Text parse) => Encoder check parse (Some JSaddleWarpRoute) (Maybe Text)
501+jsaddleWarpRouteComponentEncoder = enum1Encoder $ \case
499502 JSaddleWarpRoute_JavaScript -> Just "jsaddle.js"
500− JSaddleWarpRoute_WebSocket -> Just "websocket"
503+ JSaddleWarpRoute_WebSocket -> Nothing
501504 JSaddleWarpRoute_Sync -> Just "sync"
502505
503−jsaddleWarpEncoder :: (MonadError Text check, MonadError Text parse) => Encoder check parse (R JSaddleWarpRoute) PageName
504−jsaddleWarpEncoder = pathComponentEncoder jsaddleWarpComponentEncoder $ \case
506+jsaddleWarpRouteEncoder :: (MonadError Text check, MonadError Text parse) => Encoder check parse (R JSaddleWarpRoute) PageName
507+jsaddleWarpRouteEncoder = pathComponentEncoder jsaddleWarpRouteComponentEncoder $ \case
505508 JSaddleWarpRoute_JavaScript -> endValidEncoder mempty
506509 JSaddleWarpRoute_WebSocket -> endValidEncoder mempty
507510 JSaddleWarpRoute_Sync -> pathOnlyValidEncoder
lib/run/obelisk-run.cabal+5
@@ -10,6 +10,8 @@ library
1010 attoparsec
1111 , base
1212 , bytestring
13+ , dependent-sum
14+ , dependent-sum-template
1315 , http-client
1416 , http-reverse-proxy
1517 , http-types
@@ -17,12 +19,15 @@ library
1719 , jsaddle-warp
1820 , lens
1921 , modern-uri
22+ , mtl
2023 , network
2124 , obelisk-executable-config
25+ , obelisk-route
2226 , process
2327 , reflex-dom
2428 , streaming-commons
2529 , text
30+ , universe
2631 , wai
2732 , wai-websockets
2833 , warp
lib/run/src/Obelisk/Run.hs+42−12
@@ -1,20 +1,35 @@
1+{-# LANGUAGE EmptyCase #-}
2+{-# LANGUAGE EmptyDataDecls #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE KindSignatures #-}
17{-# LANGUAGE LambdaCase #-}
28{-# LANGUAGE OverloadedStrings #-}
39{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TemplateHaskell #-}
411module Obelisk.Run where
512
13+import Obelisk.Route
14+
615import Control.Concurrent
716import Control.Exception
817import Control.Lens ((^?), _Just, _Right)
18+import Control.Monad.Except
919import qualified Data.Attoparsec.ByteString.Char8 as A
1020import Data.ByteString (ByteString)
1121import qualified Data.ByteString.Char8 as BSC
1222import qualified Data.ByteString.Lazy.Char8 as BSLC
1323import Data.List (uncons)
1424import Data.Maybe
25+import Data.GADT.Compare.TH
26+import Data.GADT.Show
1527import Data.Semigroup ((<>))
28+import Data.Some (Some)
1629import Data.Streaming.Network (bindPortTCP)
30+import Data.Text (Text)
1731import qualified Data.Text as T
32+import Data.Universe
1833import Language.Javascript.JSaddle.Run (syncPoint)
1934import Language.Javascript.JSaddle.WebSockets
2035import Network.HTTP.Client (Manager, defaultManagerSettings, newManager)
@@ -25,7 +40,6 @@ import Network.Wai (Application)
2540import qualified Network.Wai as W
2641import Network.Wai.Handler.Warp
2742import Network.Wai.Handler.Warp.Internal (settingsHost, settingsPort)
28−import Network.Wai.Handler.WebSockets (isWebSocketsReq)
2943import Network.WebSockets (ConnectionOptions)
3044import Network.WebSockets.Connection (defaultConnectionOptions)
3145import Obelisk.ExecutableConfig (get)
@@ -77,28 +91,39 @@ runWidget conf (h, b) = do
7791 app <- obeliskApp defaultConnectionOptions h b (fallbackProxy redirectHost redirectPort man)
7892 runSettingsSocket settings skt app)
7993
94+data Void1 :: * -> * where {}
95+
96+instance Universe (Some Void1) where
97+ universe = []
98+
99+void1Encoder :: (Applicative check, MonadError Text parse) => Encoder check parse (Some Void1) a
100+void1Encoder = Encoder $ pure $ ValidEncoder
101+ { _validEncoder_encode = \case {}
102+ , _validEncoder_decode = \_ -> throwError "void1Encoder: can't decode anything"
103+ }
104+
80105obeliskApp :: ConnectionOptions -> StaticWidget () () -> Widget () () -> Application -> IO Application
81106obeliskApp opts h b backend = do
82107 html <- BSLC.fromStrict <$> indexHtml h
83108 let entryPoint = mainWidget' b >> syncPoint
84− jsaddle <- jsaddleOr opts entryPoint $ \req sendResponse -> case (W.requestMethod req, W.pathInfo req) of
85− ("GET", []) -> sendResponse $ W.responseLBS H.status200 [("Content-Type", "text/html")] html
86− ("GET", ["jsaddle.js"]) -> sendResponse $ W.responseLBS H.status200 [("Content-Type", "application/javascript")] $ jsaddleJs False
109+ Right ve <- return $ checkEncoder $ obeliskRouteEncoder void1Encoder (\case {})
110+ Right (jsaddleWarpRouteValidEncoder :: ValidEncoder (Either Text) (R JSaddleWarpRoute) PageName) <- return $ checkEncoder jsaddleWarpRouteEncoder
111+ jsaddle <- jsaddleWithAppOr opts entryPoint $ error "obeliskApp: jsaddle got a bad URL"
112+ return $ \req sendResponse -> case _validEncoder_decode ve (W.pathInfo req, mempty) of --TODO: Query strings
113+ Right (ObeliskRoute_Resource ResourceRoute_JSaddleWarp :/ jsaddleRoute) -> case jsaddleRoute of
114+ JSaddleWarpRoute_JavaScript :/ () -> sendResponse $ W.responseLBS H.status200 [("Content-Type", "application/javascript")] $ jsaddleJs' (Just "http://localhost:8000/jsaddle") False
115+ _ -> flip jsaddle sendResponse $ req
116+ { W.pathInfo = fst $ _validEncoder_encode jsaddleWarpRouteValidEncoder jsaddleRoute
117+ }
118+ Left _ -> sendResponse $ W.responseLBS H.status200 [("Content-Type", "text/html")] html
87119 _ -> backend req sendResponse
88− -- Workaround jsaddleOr wanting to handle all websockets requests without
89− -- having a chance for run to proxy non jsaddle websocket requests to the
90− -- backend.
91− return $ \req sendResponse -> do
92− if isWebSocketsReq req && not (null $ W.pathInfo req)
93− then backend req sendResponse
94− else jsaddle req sendResponse
95120
96121indexHtml :: StaticWidget () () -> IO ByteString
97122indexHtml h = do
98123 ((), bs) <- renderStatic $ el "html" $ do
99124 el "head" $ h
100125 el "body" $ return ()
101− elAttr "script" ("src" =: "/jsaddle.js") $ return ()
126+ elAttr "script" ("src" =: "/jsaddle/jsaddle.js") $ return ()
102127 return $ "<!DOCTYPE html>" <> bs
103128
104129-- | like 'bindPortTCP' but reconnects on exception
@@ -147,3 +172,8 @@ defRunConfig = RunConfig
147172 , _runConfig_redirectPort = 3001
148173 , _runConfig_retryTimeout = 1
149174 }
175+
176+deriveGCompare ''Void1
177+deriveGEq ''Void1
178+instance GShow Void1 where
179+ gshowsPrec _ = \case {}