ton of refactoring, dropped lustre for a wasm frontend in rust
This commit is contained in:
18 files changed
+543
-224
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import app/web
|
||||
import gleam/bytes_tree
|
||||
import gleam/http/request.{type Request}
|
||||
import gleam/http/response.{type Response}
|
||||
import gleam/option.{None}
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import mist.{type Connection, type ResponseData}
|
||||
|
||||
pub fn handle_request(
|
||||
request: Request(Connection),
|
||||
ctx: web.Context,
|
||||
) -> Response(ResponseData) {
|
||||
case request.path_segments(request) {
|
||||
[] -> serve_frontend()
|
||||
["static", "frontend.wasm"] -> serve_wasm(ctx)
|
||||
_ -> response.set_body(response.new(404), mist.Bytes(bytes_tree.new()))
|
||||
}
|
||||
}
|
||||
|
||||
const game_body = "
|
||||
<html lang=\"en\">
|
||||
|
||||
<head>
|
||||
<meta charset=\"utf-8\">
|
||||
<title>TITLE</title>
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
canvas {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
background: black;
|
||||
z-index: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<canvas id=\"glcanvas\" tabindex='1'></canvas>
|
||||
<!-- Minified and statically hosted version of https://github.com/not-fl3/macroquad/blob/master/js/mq_js_bundle.js -->
|
||||
<script src=\"https://not-fl3.github.io/miniquad-samples/mq_js_bundle.js\"></script>
|
||||
<script>load(\"static/frontend.wasm\");</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
"
|
||||
|
||||
fn serve_frontend() -> Response(ResponseData) {
|
||||
response.new(200)
|
||||
|> response.set_body(mist.Bytes(bytes_tree.from_string(game_body)))
|
||||
|> response.set_header("content-type", "text/html")
|
||||
}
|
||||
|
||||
fn serve_wasm(ctx: web.Context) -> Response(ResponseData) {
|
||||
let wasm_path = string.join([ctx.config.static_path, "frontend.wasm"], "/")
|
||||
mist.send_file(wasm_path, offset: 0, limit: None)
|
||||
|> result.map(fn(file) {
|
||||
response.new(200)
|
||||
|> response.prepend_header("content-type", "application/wasm")
|
||||
|> response.set_body(file)
|
||||
})
|
||||
|> result.lazy_unwrap(fn() {
|
||||
response.new(404)
|
||||
|> response.set_body(mist.Bytes(bytes_tree.new()))
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import config
|
||||
import session
|
||||
import storail
|
||||
|
||||
pub type Context {
|
||||
Context(config: config.Config, sessions: storail.Collection(session.Session))
|
||||
}
|
||||
@@ -1,5 +1,74 @@
|
||||
import gleam/io
|
||||
import app/router
|
||||
import app/web
|
||||
import argv
|
||||
import config
|
||||
import gleam/erlang/process
|
||||
import gleam/result
|
||||
import glint
|
||||
import mist
|
||||
import session
|
||||
import storail
|
||||
|
||||
pub type Error {
|
||||
ConfigError(config.ConfigError)
|
||||
}
|
||||
|
||||
pub fn error_string(err: Error) -> String {
|
||||
case err {
|
||||
ConfigError(err) -> config.error_to_string(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_session_collection(
|
||||
config: storail.Config,
|
||||
) -> storail.Collection(session.Session) {
|
||||
storail.Collection(
|
||||
name: "Sessions",
|
||||
to_json: session.serialize,
|
||||
decoder: session.decoder(),
|
||||
config:,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn run_server() -> glint.Command(Result(Nil, Error)) {
|
||||
use <- glint.command_help("Runs the backend of Play of the Game")
|
||||
use _, args, _ <- glint.command()
|
||||
|
||||
let cfg_path = case args {
|
||||
[] -> "config.toml"
|
||||
[cfg_path, ..] -> cfg_path
|
||||
}
|
||||
|
||||
use cfg <- result.try(
|
||||
result.map_error(config.from_file(cfg_path), fn(err) {
|
||||
let err = ConfigError(err)
|
||||
err
|
||||
}),
|
||||
)
|
||||
|
||||
let storail_cfg = storail.Config(cfg.storage_path)
|
||||
|
||||
let ctx =
|
||||
web.Context(config: cfg, sessions: setup_session_collection(storail_cfg))
|
||||
|
||||
let handler = router.handle_request(_, ctx)
|
||||
|
||||
let assert Ok(_) =
|
||||
handler
|
||||
|> mist.new
|
||||
|> mist.bind(cfg.host)
|
||||
|> mist.port(cfg.port)
|
||||
|> mist.start_http
|
||||
|
||||
process.sleep_forever()
|
||||
|
||||
Ok(Nil)
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
io.println("Hello from backend!")
|
||||
glint.new()
|
||||
|> glint.with_name("Play Of The Game")
|
||||
|> glint.pretty_help(glint.default_pretty_help())
|
||||
|> glint.add(at: [], do: run_server())
|
||||
|> glint.run(argv.load().arguments)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import simplifile
|
||||
import tom
|
||||
|
||||
pub type ConfigError {
|
||||
IOError(simplifile.FileError)
|
||||
TomlError(tom.ParseError)
|
||||
MissingKey(tom.GetError)
|
||||
}
|
||||
|
||||
pub type Config {
|
||||
Config(storage_path: String, host: String, port: Int, static_path: String)
|
||||
}
|
||||
|
||||
pub fn error_to_string(err: ConfigError) -> String {
|
||||
let msg = case err {
|
||||
IOError(err) -> simplifile.describe_error(err)
|
||||
TomlError(err) -> {
|
||||
case err {
|
||||
tom.Unexpected(got, expected) ->
|
||||
"Unexpected: Got: " <> got <> "Expected: " <> expected
|
||||
tom.KeyAlreadyInUse(path) ->
|
||||
"Key already used at: " <> string.join(path, ".")
|
||||
}
|
||||
}
|
||||
MissingKey(err) -> {
|
||||
case err {
|
||||
tom.NotFound(path) -> "Missing Key: " <> string.join(path, ".")
|
||||
tom.WrongType(path, expected, got) ->
|
||||
"Wrong type at: "
|
||||
<> string.join(path, ".")
|
||||
<> ", got: "
|
||||
<> got
|
||||
<> "expected: "
|
||||
<> expected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Config error: " <> msg
|
||||
}
|
||||
|
||||
pub fn from_file(path: String) -> Result(Config, ConfigError) {
|
||||
use config_str <- result.try(result.map_error(
|
||||
simplifile.read(from: path),
|
||||
IOError,
|
||||
))
|
||||
use config_tom <- result.try(result.map_error(
|
||||
tom.parse(config_str),
|
||||
TomlError,
|
||||
))
|
||||
use storage_path <- result.try(result.map_error(
|
||||
tom.get_string(config_tom, ["storage_path"]),
|
||||
MissingKey,
|
||||
))
|
||||
use port <- result.try(result.map_error(
|
||||
tom.get_int(config_tom, ["port"]),
|
||||
MissingKey,
|
||||
))
|
||||
use host <- result.try(result.map_error(
|
||||
tom.get_string(config_tom, ["host"]),
|
||||
MissingKey,
|
||||
))
|
||||
use static_path <- result.try(result.map_error(
|
||||
tom.get_string(config_tom, ["static_path"]),
|
||||
MissingKey,
|
||||
))
|
||||
|
||||
Ok(Config(storage_path:, port:, host:, static_path:))
|
||||
}
|
||||
Reference in new issue
Block a user