From ce06b07d6dae781fe09e4b0512a9b6d41ba687a6 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Fri, 14 Aug 2020 01:43:30 +0200 Subject: WIP --- README.md | 20 ++++++++++++++++++ server/lib/Uplcg/BaseUrl.hs | 17 ++++++++++++++++ server/lib/Uplcg/Main/Server.hs | 45 ++++++++++++++++++++++++----------------- server/lib/Uplcg/Views.hs | 19 +++++++++++++++++ server/uplcg.cabal | 5 ++++- 5 files changed, 87 insertions(+), 19 deletions(-) create mode 100644 README.md create mode 100644 server/lib/Uplcg/BaseUrl.hs create mode 100644 server/lib/Uplcg/Views.hs diff --git a/README.md b/README.md new file mode 100644 index 0000000..da95309 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# Untitled PL Card Game + +## Event Info + +Untitled PL Card Game is a game heavily inspired by [Cards Against Humanity], +[Cards Against Cryptography], and [Apples to Apples]. + +We've created custom cards that relate to ICFP2020 and free of the racism, +sexism and homophobia appearing in the original version. + +Another change we've made to the game is that there is a democratic voting round +at the end of each play phase, rather than the starting player picking the +winner. + +The game can be fully played in the browser, but we'll have a video call along +the side to make it more social. + +[Cards Against Humanity]: https://cardsagainsthumanity.com/ +[Cards Against Cryptography]: https://github.com/CardsAgainstCryptography/CAC +[Apples to Apples]: https://en.wikipedia.org/wiki/Apples_to_Apples diff --git a/server/lib/Uplcg/BaseUrl.hs b/server/lib/Uplcg/BaseUrl.hs new file mode 100644 index 0000000..4374322 --- /dev/null +++ b/server/lib/Uplcg/BaseUrl.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE OverloadedStrings #-} +module Uplcg.BaseUrl + ( BaseUrl (..) + , parse + , render + ) where + +import qualified Data.Text as T + +newtype BaseUrl = BaseUrl [T.Text] + +render :: BaseUrl -> T.Text +render (BaseUrl []) = "" +render (BaseUrl xs) = "/" <> T.intercalate "/" xs + +parse :: T.Text -> BaseUrl +parse = BaseUrl . filter (not . T.null) . T.split (== '/') diff --git a/server/lib/Uplcg/Main/Server.hs b/server/lib/Uplcg/Main/Server.hs index a2914ab..72d9614 100644 --- a/server/lib/Uplcg/Main/Server.hs +++ b/server/lib/Uplcg/Main/Server.hs @@ -10,6 +10,7 @@ import qualified Control.Concurrent.STM as STM import Control.Exception (bracket) import Control.Lens ((&), (.~), (^.)) import Control.Monad (forever, when) +import Control.Monad.Trans (liftIO) import qualified Data.Aeson as Aeson import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL @@ -30,9 +31,13 @@ import qualified Network.WebSockets as WS import System.Environment (getEnv) import qualified System.Log.FastLogger as FL import System.Random (StdGen, newStdGen) +import Text.Blaze.Html.Renderer.Text (renderHtml) +import Uplcg.BaseUrl (BaseUrl) +import qualified Uplcg.BaseUrl as BaseUrl import qualified Uplcg.CookieSocket as CookieSocket import Uplcg.Game import Uplcg.Messages +import qualified Uplcg.Views as Views import qualified Web.Scotty as Scotty type RoomId = T.Text @@ -46,7 +51,8 @@ data Room = Room } data Server = Server - { serverLogger :: FL.FastLogger + { serverBaseUrl :: BaseUrl + , serverLogger :: FL.FastLogger , serverCookieSocket :: CookieSocket.Handle Player , serverCards :: Cards , serverRooms :: MVar (HMS.HashMap RoomId Room) @@ -60,9 +66,9 @@ readCards = Cards parseCards = V.fromList . filter (not . T.null) . map dropComment . T.lines dropComment = T.strip . fst . T.break (== '#') -withServer :: FL.FastLogger -> (Server -> IO a) -> IO a -withServer fl f = CookieSocket.withHandle 5 $ \cs -> do - f =<< Server fl cs <$> readCards <*> MVar.newMVar HMS.empty +withServer :: BaseUrl -> FL.FastLogger -> (Server -> IO a) -> IO a +withServer base fl f = CookieSocket.withHandle 5 $ \cs -> do + f =<< Server base fl cs <$> readCards <*> MVar.newMVar HMS.empty newRoom :: RoomId -> Cards -> StdGen -> STM Room newRoom rid cards gen = Room rid @@ -74,8 +80,13 @@ parseRoomId txt | T.all isAlphaNum txt && T.length txt >= 6 = Right txt | otherwise = Left "Bad room name" -scottyApp :: IO Wai.Application -scottyApp = Scotty.scottyApp $ do +scottyApp :: Server -> IO Wai.Application +scottyApp server = Scotty.scottyApp $ do + Scotty.get "/rooms" $ do + rooms <- liftIO . MVar.readMVar $ serverRooms server + Scotty.html . renderHtml . Views.rooms (serverBaseUrl server) $ + HMS.keys rooms + Scotty.get "/rooms/:id/" $ do rid <- Scotty.param "id" when (T.length rid < 6) $ @@ -94,9 +105,10 @@ scottyApp = Scotty.scottyApp $ do routePendingConnection :: WS.PendingConnection -> Maybe RoomId routePendingConnection pending = let path = T.decodeUtf8 . WS.requestPath $ WS.pendingRequest pending in - case splitPath path of - ["rooms", txt, "events"] | Right r <- parseRoomId txt -> Just r - _ -> Nothing + case BaseUrl.parse path of + BaseUrl.BaseUrl ["rooms", txt, "events"] | Right r <- parseRoomId txt -> + Just r + _ -> Nothing getOrCreateRoom :: Server -> RoomId -> IO Room getOrCreateRoom server rid = MVar.modifyMVar (serverRooms server) $ \rooms -> @@ -183,11 +195,8 @@ wsApp server pc = case routePendingConnection pc of serverLogger server $ "Could not decode client message: " <> FL.toLogStr (show msg) -splitPath :: T.Text -> [T.Text] -splitPath = filter (not . T.null) . T.split (== '/') - -baseUrl :: [T.Text] -> Wai.Middleware -baseUrl prefix application = \req -> +baseUrl :: BaseUrl -> Wai.Middleware +baseUrl base@(BaseUrl.BaseUrl prefix) application = \req -> case L.stripPrefix prefix (Wai.pathInfo req) of Nothing -> application req Just path -> application req @@ -196,19 +205,19 @@ baseUrl prefix application = \req -> B.stripPrefix bs $ Wai.rawPathInfo req } where - bs = T.encodeUtf8 $ "/" <> T.intercalate "/" prefix + bs = T.encodeUtf8 $ BaseUrl.render base main :: IO () main = do host <- fromString <$> getEnv "UPLCG_HOSTNAME" port <- read <$> getEnv "UPLCG_PORT" - base <- splitPath . T.pack <$> getEnv "UPLCG_BASE" + base <- BaseUrl.parse . T.pack <$> getEnv "UPLCG_BASE" let settings = Warp.setPort port . Warp.setHost host $ Warp.defaultSettings timeCache <- FL.newTimeCache FL.simpleTimeFormat FL.withTimedFastLogger timeCache (FL.LogStderr FL.defaultBufSize) $ \tfl -> let fl s = tfl (\time -> FL.toLogStr time <> " " <> s <> "\n") in - withServer fl $ \server -> do - sapp <- scottyApp + withServer base fl $ \server -> do + sapp <- scottyApp server Warp.runSettings settings $ baseUrl base $ WaiWs.websocketsOr WS.defaultConnectionOptions (wsApp server) sapp diff --git a/server/lib/Uplcg/Views.hs b/server/lib/Uplcg/Views.hs new file mode 100644 index 0000000..91b03ff --- /dev/null +++ b/server/lib/Uplcg/Views.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE OverloadedStrings #-} +module Uplcg.Views + ( rooms + ) where + +import Data.Text (Text) +import qualified Text.Blaze.Html5 as H +import qualified Text.Blaze.Html5.Attributes as A +import Uplcg.BaseUrl (BaseUrl) +import qualified Uplcg.BaseUrl as BaseUrl + +rooms :: BaseUrl -> [Text] -> H.Html +rooms base _ids = H.docTypeHtml $ do + H.head $ do + H.meta H.! A.charset "UTF-8" + H.link H.! A.rel "stylesheet" H.! A.type_ "text/css" + H.! A.href (H.toValue $ BaseUrl.render base <> "/assets/style.css") + H.body $ do + H.footer $ "Untitled PL Card Game" diff --git a/server/uplcg.cabal b/server/uplcg.cabal index 830c01a..403facd 100644 --- a/server/uplcg.cabal +++ b/server/uplcg.cabal @@ -16,16 +16,19 @@ Library Hs-source-dirs: lib Exposed-modules: + Uplcg.BaseUrl Uplcg.CookieSocket Uplcg.Game - Uplcg.Messages Uplcg.Main.GenerateElmTypes Uplcg.Main.Server + Uplcg.Messages + Uplcg.Views Build-depends: aeson >= 1.4 && < 1.5, async >= 2.2 && < 2.3, base >= 4.9 && < 5, + blaze-html >= 0.9 && < 0.10, bytestring >= 0.10 && < 0.11, elm-bridge >= 0.5 && < 0.6, fast-logger >= 3.0 && < 3.1, -- cgit v1.2.3 From b250aa81e332c612551803d0d156246b853b3fd3 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Fri, 14 Aug 2020 10:49:36 +0200 Subject: Actually list rooms --- server/lib/Uplcg/Main/Server.hs | 5 +++++ server/lib/Uplcg/Views.hs | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/server/lib/Uplcg/Main/Server.hs b/server/lib/Uplcg/Main/Server.hs index 72d9614..bd2b3ec 100644 --- a/server/lib/Uplcg/Main/Server.hs +++ b/server/lib/Uplcg/Main/Server.hs @@ -23,6 +23,7 @@ import Data.String (fromString) import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T +import qualified Data.Text.Lazy as TL import qualified Data.Vector as V import qualified Network.Wai as Wai import qualified Network.Wai.Handler.Warp as Warp @@ -82,6 +83,10 @@ parseRoomId txt scottyApp :: Server -> IO Wai.Application scottyApp server = Scotty.scottyApp $ do + Scotty.get "/" $ + Scotty.redirect $ TL.fromStrict $ + BaseUrl.render (serverBaseUrl server) <> "/rooms" + Scotty.get "/rooms" $ do rooms <- liftIO . MVar.readMVar $ serverRooms server Scotty.html . renderHtml . Views.rooms (serverBaseUrl server) $ diff --git a/server/lib/Uplcg/Views.hs b/server/lib/Uplcg/Views.hs index 91b03ff..90716c1 100644 --- a/server/lib/Uplcg/Views.hs +++ b/server/lib/Uplcg/Views.hs @@ -3,6 +3,7 @@ module Uplcg.Views ( rooms ) where +import Data.Foldable (for_) import Data.Text (Text) import qualified Text.Blaze.Html5 as H import qualified Text.Blaze.Html5.Attributes as A @@ -10,10 +11,14 @@ import Uplcg.BaseUrl (BaseUrl) import qualified Uplcg.BaseUrl as BaseUrl rooms :: BaseUrl -> [Text] -> H.Html -rooms base _ids = H.docTypeHtml $ do +rooms base rids = H.docTypeHtml $ do H.head $ do H.meta H.! A.charset "UTF-8" H.link H.! A.rel "stylesheet" H.! A.type_ "text/css" H.! A.href (H.toValue $ BaseUrl.render base <> "/assets/style.css") H.body $ do + H.h1 "Rooms" + H.ul $ for_ rids $ \rid -> H.li $ + H.a H.! A.href (H.toValue $ BaseUrl.render base <> "/rooms/" <> rid) $ + H.toHtml rid H.footer $ "Untitled PL Card Game" -- cgit v1.2.3 From 41622353bc3309921109f44bc0163e0987c20052 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Fri, 14 Aug 2020 17:32:00 +0200 Subject: List room num members --- server/lib/Uplcg/Main/Server.hs | 17 +++++++++++++---- server/lib/Uplcg/Views.hs | 12 +++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/server/lib/Uplcg/Main/Server.hs b/server/lib/Uplcg/Main/Server.hs index bd2b3ec..bd89540 100644 --- a/server/lib/Uplcg/Main/Server.hs +++ b/server/lib/Uplcg/Main/Server.hs @@ -24,6 +24,7 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import qualified Data.Text.Lazy as TL +import Data.Traversable (for) import qualified Data.Vector as V import qualified Network.Wai as Wai import qualified Network.Wai.Handler.Warp as Warp @@ -78,8 +79,17 @@ newRoom rid cards gen = Room rid parseRoomId :: T.Text -> Either String T.Text parseRoomId txt - | T.all isAlphaNum txt && T.length txt >= 6 = Right txt + | T.all isAlphaNum txt && l >= 6 && l <= 32 = Right txt | otherwise = Left "Bad room name" + where + l = T.length txt + +roomViews :: Server -> IO [Views.RoomView] +roomViews server = do + rooms <- liftIO . MVar.readMVar $ serverRooms server + liftIO . for (HMS.toList rooms) $ \(rid, room) -> + fmap (Views.RoomView rid . HMS.size) . atomically . STM.readTVar $ + roomSinks room scottyApp :: Server -> IO Wai.Application scottyApp server = Scotty.scottyApp $ do @@ -88,9 +98,8 @@ scottyApp server = Scotty.scottyApp $ do BaseUrl.render (serverBaseUrl server) <> "/rooms" Scotty.get "/rooms" $ do - rooms <- liftIO . MVar.readMVar $ serverRooms server - Scotty.html . renderHtml . Views.rooms (serverBaseUrl server) $ - HMS.keys rooms + views <- liftIO $ roomViews server + Scotty.html . renderHtml $ Views.rooms (serverBaseUrl server) views Scotty.get "/rooms/:id/" $ do rid <- Scotty.param "id" diff --git a/server/lib/Uplcg/Views.hs b/server/lib/Uplcg/Views.hs index 90716c1..ef4bc09 100644 --- a/server/lib/Uplcg/Views.hs +++ b/server/lib/Uplcg/Views.hs @@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} module Uplcg.Views - ( rooms + ( RoomView (..) + , rooms ) where import Data.Foldable (for_) @@ -10,7 +11,9 @@ import qualified Text.Blaze.Html5.Attributes as A import Uplcg.BaseUrl (BaseUrl) import qualified Uplcg.BaseUrl as BaseUrl -rooms :: BaseUrl -> [Text] -> H.Html +data RoomView = RoomView Text Int + +rooms :: BaseUrl -> [RoomView] -> H.Html rooms base rids = H.docTypeHtml $ do H.head $ do H.meta H.! A.charset "UTF-8" @@ -18,7 +21,10 @@ rooms base rids = H.docTypeHtml $ do H.! A.href (H.toValue $ BaseUrl.render base <> "/assets/style.css") H.body $ do H.h1 "Rooms" - H.ul $ for_ rids $ \rid -> H.li $ + H.ul $ for_ rids $ \(RoomView rid num) -> H.li $ do H.a H.! A.href (H.toValue $ BaseUrl.render base <> "/rooms/" <> rid) $ H.toHtml rid + " (" + H.toHtml num + ")" H.footer $ "Untitled PL Card Game" -- cgit v1.2.3 From 9f2d12f0b098a365d7b0d4cc00b03fd2e5284740 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Sun, 16 Aug 2020 10:21:14 +0200 Subject: WIP --- server/lib/Uplcg/BaseUrl.hs | 2 +- server/lib/Uplcg/Config.hs | 24 +++++++++++++ server/lib/Uplcg/Main/Server.hs | 26 +++++++------- server/lib/Uplcg/Views.hs | 80 ++++++++++++++++++++++++++++++++++------- server/uplcg.cabal | 1 + 5 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 server/lib/Uplcg/Config.hs diff --git a/server/lib/Uplcg/BaseUrl.hs b/server/lib/Uplcg/BaseUrl.hs index 4374322..f49d0d0 100644 --- a/server/lib/Uplcg/BaseUrl.hs +++ b/server/lib/Uplcg/BaseUrl.hs @@ -7,7 +7,7 @@ module Uplcg.BaseUrl import qualified Data.Text as T -newtype BaseUrl = BaseUrl [T.Text] +newtype BaseUrl = BaseUrl [T.Text] deriving (Show) render :: BaseUrl -> T.Text render (BaseUrl []) = "" diff --git a/server/lib/Uplcg/Config.hs b/server/lib/Uplcg/Config.hs new file mode 100644 index 0000000..627a829 --- /dev/null +++ b/server/lib/Uplcg/Config.hs @@ -0,0 +1,24 @@ +module Uplcg.Config + ( Config (..) + , fromEnv + ) where + +import Data.String (fromString) +import qualified Data.Text as T +import System.Environment (getEnv) +import Uplcg.BaseUrl (BaseUrl) +import qualified Uplcg.BaseUrl as BaseUrl + +data Config = Config + { cHostname :: String + , cPort :: Int + , cBaseUrl :: BaseUrl + , cVersion :: String + } deriving (Show) + +fromEnv :: IO Config +fromEnv = Config + <$> getEnv "UPLCG_HOSTNAME" + <*> (read <$> getEnv "UPLCG_PORT") + <*> (BaseUrl.parse . T.pack <$> getEnv "UPLCG_BASE") + <*> getEnv "UPLCG_VERSION" diff --git a/server/lib/Uplcg/Main/Server.hs b/server/lib/Uplcg/Main/Server.hs index bd89540..72b9377 100644 --- a/server/lib/Uplcg/Main/Server.hs +++ b/server/lib/Uplcg/Main/Server.hs @@ -36,6 +36,8 @@ import System.Random (StdGen, newStdGen) import Text.Blaze.Html.Renderer.Text (renderHtml) import Uplcg.BaseUrl (BaseUrl) import qualified Uplcg.BaseUrl as BaseUrl +import Uplcg.Config (Config) +import qualified Uplcg.Config as Config import qualified Uplcg.CookieSocket as CookieSocket import Uplcg.Game import Uplcg.Messages @@ -53,7 +55,7 @@ data Room = Room } data Server = Server - { serverBaseUrl :: BaseUrl + { serverConfig :: Config , serverLogger :: FL.FastLogger , serverCookieSocket :: CookieSocket.Handle Player , serverCards :: Cards @@ -68,9 +70,9 @@ readCards = Cards parseCards = V.fromList . filter (not . T.null) . map dropComment . T.lines dropComment = T.strip . fst . T.break (== '#') -withServer :: BaseUrl -> FL.FastLogger -> (Server -> IO a) -> IO a -withServer base fl f = CookieSocket.withHandle 5 $ \cs -> do - f =<< Server base fl cs <$> readCards <*> MVar.newMVar HMS.empty +withServer :: Config -> FL.FastLogger -> (Server -> IO a) -> IO a +withServer conf fl f = CookieSocket.withHandle 5 $ \cs -> do + f =<< Server conf fl cs <$> readCards <*> MVar.newMVar HMS.empty newRoom :: RoomId -> Cards -> StdGen -> STM Room newRoom rid cards gen = Room rid @@ -95,11 +97,11 @@ scottyApp :: Server -> IO Wai.Application scottyApp server = Scotty.scottyApp $ do Scotty.get "/" $ Scotty.redirect $ TL.fromStrict $ - BaseUrl.render (serverBaseUrl server) <> "/rooms" + BaseUrl.render (Config.cBaseUrl $ serverConfig server) <> "/rooms" Scotty.get "/rooms" $ do views <- liftIO $ roomViews server - Scotty.html . renderHtml $ Views.rooms (serverBaseUrl server) views + Scotty.html . renderHtml $ Views.rooms (serverConfig server) views Scotty.get "/rooms/:id/" $ do rid <- Scotty.param "id" @@ -223,15 +225,15 @@ baseUrl base@(BaseUrl.BaseUrl prefix) application = \req -> main :: IO () main = do - host <- fromString <$> getEnv "UPLCG_HOSTNAME" - port <- read <$> getEnv "UPLCG_PORT" - base <- BaseUrl.parse . T.pack <$> getEnv "UPLCG_BASE" - let settings = Warp.setPort port . Warp.setHost host $ Warp.defaultSettings + config <- Config.fromEnv + let settings = Warp.setPort (Config.cPort config) . + Warp.setHost (fromString $ Config.cHostname config) $ + Warp.defaultSettings timeCache <- FL.newTimeCache FL.simpleTimeFormat FL.withTimedFastLogger timeCache (FL.LogStderr FL.defaultBufSize) $ \tfl -> let fl s = tfl (\time -> FL.toLogStr time <> " " <> s <> "\n") in - withServer base fl $ \server -> do + withServer config fl $ \server -> do sapp <- scottyApp server - Warp.runSettings settings $ baseUrl base $ + Warp.runSettings settings $ baseUrl (Config.cBaseUrl config) $ WaiWs.websocketsOr WS.defaultConnectionOptions (wsApp server) sapp diff --git a/server/lib/Uplcg/Views.hs b/server/lib/Uplcg/Views.hs index ef4bc09..3cb9ebe 100644 --- a/server/lib/Uplcg/Views.hs +++ b/server/lib/Uplcg/Views.hs @@ -8,23 +8,79 @@ import Data.Foldable (for_) import Data.Text (Text) import qualified Text.Blaze.Html5 as H import qualified Text.Blaze.Html5.Attributes as A -import Uplcg.BaseUrl (BaseUrl) +import qualified Data.ByteString.Lazy.Builder as BLB import qualified Uplcg.BaseUrl as BaseUrl +import Uplcg.Config data RoomView = RoomView Text Int -rooms :: BaseUrl -> [RoomView] -> H.Html -rooms base rids = H.docTypeHtml $ do +template :: Config -> Text -> H.Html -> H.Html +template conf title body = H.docTypeHtml $ do H.head $ do H.meta H.! A.charset "UTF-8" H.link H.! A.rel "stylesheet" H.! A.type_ "text/css" - H.! A.href (H.toValue $ BaseUrl.render base <> "/assets/style.css") + H.! A.href (H.toValue $ + BaseUrl.render (cBaseUrl conf) <> "/assets/style.css") + H.title $ H.toHtml title + H.meta H.! A.name "viewport" H.! A.content "width=device-width" H.body $ do - H.h1 "Rooms" - H.ul $ for_ rids $ \(RoomView rid num) -> H.li $ do - H.a H.! A.href (H.toValue $ BaseUrl.render base <> "/rooms/" <> rid) $ - H.toHtml rid - " (" - H.toHtml num - ")" - H.footer $ "Untitled PL Card Game" + body + H.footer $ "Untitled PL Card Game version " <> H.toHtml (cVersion conf) + +rooms :: Config -> [RoomView] -> H.Html +rooms conf rids = template conf "Untitled PL Card Game" $ do + H.h1 "Rooms" + H.ul $ for_ rids $ \(RoomView rid num) -> H.li $ do + H.a H.! A.href (H.toValue $ + BaseUrl.render (cBaseUrl conf) <> "/rooms/" <> rid) $ + H.toHtml rid + " (" + H.toHtml num + ")" + +client :: Config -> Text -> H.Html +client conf roomId = template conf "Untitled PL Card Game" $ do + H.div H.! A.id "main" $ "" + H.script H.! A.type_ "text/JavaScript" + H.! A.src (H.toValue $ + BaseUrl.render (cBaseUrl conf) <> "/assets/client.js") + H.script $ H.unsafeLazyByteString $ clientScript $ BLB.toLazyByteString $ + var app = Elm.Client.init({node: document.querySelector("main")}); + + function connect() { + var protocol = "ws:"; + if(document.location.protocol == "https:") { + protocol = "wss:" + } + var path = document.location.pathname; + if(path.startsWith("$UPLCG_BASE")) { + path = path.substr("$UPLCG_BASE".length); + } + var roomId = path.split("/")[2]; + var url = protocol + "//" + document.location.host + + "$UPLCG_BASE/rooms/" + roomId + "/events"; + + var socket = new WebSocket(url); + var socketSend = function(message) { + socket.send(message); + }; + app.ports.webSocketOut.subscribe(socketSend); + socket.onmessage = function(event) { + app.ports.webSocketIn.send(event.data); + }; + socket.onclose = function(event) { + app.ports.webSocketOut.unsubscribe(socketSend); + setTimeout(function() { + connect(); + }, 1000); + }; + socket.onerror = function(event) { + socket.close(); + }; + } + + connect(); + + + + diff --git a/server/uplcg.cabal b/server/uplcg.cabal index 403facd..72b2f82 100644 --- a/server/uplcg.cabal +++ b/server/uplcg.cabal @@ -18,6 +18,7 @@ Library Exposed-modules: Uplcg.BaseUrl Uplcg.CookieSocket + Uplcg.Config Uplcg.Game Uplcg.Main.GenerateElmTypes Uplcg.Main.Server -- cgit v1.2.3 From 5a3fc14c1a92b28423d1b64b64e12d0502a90219 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Sun, 16 Aug 2020 12:29:31 +0200 Subject: Move client to server --- Makefile | 6 --- client/index.html | 51 ------------------------ config.mk | 1 - server/lib/Uplcg/Config.hs | 3 -- server/lib/Uplcg/Main/Server.hs | 11 ++---- server/lib/Uplcg/Version.hs | 17 ++++++++ server/lib/Uplcg/Views.hs | 88 ++++++++++++++++++++--------------------- server/uplcg.cabal | 4 ++ 8 files changed, 67 insertions(+), 114 deletions(-) delete mode 100644 client/index.html create mode 100644 server/lib/Uplcg/Version.hs diff --git a/Makefile b/Makefile index e3e7947..921d0eb 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,6 @@ STACK_BIN=$(shell cd server && stack path --local-install-root)/bin .PHONY: build build: server/assets/client.js \ - server/assets/client.html \ server/assets/style.css \ server/assets/black.txt \ server/assets/white.txt @@ -36,11 +35,6 @@ server/assets/client.js: $(ELM_MESSAGES_SOURCE) $(ELM_SOURCES) mkdir -p server/assets cd client && elm make src/Client.elm --optimize --output=../$@ -.PHONY: server/assets/client.html # Depends on git hash. -server/assets/client.html: client/index.html config.mk - sed "s@\$$UPLCG_BASE@$(UPLCG_BASE)@" $< | \ - sed "s@\$$UPLCG_VERSION@$(UPLCG_VERSION)@" >$@ - server/assets/style.css: client/style.css cp $< $@ diff --git a/client/index.html b/client/index.html deleted file mode 100644 index a03d777..0000000 --- a/client/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Client - - - - -
- - - - - diff --git a/config.mk b/config.mk index 5fd098d..ddec45c 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,3 @@ UPLCG_HOSTNAME=0.0.0.0 UPLCG_PORT=8002 UPLCG_BASE=/uplcg -UPLCG_VERSION=$(shell git rev-parse HEAD | head -c8) diff --git a/server/lib/Uplcg/Config.hs b/server/lib/Uplcg/Config.hs index 627a829..9197d97 100644 --- a/server/lib/Uplcg/Config.hs +++ b/server/lib/Uplcg/Config.hs @@ -3,7 +3,6 @@ module Uplcg.Config , fromEnv ) where -import Data.String (fromString) import qualified Data.Text as T import System.Environment (getEnv) import Uplcg.BaseUrl (BaseUrl) @@ -13,7 +12,6 @@ data Config = Config { cHostname :: String , cPort :: Int , cBaseUrl :: BaseUrl - , cVersion :: String } deriving (Show) fromEnv :: IO Config @@ -21,4 +19,3 @@ fromEnv = Config <$> getEnv "UPLCG_HOSTNAME" <*> (read <$> getEnv "UPLCG_PORT") <*> (BaseUrl.parse . T.pack <$> getEnv "UPLCG_BASE") - <*> getEnv "UPLCG_VERSION" diff --git a/server/lib/Uplcg/Main/Server.hs b/server/lib/Uplcg/Main/Server.hs index 72b9377..acf2931 100644 --- a/server/lib/Uplcg/Main/Server.hs +++ b/server/lib/Uplcg/Main/Server.hs @@ -9,7 +9,7 @@ import Control.Concurrent.STM (STM, TVar, atomically) import qualified Control.Concurrent.STM as STM import Control.Exception (bracket) import Control.Lens ((&), (.~), (^.)) -import Control.Monad (forever, when) +import Control.Monad (forever) import Control.Monad.Trans (liftIO) import qualified Data.Aeson as Aeson import qualified Data.ByteString as B @@ -30,7 +30,6 @@ import qualified Network.Wai as Wai import qualified Network.Wai.Handler.Warp as Warp import qualified Network.Wai.Handler.WebSockets as WaiWs import qualified Network.WebSockets as WS -import System.Environment (getEnv) import qualified System.Log.FastLogger as FL import System.Random (StdGen, newStdGen) import Text.Blaze.Html.Renderer.Text (renderHtml) @@ -104,11 +103,9 @@ scottyApp server = Scotty.scottyApp $ do Scotty.html . renderHtml $ Views.rooms (serverConfig server) views Scotty.get "/rooms/:id/" $ do - rid <- Scotty.param "id" - when (T.length rid < 6) $ - Scotty.raise "Room ID should be at least 6 characters" - Scotty.setHeader "Content-Type" "text/html" - Scotty.file "assets/client.html" + rid <- Scotty.param "id" >>= + either (Scotty.raise . TL.pack) pure . parseRoomId + Scotty.html . renderHtml $ Views.client (serverConfig server) rid Scotty.get "/assets/client.js" $ do Scotty.setHeader "Content-Type" "application/JavaScript" diff --git a/server/lib/Uplcg/Version.hs b/server/lib/Uplcg/Version.hs new file mode 100644 index 0000000..b718a10 --- /dev/null +++ b/server/lib/Uplcg/Version.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE TemplateHaskell #-} +module Uplcg.Version + ( version + ) where + +import Control.Monad.Trans (liftIO) +import Data.Version (showVersion) +import qualified Language.Haskell.TH as TH +import qualified Paths_uplcg +import System.Process (readProcess) + +version :: String +version = showVersion Paths_uplcg.version ++ " (" ++ + $(do + hash <- liftIO $ readProcess "git" ["rev-parse", "HEAD"] "" + pure . TH.LitE . TH.StringL $ take 8 hash) ++ + ")" diff --git a/server/lib/Uplcg/Views.hs b/server/lib/Uplcg/Views.hs index 3cb9ebe..772c83b 100644 --- a/server/lib/Uplcg/Views.hs +++ b/server/lib/Uplcg/Views.hs @@ -2,15 +2,18 @@ module Uplcg.Views ( RoomView (..) , rooms + , client ) where -import Data.Foldable (for_) -import Data.Text (Text) -import qualified Text.Blaze.Html5 as H -import qualified Text.Blaze.Html5.Attributes as A import qualified Data.ByteString.Lazy.Builder as BLB -import qualified Uplcg.BaseUrl as BaseUrl +import Data.Foldable (for_) +import Data.Text (Text) +import qualified Data.Text.Encoding as T +import qualified Text.Blaze.Html5 as H +import qualified Text.Blaze.Html5.Attributes as A +import qualified Uplcg.BaseUrl as BaseUrl import Uplcg.Config +import Uplcg.Version (version) data RoomView = RoomView Text Int @@ -25,7 +28,7 @@ template conf title body = H.docTypeHtml $ do H.meta H.! A.name "viewport" H.! A.content "width=device-width" H.body $ do body - H.footer $ "Untitled PL Card Game version " <> H.toHtml (cVersion conf) + H.footer $ "Untitled PL Card Game version " <> H.toHtml version rooms :: Config -> [RoomView] -> H.Html rooms conf rids = template conf "Untitled PL Card Game" $ do @@ -43,44 +46,37 @@ client conf roomId = template conf "Untitled PL Card Game" $ do H.div H.! A.id "main" $ "" H.script H.! A.type_ "text/JavaScript" H.! A.src (H.toValue $ - BaseUrl.render (cBaseUrl conf) <> "/assets/client.js") - H.script $ H.unsafeLazyByteString $ clientScript $ BLB.toLazyByteString $ - var app = Elm.Client.init({node: document.querySelector("main")}); + BaseUrl.render (cBaseUrl conf) <> "/assets/client.js") $ "" + H.script H.! A.type_ "text/JavaScript" $ H.unsafeLazyByteString entryPoint + where + t2b = BLB.byteString . T.encodeUtf8 + entryPoint = BLB.toLazyByteString $ + "var app = Elm.Client.init({node: document.querySelector('main')});" <> - function connect() { - var protocol = "ws:"; - if(document.location.protocol == "https:") { - protocol = "wss:" - } - var path = document.location.pathname; - if(path.startsWith("$UPLCG_BASE")) { - path = path.substr("$UPLCG_BASE".length); - } - var roomId = path.split("/")[2]; - var url = protocol + "//" + document.location.host + - "$UPLCG_BASE/rooms/" + roomId + "/events"; - - var socket = new WebSocket(url); - var socketSend = function(message) { - socket.send(message); - }; - app.ports.webSocketOut.subscribe(socketSend); - socket.onmessage = function(event) { - app.ports.webSocketIn.send(event.data); - }; - socket.onclose = function(event) { - app.ports.webSocketOut.unsubscribe(socketSend); - setTimeout(function() { - connect(); - }, 1000); - }; - socket.onerror = function(event) { - socket.close(); - }; - } - - connect(); - - - - + "function connect() {" <> + " var protocol = 'ws:';" <> + " if(document.location.protocol == 'https:') {" <> + " protocol = 'wss:'" <> + " }" <> + " var url = protocol + '//' + document.location.host +" <> + " '" <> t2b (BaseUrl.render $ cBaseUrl conf) <> "/rooms/" <> + t2b roomId <> "/events';" <> + " var socket = new WebSocket(url);" <> + " var socketSend = function(message) {" <> + " socket.send(message);" <> + " };" <> + " app.ports.webSocketOut.subscribe(socketSend);" <> + " socket.onmessage = function(event) {" <> + " app.ports.webSocketIn.send(event.data);" <> + " };" <> + " socket.onclose = function(event) {" <> + " app.ports.webSocketOut.unsubscribe(socketSend);" <> + " setTimeout(function() {" <> + " connect();" <> + " }, 1000);" <> + " };" <> + " socket.onerror = function(event) {" <> + " socket.close();" <> + " };" <> + "}" <> + "connect();" diff --git a/server/uplcg.cabal b/server/uplcg.cabal index 72b2f82..c97d358 100644 --- a/server/uplcg.cabal +++ b/server/uplcg.cabal @@ -14,6 +14,7 @@ Library Default-language: Haskell2010 Ghc-options: -Wall Hs-source-dirs: lib + Other-modules: Paths_uplcg Exposed-modules: Uplcg.BaseUrl @@ -23,6 +24,7 @@ Library Uplcg.Main.GenerateElmTypes Uplcg.Main.Server Uplcg.Messages + Uplcg.Version Uplcg.Views Build-depends: @@ -36,9 +38,11 @@ Library hashable >= 1.3 && < 1.4, lens >= 4.18 && < 4.19, mtl >= 2.2 && < 2.3, + process >= 1.6 && < 1.7, random >= 1.1 && < 1.2, scotty >= 0.11 && < 0.12, stm >= 2.5 && < 2.6, + template-haskell >= 2.15 && < 2.16, text >= 1.2 && < 1.3, time >= 1.9 && < 1.10, unordered-containers >= 0.2 && < 0.3, -- cgit v1.2.3 From d543ef8b1f68a23f9bc3706363fc3807ccbabf30 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Sun, 16 Aug 2020 12:33:21 +0200 Subject: Room list styling --- client/style.css | 9 +++++++++ server/lib/Uplcg/Views.hs | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/client/style.css b/client/style.css index 90e6a03..3da29f8 100644 --- a/client/style.css +++ b/client/style.css @@ -118,6 +118,15 @@ button, input { margin-top: 6px; } +.rooms { + max-width: 800px; + margin: auto; +} + +.rooms ul { + text-align: left; +} + footer { font-size: 12px; margin: 60px auto 60px auto; diff --git a/server/lib/Uplcg/Views.hs b/server/lib/Uplcg/Views.hs index 772c83b..8241158 100644 --- a/server/lib/Uplcg/Views.hs +++ b/server/lib/Uplcg/Views.hs @@ -31,15 +31,16 @@ template conf title body = H.docTypeHtml $ do H.footer $ "Untitled PL Card Game version " <> H.toHtml version rooms :: Config -> [RoomView] -> H.Html -rooms conf rids = template conf "Untitled PL Card Game" $ do - H.h1 "Rooms" - H.ul $ for_ rids $ \(RoomView rid num) -> H.li $ do - H.a H.! A.href (H.toValue $ - BaseUrl.render (cBaseUrl conf) <> "/rooms/" <> rid) $ - H.toHtml rid - " (" - H.toHtml num - ")" +rooms conf rids = template conf "Untitled PL Card Game" $ + H.div H.! A.class_ "rooms" $ do + H.h1 "Rooms" + H.ul $ for_ rids $ \(RoomView rid num) -> H.li $ do + H.a H.! A.href (H.toValue $ + BaseUrl.render (cBaseUrl conf) <> "/rooms/" <> rid) $ + H.toHtml rid + " (" + H.toHtml num + ")" client :: Config -> Text -> H.Html client conf roomId = template conf "Untitled PL Card Game" $ do -- cgit v1.2.3