1 module Literate.Web.Live where
3 import Control.Applicative (Applicative (..))
4 import Control.Concurrent (threadDelay)
5 import Control.Concurrent.STM (STM)
6 import Control.Concurrent.STM qualified as STM
7 import Control.Monad (void)
8 import Data.ByteString.Builder qualified as BSB
9 import Data.Function (const, ($), (&))
10 import Data.Functor ((<&>))
11 import Data.Map.Strict qualified as Map
12 import Data.Maybe (Maybe (..), maybe)
13 import Data.Text (Text)
14 import Network.Wai qualified as Wai
15 import Network.Wai.Handler.Warp qualified as Warp
16 import Network.Wai.Handler.WebSockets qualified as WaiWs
17 import Network.WebSockets qualified as WS
19 import System.IO qualified as Sys
20 import Prelude (Bounded (..))
22 import Literate.Web qualified as Web
23 import Literate.Web.Live.HTTP
24 import Literate.Web.Live.WebSocket
28 Warp.HostPreference ->
31 (model -> IO (Map.Map Web.OutputPath (IO BSB.Builder))) ->
33 runLive mWsOpts host portMaybe modelSTM siteMapBSB = do
34 iniModel <- STM.atomically modelSTM
36 siteMap model = siteMapBSB model <&> (<&> (<&> BSB.toLazyByteString))
37 settings = Warp.defaultSettings & Warp.setHost host
39 Nothing -> httpApp modelSTM siteMap Nothing
42 WS.defaultConnectionOptions
43 (webSocketApp iniModel modelSTM siteMap)
44 (httpApp modelSTM siteMap (Just webSocketClientJS))
48 (host, "port" :: Text, port, maybe "no ws" (const "ws") mWsOpts :: Text)
49 warpRunSettings settings portMaybe banner app
51 -- Like Warp.runSettings but takes *optional* port. When no port is set,
52 -- a free (random) port is used.
56 (Warp.Port -> IO a) ->
59 warpRunSettings settings portMaybe banner app = do
62 Warp.withApplicationSettings settings (pure app) $ \port -> do
67 Warp.runSettings (Warp.setPort port settings) app