update deps, fix stuff and add some comments
This commit is contained in:
parent
dbeda509fc
commit
3cfabcc39f
5 changed files with 477 additions and 466 deletions
507
Cargo.lock
generated
507
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,15 +1,14 @@
|
||||||
[package]
|
[package]
|
||||||
name = "open_tavern"
|
name = "open_tavern"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.7.7", features = ["ws"] }
|
axum = { version = "0.8.4", features = ["ws"] }
|
||||||
serde = "1.*.*"
|
serde = "1.*.*"
|
||||||
serde_json = "1.*.*"
|
serde_json = "1.*.*"
|
||||||
tokio = { version = "1.*.*", features = ["full"] }
|
tokio = { version = "1.*.*", features = ["full"] }
|
||||||
sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] }
|
sqlx = { version = "0.8.6", features = ["runtime-tokio", "sqlite"] }
|
||||||
tavern_macros = { version = "0.1.0", path = "tavern_macros" }
|
tavern_macros = { version = "0.1.0", path = "tavern_macros" }
|
||||||
parking_lot = "0.12.3"
|
futures-util = "0.3.31"
|
||||||
futures-util = "0.3.30"
|
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
|
|
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
binop_separator = "Back"
|
||||||
|
max_width = 120
|
111
src/lib.rs
111
src/lib.rs
|
@ -1,7 +1,11 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use api::game_actions::SpawnToken;
|
use api::game_actions::SpawnToken;
|
||||||
use game::{chat_message::ChatMessage, entry::{ActionDefinition, DiceRoll}, Game, GameImpl};
|
use game::{
|
||||||
|
Game, GameImpl,
|
||||||
|
chat_message::ChatMessage,
|
||||||
|
entry::{ActionDefinition, DiceRoll},
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{broadcast, mpsc};
|
use tokio::sync::{broadcast, mpsc};
|
||||||
|
|
||||||
|
@ -14,7 +18,9 @@ pub mod user;
|
||||||
pub struct GameServer {
|
pub struct GameServer {
|
||||||
game: Game<pathfinder2r_impl::Pathfinder2rCharacterSheet, pathfinder2r_impl::entry::Entry>,
|
game: Game<pathfinder2r_impl::Pathfinder2rCharacterSheet, pathfinder2r_impl::entry::Entry>,
|
||||||
chat: Vec<(String, ChatMessage)>,
|
chat: Vec<(String, ChatMessage)>,
|
||||||
#[serde(skip)] // we dont want to save the logged users as it will always be empty when the server restarts
|
// we dont want to save the logged users as it will always be empty when the server restarts
|
||||||
|
#[serde(skip)]
|
||||||
|
/// Logged in users, bool value used to know if the user is an admin or not
|
||||||
users: HashMap<String, bool>,
|
users: HashMap<String, bool>,
|
||||||
// TODO: JEESH REPLACE THIS WITH A DATABASE AND PROPER SECURITY ONCE ITS DONE PLEASE GOD
|
// TODO: JEESH REPLACE THIS WITH A DATABASE AND PROPER SECURITY ONCE ITS DONE PLEASE GOD
|
||||||
creds: HashMap<String, String>,
|
creds: HashMap<String, String>,
|
||||||
|
@ -22,13 +28,12 @@ pub struct GameServer {
|
||||||
impl GameServer {
|
impl GameServer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut creds = HashMap::new();
|
let mut creds = HashMap::new();
|
||||||
creds.insert("rusty".to_string(), String::new());
|
creds.insert("rusty".to_string(), "rusty".to_string());
|
||||||
creds.insert("artist".to_string(), "artist".to_string());
|
creds.insert("test".to_string(), "test".to_string());
|
||||||
creds.insert("dragonfly".to_string(), "cool".to_string());
|
creds.insert("dragonfly".to_string(), "dragonfly".to_string());
|
||||||
Self {
|
Self {
|
||||||
game: Game::new(),
|
game: Game::new(),
|
||||||
chat: vec![
|
chat: vec![(
|
||||||
(
|
|
||||||
"Server".to_string(),
|
"Server".to_string(),
|
||||||
ChatMessage::new("a weapon description".to_string())
|
ChatMessage::new("a weapon description".to_string())
|
||||||
.id(1)
|
.id(1)
|
||||||
|
@ -37,12 +42,15 @@ impl GameServer {
|
||||||
ActionDefinition::new("weapon/attack".to_string())
|
ActionDefinition::new("weapon/attack".to_string())
|
||||||
.display_name(Some("Attack +7".to_string()))
|
.display_name(Some("Attack +7".to_string()))
|
||||||
.with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1))
|
.with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1))
|
||||||
.with_roll(DiceRoll::new("Fire".to_string(), 4, 2))
|
.with_roll(DiceRoll::new("Fire".to_string(), 4, 2)),
|
||||||
)
|
)
|
||||||
.with_action(ActionDefinition::new("Attack +3".to_string()).with_roll(DiceRoll::new("Base".to_string(), 20, 1)))
|
.with_action(ActionDefinition::new("Attack +3".to_string()).with_roll(DiceRoll::new(
|
||||||
.with_action(ActionDefinition::new("Attack -1".to_string()))
|
"Base".to_string(),
|
||||||
)
|
20,
|
||||||
],
|
1,
|
||||||
|
)))
|
||||||
|
.with_action(ActionDefinition::new("Attack -1".to_string())),
|
||||||
|
)],
|
||||||
users: HashMap::new(),
|
users: HashMap::new(),
|
||||||
creds,
|
creds,
|
||||||
}
|
}
|
||||||
|
@ -63,20 +71,34 @@ impl GameServer {
|
||||||
api::Request::Error => {}
|
api::Request::Error => {}
|
||||||
api::Request::Login(login) => {
|
api::Request::Login(login) => {
|
||||||
println!("login req from {}: {:?}", &id, &login);
|
println!("login req from {}: {:?}", &id, &login);
|
||||||
if !self.users.contains_key(&login.username) && self.creds.get(&login.username).map(|p| p == &login.password).unwrap_or(false) {
|
if !self.users.contains_key(&login.username) &&
|
||||||
|
self.creds
|
||||||
|
.get(&login.username)
|
||||||
|
.map(|p| p == &login.password)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
self.users.insert(login.username.clone(), login.username == "rusty"); // rusty will be admin for now :)
|
self.users.insert(login.username.clone(), login.username == "rusty"); // rusty will be admin for now :)
|
||||||
_ = broadcast.send((Some(id), api::Response::Login(api::login::LoginResult { success: true, username: login.username })));
|
_ = broadcast.send((
|
||||||
}
|
Some(id),
|
||||||
else {
|
api::Response::Login(api::login::LoginResult {
|
||||||
_ = broadcast.send((Some(id.clone()), api::Response::Login(api::login::LoginResult { success: false, username: login.username })));
|
success: true,
|
||||||
|
username: login.username,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
_ = broadcast.send((
|
||||||
|
Some(id.clone()),
|
||||||
|
api::Response::Login(api::login::LoginResult {
|
||||||
|
success: false,
|
||||||
|
username: login.username,
|
||||||
|
}),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
api::Request::Message(mut msg) => {
|
api::Request::Message(mut msg) => {
|
||||||
if msg.id == 0 || msg.id > self.chat.len() {
|
if msg.id == 0 || msg.id > self.chat.len() {
|
||||||
msg.id = self.chat.len() + 1; // set the message id, 0 is invalid
|
msg.id = self.chat.len() + 1; // set the message id, 0 is invalid
|
||||||
}
|
} else if id == self.chat[msg.id - 1].0 || *self.users.get(&id).unwrap_or(&false) {
|
||||||
// TODO: check if the editor is an admin as well
|
|
||||||
else if id == self.chat[msg.id - 1].0 {
|
|
||||||
self.chat[msg.id - 1] = (id.clone(), msg.clone());
|
self.chat[msg.id - 1] = (id.clone(), msg.clone());
|
||||||
} else {
|
} else {
|
||||||
// if its an edit message and editor is not the owner, skip
|
// if its an edit message and editor is not the owner, skip
|
||||||
|
@ -116,37 +138,57 @@ impl GameServer {
|
||||||
} else {
|
} else {
|
||||||
self.chat.len() - amount
|
self.chat.len() - amount
|
||||||
};
|
};
|
||||||
let history: Vec<ChatMessage> =
|
let history: Vec<ChatMessage> = self.chat.iter().skip(start).map(|m| m.1.clone()).collect();
|
||||||
self.chat.iter().skip(start).map(|m| m.1.clone()).collect();
|
|
||||||
_ = broadcast.send((Some(id), api::Response::GetChatHistory(history)));
|
_ = broadcast.send((Some(id), api::Response::GetChatHistory(history)));
|
||||||
},
|
}
|
||||||
api::Request::GetTokens { scene } => {
|
api::Request::GetTokens { scene } => {
|
||||||
for token_id in self.game.available_tokens(scene) {
|
for token_id in self.game.available_tokens(scene) {
|
||||||
if let Some(ti) = self.game.token_info(0, token_id) {
|
if let Some(ti) = self.game.token_info(0, token_id) {
|
||||||
let bits = std::fs::read(&ti.img_source).expect("FAILED READING TOKEN IMAGE");
|
let bits = std::fs::read(&ti.img_source).expect("FAILED READING TOKEN IMAGE");
|
||||||
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
||||||
_ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id: token_id, x: ti.x, y: ti.y, img })));
|
_ = broadcast.send((
|
||||||
|
Some(id.clone()),
|
||||||
|
api::Response::SpawnToken(SpawnToken {
|
||||||
|
token_id: token_id,
|
||||||
|
x: ti.x,
|
||||||
|
y: ti.y,
|
||||||
|
img,
|
||||||
|
}),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
api::Request::SpawnToken { map_id, character, x, y, img_path } => {
|
api::Request::SpawnToken {
|
||||||
|
map_id,
|
||||||
|
character,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
img_path,
|
||||||
|
} => {
|
||||||
let token_id = self.game.create_token(map_id, character, img_path.clone(), x, y);
|
let token_id = self.game.create_token(map_id, character, img_path.clone(), x, y);
|
||||||
let bits = std::fs::read(&img_path).expect("FAILED READING TOKEN IMAGE");
|
let bits = std::fs::read(&img_path).expect("FAILED READING TOKEN IMAGE");
|
||||||
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
||||||
_ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id, x, y, img })));
|
_ = broadcast.send((
|
||||||
},
|
Some(id.clone()),
|
||||||
|
api::Response::SpawnToken(SpawnToken { token_id, x, y, img }),
|
||||||
|
));
|
||||||
|
}
|
||||||
api::Request::MoveToken { token_id, x, y } => {
|
api::Request::MoveToken { token_id, x, y } => {
|
||||||
// TODO: add check to make sure the actor is authorized to move the token
|
// TODO: add check to make sure the actor is authorized to move the token
|
||||||
if self.game.move_token(0, token_id, x, y) {
|
if self.game.move_token(0, token_id, x, y) {
|
||||||
// TODO: maybe chage move_token to return optional x,y values if succeeded to make sure the token is where it was going to be
|
// TODO: maybe chage move_token to return optional x,y values if succeeded to make sure the token is where it was going to be
|
||||||
_ = broadcast.send((None, api::Response::MoveToken { token_id, x, y }));
|
_ = broadcast.send((None, api::Response::MoveToken { token_id, x, y }));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
api::Request::ActionResult(result) => {
|
api::Request::ActionResult(result) => {
|
||||||
let msg = ChatMessage::new(
|
let msg = ChatMessage::new(
|
||||||
result.results.iter()
|
result
|
||||||
|
.results
|
||||||
|
.iter()
|
||||||
// .map(|d| &d.result_text)
|
// .map(|d| &d.result_text)
|
||||||
.fold(String::new(), |a,b| a + &format!("{}: {} = {}\n", &b.name, &b.result_text, b.result))
|
.fold(String::new(), |a, b| {
|
||||||
|
a + &format!("{}: {} = {}\n", &b.name, &b.result_text, b.result)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.character(Some(result.name))
|
.character(Some(result.name))
|
||||||
.source(id.clone())
|
.source(id.clone())
|
||||||
|
@ -154,8 +196,7 @@ impl GameServer {
|
||||||
.id(self.chat.len() + 1);
|
.id(self.chat.len() + 1);
|
||||||
self.chat.push((id, msg.clone()));
|
self.chat.push((id, msg.clone()));
|
||||||
_ = broadcast.send((None, api::Response::Message(msg)));
|
_ = broadcast.send((None, api::Response::Message(msg)));
|
||||||
|
}
|
||||||
},
|
|
||||||
api::Request::CreateCharacter => {
|
api::Request::CreateCharacter => {
|
||||||
// check if user is admin
|
// check if user is admin
|
||||||
if self.users.get(&id).map(|a| *a).unwrap_or(false) {
|
if self.users.get(&id).map(|a| *a).unwrap_or(false) {
|
||||||
|
@ -163,13 +204,13 @@ impl GameServer {
|
||||||
// return the new id with the character i think
|
// return the new id with the character i think
|
||||||
_ = broadcast.send((Some(id), api::Response::CharacterCreated(new_id)));
|
_ = broadcast.send((Some(id), api::Response::CharacterCreated(new_id)));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
api::Request::Quit => {
|
api::Request::Quit => {
|
||||||
if self.users.contains_key(&id) {
|
if self.users.contains_key(&id) {
|
||||||
self.users.remove(&id);
|
self.users.remove(&id);
|
||||||
}
|
}
|
||||||
_ = broadcast.send((None, api::Response::Quit { id }));
|
_ = broadcast.send((None, api::Response::Quit { id }));
|
||||||
},
|
}
|
||||||
api::Request::Kick(id) => {
|
api::Request::Kick(id) => {
|
||||||
if self.users.contains_key(&id) {
|
if self.users.contains_key(&id) {
|
||||||
self.users.remove(&id);
|
self.users.remove(&id);
|
||||||
|
|
80
src/main.rs
80
src/main.rs
|
@ -1,7 +1,12 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::ws::{self,Message}, response, routing, Router
|
Router,
|
||||||
|
extract::ws::{self, Message},
|
||||||
|
response, routing,
|
||||||
|
};
|
||||||
|
use futures_util::{
|
||||||
|
SinkExt, StreamExt,
|
||||||
|
stream::{SplitSink, SplitStream},
|
||||||
};
|
};
|
||||||
use futures_util::{stream::{SplitSink, SplitStream}, SinkExt, StreamExt};
|
|
||||||
use open_tavern::api::{Request, RequestError, Response};
|
use open_tavern::api::{Request, RequestError, Response};
|
||||||
use tokio::sync::{broadcast, mpsc};
|
use tokio::sync::{broadcast, mpsc};
|
||||||
|
|
||||||
|
@ -15,19 +20,30 @@ async fn main() {
|
||||||
.route("/tavern.js", routing::get(socket))
|
.route("/tavern.js", routing::get(socket))
|
||||||
.route("/app.js", routing::get(app_js))
|
.route("/app.js", routing::get(app_js))
|
||||||
.route("/style.css", routing::get(style))
|
.route("/style.css", routing::get(style))
|
||||||
.route("/ws", routing::get(move |w| ws_handler(w, msend, bsend2.clone().subscribe())));
|
.route(
|
||||||
|
"/ws",
|
||||||
|
routing::get(move |w| ws_handler(w, msend, bsend2.clone().subscribe())),
|
||||||
|
);
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
|
||||||
let game = open_tavern::GameServer::new();
|
let game = open_tavern::GameServer::new();
|
||||||
tokio::spawn(game.server_loop(mrecv, bsend));
|
tokio::spawn(game.server_loop(mrecv, bsend));
|
||||||
|
|
||||||
axum::serve(listener, app).await.expect("axum server crashed, yaaaaay (unless i crashed him that yay)");
|
axum::serve(listener, app)
|
||||||
|
.await
|
||||||
|
.expect("axum server crashed, yaaaaay (unless i crashed him that yay)");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ws_handler(ws: ws::WebSocketUpgrade, msend: mpsc::Sender<(String, Request)>, brecv: broadcast::Receiver<(Option<String>, Response)>) -> impl axum::response::IntoResponse {
|
/// Executes on a new WebSocket request, set update to [handle_socket]
|
||||||
|
async fn ws_handler(
|
||||||
|
ws: ws::WebSocketUpgrade,
|
||||||
|
msend: mpsc::Sender<(String, Request)>,
|
||||||
|
brecv: broadcast::Receiver<(Option<String>, Response)>,
|
||||||
|
) -> impl axum::response::IntoResponse {
|
||||||
ws.on_upgrade(|w| handle_socket(w, msend, brecv))
|
ws.on_upgrade(|w| handle_socket(w, msend, brecv))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receiver of a websocket after [handle_socket] handle the login
|
||||||
async fn socket_receiver(mut recv: SplitStream<ws::WebSocket>, msend: mpsc::Sender<(String, Request)>, id: String) {
|
async fn socket_receiver(mut recv: SplitStream<ws::WebSocket>, msend: mpsc::Sender<(String, Request)>, id: String) {
|
||||||
while let Some(msg) = recv.next().await {
|
while let Some(msg) = recv.next().await {
|
||||||
if let Ok(msg) = msg {
|
if let Ok(msg) = msg {
|
||||||
|
@ -47,17 +63,24 @@ async fn socket_receiver(mut recv: SplitStream<ws::WebSocket>, msend: mpsc::Send
|
||||||
// dont care if we fail the send as we are quitting regardless
|
// dont care if we fail the send as we are quitting regardless
|
||||||
_ = msend.send((id.clone(), open_tavern::api::Request::Quit)).await;
|
_ = msend.send((id.clone(), open_tavern::api::Request::Quit)).await;
|
||||||
break;
|
break;
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
async fn socket_sender(id: String, mut send: SplitSink<ws::WebSocket, ws::Message>, mut brecv: broadcast::Receiver<(Option<String>, Response)>) {
|
/// Sender of a websocket after [handle_socket] handles the login
|
||||||
|
async fn socket_sender(
|
||||||
|
id: String,
|
||||||
|
mut send: SplitSink<ws::WebSocket, ws::Message>,
|
||||||
|
mut brecv: broadcast::Receiver<(Option<String>, Response)>,
|
||||||
|
) {
|
||||||
while let Ok((to_id, msg)) = brecv.recv().await {
|
while let Ok((to_id, msg)) = brecv.recv().await {
|
||||||
if to_id.is_none() || to_id.map(|t| t == id).unwrap_or(false) {
|
if to_id.is_none() || to_id.map(|t| t == id).unwrap_or(false) {
|
||||||
println!("Sending a message to {}: {:?}", &id, &msg);
|
println!("Sending a message to {}: {:?}", &id, &msg);
|
||||||
let err = send.send(ws::Message::Text(serde_json::to_string(&msg).unwrap())).await.is_err();
|
let err = send
|
||||||
|
.send(ws::Message::Text(serde_json::to_string(&msg).unwrap().into()))
|
||||||
|
.await
|
||||||
|
.is_err();
|
||||||
if err || matches!(msg, Response::Shutdown) {
|
if err || matches!(msg, Response::Shutdown) {
|
||||||
_ = send.close().await;
|
_ = send.close().await;
|
||||||
break;
|
break;
|
||||||
|
@ -65,11 +88,22 @@ async fn socket_sender(id: String, mut send: SplitSink<ws::WebSocket, ws::Messag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Socket login handler, upon a websocket upgrade it will check for login requests until a login
|
||||||
async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, Request)>, mut brecv: broadcast::Receiver<(Option<String>, Response)>) {
|
/// request succeeds, then launch [socket_sender] and [socket_receiver] to handle the actual gameplay part
|
||||||
|
async fn handle_socket(
|
||||||
|
mut socket: ws::WebSocket,
|
||||||
|
msend: mpsc::Sender<(String, Request)>,
|
||||||
|
mut brecv: broadcast::Receiver<(Option<String>, Response)>,
|
||||||
|
) {
|
||||||
let mut id: Option<String> = None;
|
let mut id: Option<String> = None;
|
||||||
// this is a temp id, and as long as 2 people dont try to connect to the socket at the same milisecond and to the same user it would be fine (i hope)
|
// this is a temp id, and as long as 2 people dont try to connect to the socket at the same milisecond and to the same user it would be fine (i hope)
|
||||||
let temp_id = format!("temp_id_{}", std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).map(|t| t.as_micros()).unwrap_or(0));
|
let temp_id = format!(
|
||||||
|
"temp_id_{}",
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::SystemTime::UNIX_EPOCH)
|
||||||
|
.map(|t| t.as_micros())
|
||||||
|
.unwrap_or(0)
|
||||||
|
);
|
||||||
let mut last_login_req = std::time::Instant::now();
|
let mut last_login_req = std::time::Instant::now();
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
@ -79,12 +113,12 @@ async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, R
|
||||||
if let Response::Login(open_tavern::api::login::LoginResult { success, username }) = msg.clone() {
|
if let Response::Login(open_tavern::api::login::LoginResult { success, username }) = msg.clone() {
|
||||||
let to_id = to_id.map(|ti| ti == temp_id).unwrap_or(false);
|
let to_id = to_id.map(|ti| ti == temp_id).unwrap_or(false);
|
||||||
if to_id && success && id.as_ref().map(|id| id == &username).unwrap_or(false) {
|
if to_id && success && id.as_ref().map(|id| id == &username).unwrap_or(false) {
|
||||||
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default())).await;
|
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default().into())).await;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id = None;
|
id = None;
|
||||||
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default())).await;
|
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default().into())).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +143,7 @@ async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, R
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
_ = socket.send(Message::Text(serde_json::to_string(&Response::Error(RequestError::InvalidRequest)).unwrap())).await;
|
_ = socket.send(Message::Text(serde_json::to_string(&Response::Error(RequestError::InvalidRequest)).unwrap().into())).await;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,15 +170,23 @@ async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, R
|
||||||
async fn root() -> axum::response::Html<&'static str> {
|
async fn root() -> axum::response::Html<&'static str> {
|
||||||
response::Html(include_str!("../assets/web/index.html"))
|
response::Html(include_str!("../assets/web/index.html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn socket() -> impl response::IntoResponse {
|
async fn socket() -> impl response::IntoResponse {
|
||||||
([(axum::http::header::CONTENT_TYPE, "text/javascript")], include_str!("../assets/web/tavern.js"))
|
(
|
||||||
|
[(axum::http::header::CONTENT_TYPE, "text/javascript")],
|
||||||
|
include_str!("../assets/web/tavern.js"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn app_js() -> impl response::IntoResponse {
|
async fn app_js() -> impl response::IntoResponse {
|
||||||
([(axum::http::header::CONTENT_TYPE, "text/javascript")], include_str!("../assets/web/app.js"))
|
(
|
||||||
|
[(axum::http::header::CONTENT_TYPE, "text/javascript")],
|
||||||
|
include_str!("../assets/web/app.js"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn style() -> impl response::IntoResponse {
|
async fn style() -> impl response::IntoResponse {
|
||||||
([(axum::http::header::CONTENT_TYPE, "text/css")], include_str!("../assets/web/style.css"))
|
(
|
||||||
|
[(axum::http::header::CONTENT_TYPE, "text/css")],
|
||||||
|
include_str!("../assets/web/style.css"),
|
||||||
|
)
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue