Fixes to routing and new build for Dockerfile
This commit is contained in:
parent
0024687621
commit
ccdba0f239
4 changed files with 97 additions and 47 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1 +1,6 @@
|
||||||
localbuild.sh
|
**/.*
|
||||||
|
/localbuild.sh
|
||||||
|
/client/build
|
||||||
|
/server/build
|
||||||
|
/server/priv/static/client.js
|
||||||
|
/server/priv/static/index.html
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,15 @@ FROM ghcr.io/gleam-lang/gleam:${GLEAM_VERSION}-erlang-alpine AS builder
|
||||||
COPY ./server/priv /quizterm/server/priv
|
COPY ./server/priv /quizterm/server/priv
|
||||||
COPY ./server/src /quizterm/server/src
|
COPY ./server/src /quizterm/server/src
|
||||||
COPY ./server/gleam.toml /quizterm/server/
|
COPY ./server/gleam.toml /quizterm/server/
|
||||||
|
COPY ./client/src /quizterm/client/src
|
||||||
|
COPY ./client/gleam.toml /quizterm/client/
|
||||||
|
|
||||||
RUN cd /quizterm/server && gleam deps download
|
RUN cd /quizterm/server && gleam deps download
|
||||||
|
|
||||||
|
# Compile client code and move generated javascript to server project
|
||||||
|
RUN cd /quizterm/client \
|
||||||
|
&& gleam run -m lustre/dev build --outdir=/quizterm/server/priv/static
|
||||||
|
|
||||||
# Compile the server code
|
# Compile the server code
|
||||||
RUN cd /quizterm/server \
|
RUN cd /quizterm/server \
|
||||||
&& gleam export erlang-shipment
|
&& gleam export erlang-shipment
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import gleam/int
|
import gleam/int
|
||||||
import gleam/json
|
import gleam/json
|
||||||
import gleam/list
|
import gleam/list
|
||||||
|
import gleam/option.{type Option, None, Some}
|
||||||
import gleam/result
|
import gleam/result
|
||||||
|
import gleam/string
|
||||||
import lustre
|
import lustre
|
||||||
import lustre/attribute.{class}
|
import lustre/attribute.{class}
|
||||||
import lustre/effect.{type Effect}
|
import lustre/effect.{type Effect}
|
||||||
|
|
@ -10,7 +12,7 @@ import lustre/element/html
|
||||||
import lustre/event
|
import lustre/event
|
||||||
import plinth/browser/document
|
import plinth/browser/document
|
||||||
import plinth/browser/element as plinth_element
|
import plinth/browser/element as plinth_element
|
||||||
import shared
|
import shared.{type Room}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let initial_items =
|
let initial_items =
|
||||||
|
|
@ -29,37 +31,47 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Model {
|
type Model {
|
||||||
Model(rooms: List(shared.Room), name: String)
|
Model(
|
||||||
|
rooms: List(Room),
|
||||||
|
name: Option(String),
|
||||||
|
pin: Option(String),
|
||||||
|
typed: String,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(items: List(shared.Room)) -> #(Model, Effect(Msg)) {
|
fn init(items: List(Room)) -> #(Model, Effect(State)) {
|
||||||
let model = Model(rooms: items, name: "")
|
let model = Model(rooms: items, name: None, pin: None, typed: "")
|
||||||
|
|
||||||
#(model, effect.none())
|
#(model, effect.none())
|
||||||
}
|
}
|
||||||
|
|
||||||
type Msg {
|
type State {
|
||||||
UserTypedNewItem(String)
|
SelectRoom(String)
|
||||||
UserAddedItem
|
Initial
|
||||||
|
KeyIn(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
|
fn update(model: Model, msg: State) -> #(Model, Effect(msg)) {
|
||||||
case msg {
|
case msg {
|
||||||
UserAddedItem ->
|
Initial ->
|
||||||
case model.name {
|
case model.name {
|
||||||
_ -> #(model, effect.none())
|
_ -> #(model, effect.none())
|
||||||
}
|
}
|
||||||
UserTypedNewItem(text) -> {
|
SelectRoom(text) -> {
|
||||||
echo "CLICK " <> text <> "aa"
|
#(Model(..model, name: Some(text)), effect.none())
|
||||||
#(Model(..model, name: text), effect.none())
|
}
|
||||||
|
KeyIn(newpin) -> {
|
||||||
|
case string.length(newpin) < 4 {
|
||||||
|
False -> #(Model(..model, pin: Some(newpin)), effect.none())
|
||||||
|
True -> #(Model(..model, typed: newpin), effect.none())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(model: Model) -> Element(Msg) {
|
fn view(model: Model) -> Element(State) {
|
||||||
echo "NAME " <> model.name
|
case model.name, model.pin {
|
||||||
case model.name {
|
None, _ ->
|
||||||
"" ->
|
|
||||||
html.div([], [
|
html.div([], [
|
||||||
html.div([class("terminal-header")], [
|
html.div([class("terminal-header")], [
|
||||||
html.div([class("terminal-status")], [
|
html.div([class("terminal-status")], [
|
||||||
|
|
@ -72,7 +84,7 @@ fn view(model: Model) -> Element(Msg) {
|
||||||
]),
|
]),
|
||||||
view_room_list(model.rooms),
|
view_room_list(model.rooms),
|
||||||
])
|
])
|
||||||
_ -> {
|
Some(_), None -> {
|
||||||
html.div([], [
|
html.div([], [
|
||||||
html.div([class("terminal-header")], [
|
html.div([class("terminal-header")], [
|
||||||
html.div([class("terminal-status")], [
|
html.div([class("terminal-status")], [
|
||||||
|
|
@ -86,21 +98,40 @@ fn view(model: Model) -> Element(Msg) {
|
||||||
pin(),
|
pin(),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
Some(_), Some(_) -> {
|
||||||
|
html.div([], [
|
||||||
|
html.div([class("terminal-header")], [
|
||||||
|
html.div([class("terminal-status")], [
|
||||||
|
html.span([class("status-blink")], [html.text("●")]),
|
||||||
|
html.text(" SYSTEM READY"),
|
||||||
|
html.span([class("ml-8")], [
|
||||||
|
html.text("<< Please Log On to use QuizTerm. >>"),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
html.text("FETCHING USERS FOR ROOM"),
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pin() -> Element(Msg) {
|
fn pin() -> Element(State) {
|
||||||
html.div([attribute.class("terminal-section")], [
|
html.div([attribute.class("terminal-section")], [
|
||||||
html.div([attribute.class("terminal-label mb-4")], [
|
html.div([attribute.class("terminal-label mb-4")], [
|
||||||
html.text("Select room to play in"),
|
html.text("Select room to play in"),
|
||||||
]),
|
]),
|
||||||
html.div([attribute.class("participants-grid")], [
|
html.div([attribute.class("participants-grid")], [
|
||||||
html.text("Enter PIN code for room"),
|
html.text("Enter PIN code for room"),
|
||||||
|
html.input([
|
||||||
|
attribute.type_("password"),
|
||||||
|
event.on_input(KeyIn),
|
||||||
|
attribute.autofocus(True),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_room_list(items: List(shared.Room)) -> Element(Msg) {
|
fn view_room_list(items: List(Room)) -> Element(State) {
|
||||||
html.div([attribute.class("terminal-section")], [
|
html.div([attribute.class("terminal-section")], [
|
||||||
html.div([attribute.class("terminal-label mb-4")], [
|
html.div([attribute.class("terminal-label mb-4")], [
|
||||||
html.text("Select room to play in"),
|
html.text("Select room to play in"),
|
||||||
|
|
@ -109,7 +140,7 @@ fn view_room_list(items: List(shared.Room)) -> Element(Msg) {
|
||||||
[] -> [html.text("No items in your list yet.")]
|
[] -> [html.text("No items in your list yet.")]
|
||||||
_ -> {
|
_ -> {
|
||||||
list.index_map(items, fn(item, index) {
|
list.index_map(items, fn(item, index) {
|
||||||
content_cell(index, item, UserTypedNewItem)
|
content_cell(index, item, SelectRoom)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
@ -118,9 +149,9 @@ fn view_room_list(items: List(shared.Room)) -> Element(Msg) {
|
||||||
|
|
||||||
fn content_cell(
|
fn content_cell(
|
||||||
number: Int,
|
number: Int,
|
||||||
room: shared.Room,
|
room: Room,
|
||||||
on_click: fn(String) -> Msg,
|
on_click: fn(String) -> msg,
|
||||||
) -> Element(Msg) {
|
) -> Element(msg) {
|
||||||
html.div([class("participant-login"), event.on_click(on_click(room.name))], [
|
html.div([class("participant-login"), event.on_click(on_click(room.name))], [
|
||||||
html.div([class("participant-name")], [
|
html.div([class("participant-name")], [
|
||||||
html.text("► " <> "[#" <> int.to_string(number) <> "] Team " <> room.name),
|
html.text("► " <> "[#" <> int.to_string(number) <> "] Team " <> room.name),
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ import backend/statehandler
|
||||||
import gleam/bytes_tree
|
import gleam/bytes_tree
|
||||||
import gleam/erlang/application
|
import gleam/erlang/application
|
||||||
import gleam/erlang/process
|
import gleam/erlang/process
|
||||||
|
import gleam/http
|
||||||
import gleam/http/request
|
import gleam/http/request
|
||||||
import gleam/http/response.{type Response}
|
import gleam/http/response.{type Response}
|
||||||
import gleam/list
|
import gleam/list
|
||||||
import gleam/option.{None}
|
import gleam/option.{None}
|
||||||
import gleam/result
|
import gleam/result
|
||||||
import gleam/string
|
import gleam/string
|
||||||
import mist.{type ResponseData, File}
|
import mist.{type ResponseData}
|
||||||
import web/components/answerlist
|
import web/components/answerlist
|
||||||
import web/components/card
|
import web/components/card
|
||||||
import web/components/control
|
import web/components/control
|
||||||
|
|
@ -25,29 +26,36 @@ pub fn main() {
|
||||||
let assert Ok(room_handler) = roomhandler.initialize(state_handler)
|
let assert Ok(room_handler) = roomhandler.initialize(state_handler)
|
||||||
|
|
||||||
let assert Ok(_) =
|
let assert Ok(_) =
|
||||||
fn(req) {
|
fn(req: request.Request(mist.Connection)) {
|
||||||
case request.path_segments(req) {
|
case req.method {
|
||||||
["lustre", "runtime.mjs"] -> serve_runtime()
|
// Filter out Head requests,
|
||||||
[] | ["index.html"]-> serve_static("root.html")
|
http.Head ->
|
||||||
["client.js"] -> serve_static("client.js")
|
response.new(200)
|
||||||
["static", file] -> serve_static(file)
|
|> response.set_body(mist.Bytes(bytes_tree.new()))
|
||||||
["socket", "card", id] ->
|
|
||||||
sockethandler.serve(req, card.component(), id, room_handler)
|
|
||||||
["socket", "control", id] ->
|
|
||||||
sockethandler.serve(req, control.component(), id, room_handler)
|
|
||||||
["socket", "slow", id] ->
|
|
||||||
sockethandler.serve_slow(
|
|
||||||
req,
|
|
||||||
answerlist.component(),
|
|
||||||
id,
|
|
||||||
room_handler,
|
|
||||||
state_handler,
|
|
||||||
)
|
|
||||||
_ ->
|
_ ->
|
||||||
wisp_mist.handler(
|
case request.path_segments(req) {
|
||||||
router.handle_request(room_handler, state_handler, _),
|
["lustre", "runtime.mjs"] -> serve_runtime()
|
||||||
"very_secret",
|
[] | ["index.html"] -> serve_static("root.html")
|
||||||
)(req)
|
["client.js"] -> serve_static("client.js")
|
||||||
|
["static", file] -> serve_static(file)
|
||||||
|
["socket", "card", id] ->
|
||||||
|
sockethandler.serve(req, card.component(), id, room_handler)
|
||||||
|
["socket", "control", id] ->
|
||||||
|
sockethandler.serve(req, control.component(), id, room_handler)
|
||||||
|
["socket", "slow", id] ->
|
||||||
|
sockethandler.serve_slow(
|
||||||
|
req,
|
||||||
|
answerlist.component(),
|
||||||
|
id,
|
||||||
|
room_handler,
|
||||||
|
state_handler,
|
||||||
|
)
|
||||||
|
_ ->
|
||||||
|
wisp_mist.handler(
|
||||||
|
router.handle_request(room_handler, state_handler, _),
|
||||||
|
"very_secret",
|
||||||
|
)(req)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> mist.new
|
|> mist.new
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue