2026-03-29 13:53:16 +02:00
|
|
|
import backend/roomhandler
|
|
|
|
|
import backend/sockethandler
|
|
|
|
|
import backend/statehandler
|
|
|
|
|
import gleam/bytes_tree
|
|
|
|
|
import gleam/erlang/application
|
|
|
|
|
import gleam/erlang/process
|
2026-03-30 23:49:20 +02:00
|
|
|
import gleam/http
|
2026-03-29 13:53:16 +02:00
|
|
|
import gleam/http/request
|
|
|
|
|
import gleam/http/response.{type Response}
|
|
|
|
|
import gleam/list
|
|
|
|
|
import gleam/option.{None}
|
|
|
|
|
import gleam/result
|
|
|
|
|
import gleam/string
|
2026-03-30 23:49:20 +02:00
|
|
|
import mist.{type ResponseData}
|
2026-03-29 13:53:16 +02:00
|
|
|
import web/components/answerlist
|
|
|
|
|
import web/components/card
|
|
|
|
|
import web/components/control
|
|
|
|
|
import web/router
|
|
|
|
|
import wisp
|
|
|
|
|
import wisp/wisp_mist
|
2026-04-15 20:04:56 +02:00
|
|
|
import envoy
|
2026-03-29 13:53:16 +02:00
|
|
|
|
|
|
|
|
pub fn main() {
|
|
|
|
|
wisp.configure_logger()
|
|
|
|
|
|
2026-04-15 20:04:56 +02:00
|
|
|
let assert Ok(sha_api_key) = envoy.get("SHAED_API_KEY")
|
|
|
|
|
let assert Ok(secret) = envoy.get("QTERM_SECRET")
|
|
|
|
|
|
2026-03-29 13:53:16 +02:00
|
|
|
let assert Ok(state_handler) = statehandler.initialize()
|
|
|
|
|
let assert Ok(room_handler) = roomhandler.initialize(state_handler)
|
|
|
|
|
|
|
|
|
|
let assert Ok(_) =
|
2026-03-30 23:49:20 +02:00
|
|
|
fn(req: request.Request(mist.Connection)) {
|
|
|
|
|
case req.method {
|
|
|
|
|
// Filter out Head requests,
|
|
|
|
|
http.Head ->
|
|
|
|
|
response.new(200)
|
|
|
|
|
|> response.set_body(mist.Bytes(bytes_tree.new()))
|
2026-03-29 13:53:16 +02:00
|
|
|
_ ->
|
2026-03-30 23:49:20 +02:00
|
|
|
case request.path_segments(req) {
|
|
|
|
|
["lustre", "runtime.mjs"] -> serve_runtime()
|
|
|
|
|
["client.js"] -> serve_static("client.js")
|
|
|
|
|
["static", file] -> serve_static(file)
|
2026-04-13 20:49:57 +02:00
|
|
|
["socket", "live", id, pin] ->
|
|
|
|
|
sockethandler.serve(req, card.component(), id, pin, room_handler)
|
|
|
|
|
["socket", "control", id, pin] ->
|
|
|
|
|
sockethandler.serve(
|
|
|
|
|
req,
|
|
|
|
|
control.component(),
|
|
|
|
|
id,
|
|
|
|
|
pin,
|
|
|
|
|
room_handler,
|
|
|
|
|
)
|
|
|
|
|
["socket", "single", id, pin] ->
|
2026-04-15 20:04:56 +02:00
|
|
|
sockethandler.serve_single(
|
2026-03-30 23:49:20 +02:00
|
|
|
req,
|
|
|
|
|
answerlist.component(),
|
|
|
|
|
id,
|
2026-04-13 20:49:57 +02:00
|
|
|
pin,
|
2026-03-30 23:49:20 +02:00
|
|
|
room_handler,
|
|
|
|
|
state_handler,
|
|
|
|
|
)
|
|
|
|
|
_ ->
|
|
|
|
|
wisp_mist.handler(
|
2026-04-15 20:04:56 +02:00
|
|
|
router.handle_request(sha_api_key, room_handler, state_handler, _),
|
|
|
|
|
secret,
|
2026-03-30 23:49:20 +02:00
|
|
|
)(req)
|
|
|
|
|
}
|
2026-03-29 13:53:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|> mist.new
|
|
|
|
|
|> mist.bind("0.0.0.0")
|
|
|
|
|
|> mist.port(1234)
|
|
|
|
|
|> mist.start
|
|
|
|
|
|
|
|
|
|
process.sleep_forever()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn serve_static(filename: String) {
|
|
|
|
|
let assert Ok(priv) = application.priv_directory("quizterm")
|
|
|
|
|
let surname = string.split(filename, ".") |> list.last
|
|
|
|
|
let path = priv <> "/static/" <> filename
|
|
|
|
|
let data =
|
|
|
|
|
mist.send_file(path, offset: 0, limit: None)
|
|
|
|
|
|> result.map(fn(file) {
|
|
|
|
|
echo "SUCCESS " <> filename
|
|
|
|
|
response.new(200)
|
|
|
|
|
|> response.set_header("Content-Type", case surname {
|
|
|
|
|
Ok("css") -> "text/css"
|
|
|
|
|
Ok("js") -> "application/javascript"
|
|
|
|
|
Ok(_) | Error(_) -> "text/html"
|
|
|
|
|
})
|
|
|
|
|
|> response.set_body(file)
|
|
|
|
|
})
|
|
|
|
|
|> result.lazy_unwrap(fn() {
|
|
|
|
|
echo "FAIL " <> filename
|
|
|
|
|
response.new(404)
|
|
|
|
|
|> response.set_body(
|
|
|
|
|
bytes_tree.from_string("Requested resource not found") |> mist.Bytes,
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
echo "Attempting to serve file " <> filename <> " was "
|
|
|
|
|
|
|
|
|
|
data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn serve_runtime() -> Response(ResponseData) {
|
|
|
|
|
let assert Ok(lustre_priv) = application.priv_directory("lustre")
|
|
|
|
|
let file_path = lustre_priv <> "/static/lustre-server-component.mjs"
|
|
|
|
|
|
|
|
|
|
case mist.send_file(file_path, offset: 0, limit: None) {
|
|
|
|
|
Ok(file) ->
|
|
|
|
|
response.new(200)
|
|
|
|
|
|> response.prepend_header("content-type", "application/javascript")
|
|
|
|
|
|> response.set_body(file)
|
|
|
|
|
|
|
|
|
|
Error(_) ->
|
|
|
|
|
response.new(404)
|
|
|
|
|
|> response.set_body(mist.Bytes(bytes_tree.new()))
|
|
|
|
|
}
|
|
|
|
|
}
|