initial refactoring to use a pure html/js login screen
This commit is contained in:
@@ -6,8 +6,8 @@ pub type NewUserState {
|
||||
}
|
||||
|
||||
pub type NewUserClientMessages {
|
||||
Register(game_code: String, username: String)
|
||||
CreateRoom(game_code: String, username: String)
|
||||
JoinAsPlayer(token: String, user_id: Int, game_id: String)
|
||||
JoinAsHost(token: String, user_id: Int, game_id: String)
|
||||
}
|
||||
|
||||
pub fn new_user_client_messages_decoder() -> decode.Decoder(
|
||||
@@ -15,40 +15,32 @@ pub fn new_user_client_messages_decoder() -> decode.Decoder(
|
||||
) {
|
||||
use variant <- decode.field("type", decode.string)
|
||||
case variant {
|
||||
"Register" -> {
|
||||
use game_code <- decode.field("game_code", decode.string)
|
||||
use username <- decode.field("username", decode.string)
|
||||
decode.success(Register(game_code:, username:))
|
||||
"JoinAsPlayer" -> {
|
||||
use token <- decode.field("token", decode.string)
|
||||
use user_id <- decode.field("user_id", decode.int)
|
||||
use game_id <- decode.field("game_id", decode.string)
|
||||
decode.success(JoinAsPlayer(token:, user_id:, game_id:))
|
||||
}
|
||||
"CreateRoom" -> {
|
||||
use game_code <- decode.field("game_code", decode.string)
|
||||
use username <- decode.field("username", decode.string)
|
||||
decode.success(CreateRoom(game_code:, username:))
|
||||
"JoinAsHost" -> {
|
||||
use token <- decode.field("token", decode.string)
|
||||
use user_id <- decode.field("user_id", decode.int)
|
||||
use game_id <- decode.field("game_id", decode.string)
|
||||
decode.success(JoinAsHost(token:, user_id:, game_id:))
|
||||
}
|
||||
_ -> decode.failure(Register("", ""), "NewUserClientMessages")
|
||||
_ -> decode.failure(JoinAsPlayer("", 0, ""), "NewUserClientMessages")
|
||||
}
|
||||
}
|
||||
|
||||
pub type NewUserServerMessages {
|
||||
RegisterResponse(username: String, token: String)
|
||||
HostRegisterResponse(username: String, token: String)
|
||||
RegisterResponse
|
||||
HostRegisterResponse
|
||||
}
|
||||
|
||||
pub fn encode_new_user_server_messages(
|
||||
new_user_server_messages: NewUserServerMessages,
|
||||
) -> json.Json {
|
||||
case new_user_server_messages {
|
||||
RegisterResponse(..) ->
|
||||
json.object([
|
||||
#("type", json.string("RegisterResponse")),
|
||||
#("username", json.string(new_user_server_messages.username)),
|
||||
#("token", json.string(new_user_server_messages.token)),
|
||||
])
|
||||
HostRegisterResponse(..) ->
|
||||
json.object([
|
||||
#("type", json.string("HostRegisterResponse")),
|
||||
#("username", json.string(new_user_server_messages.username)),
|
||||
#("token", json.string(new_user_server_messages.token)),
|
||||
])
|
||||
RegisterResponse -> json.string("register_response")
|
||||
HostRegisterResponse -> json.string("host_register_response")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
import app/clients/new_user_client
|
||||
import app/web
|
||||
import gleam/bit_array
|
||||
import gleam/bytes_tree
|
||||
import gleam/dict
|
||||
import gleam/erlang/process
|
||||
import gleam/http/cookie
|
||||
import gleam/http/request.{type Request}
|
||||
import gleam/http/response.{type Response}
|
||||
import gleam/int
|
||||
import gleam/io
|
||||
import gleam/json
|
||||
import gleam/option.{None, Some}
|
||||
import gleam/otp/actor
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import login
|
||||
import mist.{type Connection, type ResponseData}
|
||||
import player
|
||||
import session
|
||||
import socket_manager
|
||||
import storail
|
||||
|
||||
type JoinAs {
|
||||
JoinAsHost
|
||||
JoinAsPlayer
|
||||
}
|
||||
|
||||
pub fn handle_request(
|
||||
req: Request(Connection),
|
||||
@@ -25,10 +38,75 @@ pub fn handle_request(
|
||||
["static", "frontend_bg.wasm"] ->
|
||||
serve_wasm(ctx, "frontend_bg.wasm", "application/wasm")
|
||||
["ws"] -> serve_websocket(ctx, req)
|
||||
["login", "host"] -> server_login(ctx, req, JoinAsHost)
|
||||
["login", "join"] -> server_login(ctx, req, JoinAsPlayer)
|
||||
_ -> response.set_body(response.new(404), mist.Bytes(bytes_tree.new()))
|
||||
}
|
||||
}
|
||||
|
||||
fn server_login(
|
||||
ctx: web.Context,
|
||||
req: Request(Connection),
|
||||
join_type: JoinAs,
|
||||
) -> Response(ResponseData) {
|
||||
let assert Ok(req) = mist.read_body(req, 1000)
|
||||
let assert Ok(body) = bit_array.to_string(req.body)
|
||||
|
||||
let assert Ok(login_req) = json.parse(body, login.login_request_decoder())
|
||||
let #(token, user_id) =
|
||||
web.register_user(ctx, login_req.username, login_req.game_code)
|
||||
|
||||
let _ = case join_type {
|
||||
JoinAsHost -> {
|
||||
let key = storail.key(ctx.sessions, login_req.game_code)
|
||||
let session = session.Session(login_req.game_code, user_id, dict.new())
|
||||
let assert Ok(Nil) = storail.write(key, session)
|
||||
}
|
||||
JoinAsPlayer -> {
|
||||
let key = storail.key(ctx.sessions, login_req.game_code)
|
||||
let assert Ok(session) = storail.read(key)
|
||||
|
||||
let player =
|
||||
player.Player(
|
||||
name: login_req.username,
|
||||
id: user_id,
|
||||
score: 0,
|
||||
buzz_in_time: None,
|
||||
)
|
||||
let session =
|
||||
session.Session(
|
||||
..session,
|
||||
players: dict.insert(session.players, player.id, player),
|
||||
)
|
||||
|
||||
let assert Ok(Nil) = storail.write(key, session)
|
||||
}
|
||||
}
|
||||
|
||||
let join_type_name = case join_type {
|
||||
JoinAsHost -> "host"
|
||||
JoinAsPlayer -> "player"
|
||||
}
|
||||
|
||||
response.new(200)
|
||||
|> response.set_cookie(
|
||||
"play_of_the_game/token",
|
||||
token,
|
||||
cookie.defaults(req.scheme),
|
||||
)
|
||||
|> response.set_cookie(
|
||||
"play_of_the_game/client_type",
|
||||
join_type_name,
|
||||
cookie.defaults(req.scheme),
|
||||
)
|
||||
|> response.set_cookie(
|
||||
"play_of_the_game/username",
|
||||
login_req.username,
|
||||
cookie.defaults(req.scheme),
|
||||
)
|
||||
|> response.set_body(mist.Bytes(bytes_tree.new()))
|
||||
}
|
||||
|
||||
fn serve_wasm(
|
||||
ctx: web.Context,
|
||||
file: String,
|
||||
|
||||
+45
-37
@@ -19,6 +19,10 @@ import session
|
||||
import socket_manager
|
||||
import storail
|
||||
|
||||
pub type Error {
|
||||
InvalidToken
|
||||
}
|
||||
|
||||
pub type Context {
|
||||
Context(
|
||||
config: config.Config,
|
||||
@@ -109,8 +113,8 @@ fn handle_player(
|
||||
}
|
||||
}
|
||||
|
||||
fn register_user(
|
||||
state: SocketState,
|
||||
pub fn register_user(
|
||||
ctx: Context,
|
||||
username: String,
|
||||
game_code: String,
|
||||
) -> #(String, Int) {
|
||||
@@ -127,7 +131,7 @@ fn register_user(
|
||||
|
||||
let assert <<user_id:int-size(64)>> = crypto.strong_random_bytes(8)
|
||||
|
||||
let key = storail.key(state.ctx.player_sessions, int.to_base16(user_id))
|
||||
let key = storail.key(ctx.player_sessions, int.to_base16(user_id))
|
||||
|
||||
let assert Ok(Nil) =
|
||||
storail.write(
|
||||
@@ -136,13 +140,40 @@ fn register_user(
|
||||
id: user_id,
|
||||
token_hash:,
|
||||
username:,
|
||||
socket_id: state.id,
|
||||
socket_id: None,
|
||||
),
|
||||
)
|
||||
|
||||
#(token, user_id)
|
||||
}
|
||||
|
||||
pub fn attach_socket_to_user(
|
||||
state: SocketState,
|
||||
user_id: Int,
|
||||
token: String,
|
||||
) -> Result(Nil, Error) {
|
||||
let key = storail.key(state.ctx.player_sessions, int.to_base16(user_id))
|
||||
let assert Ok(player_state) = storail.read(key)
|
||||
|
||||
let hashed_token = player_session.hash_token(token)
|
||||
|
||||
case hashed_token == player_state.token_hash {
|
||||
False -> Error(InvalidToken)
|
||||
True -> {
|
||||
let assert Ok(Nil) =
|
||||
storail.write(
|
||||
key,
|
||||
player_session.PlayerSession(
|
||||
..player_state,
|
||||
socket_id: Some(state.id),
|
||||
),
|
||||
)
|
||||
|
||||
Ok(Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_new_user(
|
||||
socket_state: SocketState,
|
||||
_new_user_state: new_user_client.NewUserState,
|
||||
@@ -152,49 +183,25 @@ fn handle_new_user(
|
||||
json.parse(msg, new_user_client.new_user_client_messages_decoder())
|
||||
|
||||
let #(socket_state, new_user_msg) = case msg {
|
||||
new_user_client.CreateRoom(game_code, username) -> {
|
||||
let #(token, user_id) = register_user(socket_state, username, game_code)
|
||||
|
||||
let key = storail.key(socket_state.ctx.sessions, game_code)
|
||||
let session = session.Session(game_code, user_id, dict.new())
|
||||
let assert Ok(Nil) = storail.write(key, session)
|
||||
new_user_client.JoinAsHost(token, user_id, game_id) -> {
|
||||
let assert Ok(_) = attach_socket_to_user(socket_state, user_id, token)
|
||||
|
||||
#(
|
||||
SocketState(
|
||||
..socket_state,
|
||||
state: Host(host_client.HostState(user_id, game_code)),
|
||||
state: Player(player_client.PlayerState(user_id:, game_id:)),
|
||||
),
|
||||
new_user_client.HostRegisterResponse(username, token),
|
||||
new_user_client.HostRegisterResponse,
|
||||
)
|
||||
}
|
||||
new_user_client.Register(game_code, username) -> {
|
||||
let #(token, user_id) = register_user(socket_state, username, game_code)
|
||||
|
||||
let key = storail.key(socket_state.ctx.sessions, game_code)
|
||||
let assert Ok(session) = storail.read(key)
|
||||
|
||||
let player =
|
||||
player.Player(name: username, id: user_id, score: 0, buzz_in_time: None)
|
||||
let session =
|
||||
session.Session(
|
||||
..session,
|
||||
players: dict.insert(session.players, player.id, player),
|
||||
)
|
||||
|
||||
send_message_to_host(
|
||||
socket_state,
|
||||
session.host_user_id,
|
||||
host_client.UpdatePlayerStates(session.players),
|
||||
)
|
||||
|
||||
let assert Ok(Nil) = storail.write(key, session)
|
||||
|
||||
new_user_client.JoinAsPlayer(token, user_id, game_id) -> {
|
||||
let assert Ok(_) = attach_socket_to_user(socket_state, user_id, token)
|
||||
#(
|
||||
SocketState(
|
||||
..socket_state,
|
||||
state: Player(player_client.PlayerState(user_id, game_code)),
|
||||
state: Host(host_client.HostState(user_id:, game_id:)),
|
||||
),
|
||||
new_user_client.RegisterResponse(username, token),
|
||||
new_user_client.HostRegisterResponse,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -218,8 +225,9 @@ fn get_player_session_subject(
|
||||
ctx: Context,
|
||||
player: player_session.PlayerSession,
|
||||
) -> process.Subject(String) {
|
||||
let assert Some(id) = player.socket_id
|
||||
let assert Ok(subject) =
|
||||
socket_manager.get_socket_subj_by_id(ctx.socket_manager, player.socket_id)
|
||||
socket_manager.get_socket_subj_by_id(ctx.socket_manager, id)
|
||||
subject
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user