{-# LANGUAGE DataKinds #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} module Web.Suavemente.Core where import Control.Applicative (liftA2) import Control.Concurrent.STM.TVar (TVar, writeTVar) import Control.Monad.Except (throwError) import Control.Monad.IO.Class (liftIO) import Control.Monad.STM (atomically) import Control.Monad.State (evalStateT) import Data.Aeson (Value, decode, Result (..)) import Data.Aeson.Types (Parser, parse) import qualified Data.ByteString.Char8 as B import qualified Data.Map.Strict as M import Data.Proxy (Proxy (..)) import Network.Wai.Handler.Warp (run) import Network.WebSockets (Connection, receiveData, sendTextData) import Servant (Get, Handler, Capture, (:<|>)(..), (:>), serve, err404) import Servant.API.WebSocket (WebSocket) import Servant.HTML.Blaze (HTML) import qualified Streaming as S import qualified Streaming.Prelude as S import Text.Blaze (preEscapedString, Markup, ToMarkup (..)) import Text.Blaze.Renderer.String (renderMarkup) import Text.InterpolatedString.Perl6 (qc, q) import Web.Suavemente.Types ------------------------------------------------------------------------------ -- | Get a 'String' representation of a markup-able type. Useful for -- constructing elements via quasiquotation. showMarkup :: ToMarkup a => a -> String showMarkup = renderMarkup . toMarkup ------------------------------------------------------------------------------ -- | EXPLODE IF PARSING FAILS fromResult :: Result a -> a fromResult (Success a) = a fromResult (Error s) = error s ------------------------------------------------------------------------------ -- | Construct an '_iFold' field for 'Input's. getEvents :: (Value -> Parser a) -> TVar a -- ^ The underlying 'TVar' to publish changes to. -> String -- ^ The name of the HTML input. -> IO () -- ^ Publish a change notification. -> S.Stream (S.Of ChangeEvent) IO () -> S.Stream (S.Of ChangeEvent) IO () getEvents p t n update = S.mapMaybeM ( \a@(ChangeEvent i z) -> case i == n of True -> do liftIO . atomically . writeTVar t . fromResult $ parse p z update pure Nothing False -> pure $ Just a ) ------------------------------------------------------------------------------ -- | HTML code to inject into all 'Suave' pages. htmlPage :: (a -> Markup) -> String -> a -> Markup htmlPage pp res a = preEscapedString $ [q| |] ++ [q| |] ++ [qc|