1 {-# LANGUAGE QuasiQuotes #-}
2 {-# LANGUAGE RecordWildCards #-}
3 {-# LANGUAGE TemplateHaskell #-}
5 module Literate.Web.Live.Common where
7 import Control.Arrow ((>>>))
8 import Data.ByteString qualified as BS
9 import Data.ByteString.Lazy qualified as BSL
11 import Data.Function (($))
12 import Data.Functor ((<&>))
13 import Data.Semigroup (Semigroup (..))
14 import Data.Text (Text)
15 import Data.Text qualified as Text
16 import Data.Text.Encoding qualified as Text
17 import Data.Text.Lazy qualified as TextL
18 import Data.Text.Lazy.Encoding qualified as TextL
19 import System.IO qualified as Sys
21 import Literate.Web qualified as Web
22 import Text.Show (Show)
25 renderCatchingErrors ::
33 m (Asset BSL.ByteString)
34 renderCatchingErrors m r =
35 catch (siteOutput (fromPrism_ $ routePrism m) m r) $ \(err :: SomeException) -> do
36 -- Log the error first.
37 logErrorNS "App" $ show @Text err
43 -- Decode an URL path into a route
45 -- This function is used only in live server. If the route is not
46 -- isomoprhic, this returns a Left, with the mismatched encoding.
49 (Eq r, Show r, IsRoute r) =>
52 Either (BadRouteEncoding r) (Maybe r)
53 decodeUrlRoute m (urlToFilePath -> s) = do
54 case checkRoutePrismGivenFilePath routePrism m s of
55 Left (r, log) -> Left $ BadRouteEncoding s r log
59 -- | A basic error response for displaying in the browser
60 liveErrorHtmlResponse :: Text -> BSL.ByteString
61 liveErrorHtmlResponse err = mkHtmlErrorMsg err <> BSL.fromStrict wsClientHtml
63 urlToFilePath :: Text -> Sys.FilePath
66 >>> (<&> (Web.textToPathSegment >>> Web.pathSegmentToText))
67 >>> Text.intercalate "/"
70 mkHtmlErrorMsg :: Text -> BSL.ByteString
71 mkHtmlErrorMsg s = TextL.encodeUtf8 $ TextL.replace "MESSAGE" (TextL.fromStrict s) $ TextL.fromStrict $ Text.decodeUtf8 $ emaErrorHtml
73 emaErrorHtml :: BS.ByteString
74 emaErrorHtml = $(embedFile "www/live-error.html")
76 decodeRouteNothingMsg :: Text
77 decodeRouteNothingMsg = "Literate.Web.Live: 404 (route decoding returned Nothing)"
79 data BadRouteEncoding r = BadRouteEncoding
80 { _bre_urlFilePath :: Sys.FilePath
81 , _bre_decodedRoute :: r
82 , _bre_checkLog :: [(Sys.FilePath, Text)]
86 wsClientHtml :: BS.ByteString
87 wsClientHtml = $(embedFile "www/live-indicator.html")
90 badRouteEncodingMsg :: (Show r) => BadRouteEncoding r -> Text
91 badRouteEncodingMsg BadRouteEncoding {..} =
93 "A route Prism' is unlawful.\n\nThe URL '"
94 <> toText _bre_urlFilePath
95 <> "' decodes to route '"
96 <> show _bre_decodedRoute
97 <> "', but it is not isomporphic on any of the allowed candidates: \n\n"
100 ( _bre_checkLog <&> \(candidate, log) ->
101 "## Candidate '" <> toText candidate <> "':\n" <> log
103 <> " \n\nYou should make the relevant routePrism lawful to fix this issue."