moved client/host into separate modules

This commit is contained in:
emilis 2025-10-01 12:35:54 +01:00
parent a11927fb68
commit 862c5004fd
No known key found for this signature in database
6 changed files with 84 additions and 29 deletions

View File

@ -60,8 +60,7 @@ pub enum HostLobbyMessage {
Start, Start,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, werewolves_macros::Titles)]
#[cfg_attr(test, derive(werewolves_macros::Titles))]
pub enum ServerToHostMessage { pub enum ServerToHostMessage {
Disconnect, Disconnect,
Daytime { Daytime {

View File

@ -9,6 +9,7 @@ use gloo::{
net::websocket::{self, futures::WebSocket}, net::websocket::{self, futures::WebSocket},
storage::{LocalStorage, Storage, errors::StorageError}, storage::{LocalStorage, Storage, errors::StorageError},
}; };
use instant::Instant;
use serde::Serialize; use serde::Serialize;
use werewolves_proto::{ use werewolves_proto::{
error::GameError, error::GameError,
@ -28,10 +29,7 @@ use crate::{
storage::StorageKey, storage::StorageKey,
}; };
use super::WerewolfError; use crate::WerewolfError;
const DEBUG_URL: &str = "ws://192.168.1.162:8080/connect/client";
const LIVE_URL: &str = "wss://wolf.emilis.dev/connect/client";
#[derive(Debug)] #[derive(Debug)]
pub enum Message { pub enum Message {
@ -48,11 +46,20 @@ pub struct Connection {
recv: Receiver<ClientMessage>, recv: Receiver<ClientMessage>,
} }
fn url() -> String {
format!(
"{}client",
option_env!("LOCAL")
.map(|_| super::DEBUG_URL)
.unwrap_or(super::LIVE_URL)
)
}
impl Connection { impl Connection {
async fn connect_ws() -> WebSocket { async fn connect_ws() -> WebSocket {
let url = option_env!("LOCAL").map(|_| DEBUG_URL).unwrap_or(LIVE_URL); let url = url();
loop { loop {
match WebSocket::open(url) { match WebSocket::open(&url) {
Ok(ws) => break ws, Ok(ws) => break ws,
Err(err) => { Err(err) => {
log::error!("connect: {err}"); log::error!("connect: {err}");
@ -78,8 +85,18 @@ impl Connection {
} }
async fn run(mut self) { async fn run(mut self) {
let url = option_env!("LOCAL").map(|_| DEBUG_URL).unwrap_or(LIVE_URL); const CONNECT_WAIT: Duration = Duration::from_secs(3);
let url = url();
let mut last_connect: Option<Instant> = None;
'outer: loop { 'outer: loop {
if let Some(last_connect) = last_connect.as_ref() {
let time_since_last = Instant::now() - *last_connect;
if time_since_last <= CONNECT_WAIT {
yew::platform::time::sleep(CONNECT_WAIT.saturating_sub(time_since_last)).await;
continue;
}
}
last_connect = Some(Instant::now());
log::info!("connecting to {url}"); log::info!("connecting to {url}");
let mut ws = Self::connect_ws().await.fuse(); let mut ws = Self::connect_ws().await.fuse();
log::info!("connected to {url}"); log::info!("connected to {url}");

View File

@ -5,12 +5,13 @@ use futures::{
channel::mpsc::{Receiver, Sender}, channel::mpsc::{Receiver, Sender},
}; };
use gloo::net::websocket::{self, futures::WebSocket}; use gloo::net::websocket::{self, futures::WebSocket};
use instant::Instant;
use serde::Serialize; use serde::Serialize;
use werewolves_proto::{ use werewolves_proto::{
error::GameError, error::GameError,
game::{GameOver, GameSettings}, game::{GameOver, GameSettings},
message::{ message::{
CharacterState, Identification, PlayerState, PublicIdentity, Target, CharacterState, PlayerState, PublicIdentity, Target,
host::{ host::{
HostDayMessage, HostGameMessage, HostLobbyMessage, HostMessage, HostNightMessage, HostDayMessage, HostGameMessage, HostLobbyMessage, HostMessage, HostNightMessage,
ServerToHostMessage, ServerToHostMessage,
@ -30,15 +31,21 @@ use crate::{
}, },
}; };
use super::WerewolfError; use crate::WerewolfError;
const DEBUG_URL: &str = "ws://192.168.1.162:8080/connect/host"; fn url() -> String {
const LIVE_URL: &str = "wss://wolf.emilis.dev/connect/host"; format!(
"{}host",
option_env!("LOCAL")
.map(|_| super::DEBUG_URL)
.unwrap_or(super::LIVE_URL)
)
}
async fn connect_ws() -> WebSocket { async fn connect_ws() -> WebSocket {
let url = option_env!("LOCAL").map(|_| DEBUG_URL).unwrap_or(LIVE_URL); let url = url();
loop { loop {
match WebSocket::open(url) { match WebSocket::open(&url) {
Ok(ws) => break ws, Ok(ws) => break ws,
Err(err) => { Err(err) => {
log::error!("connect: {err}"); log::error!("connect: {err}");
@ -64,16 +71,31 @@ fn encode_message(msg: &impl Serialize) -> websocket::Message {
} }
async fn worker(mut recv: Receiver<HostMessage>, scope: Scope<Host>) { async fn worker(mut recv: Receiver<HostMessage>, scope: Scope<Host>) {
let url = option_env!("LOCAL").map(|_| DEBUG_URL).unwrap_or(LIVE_URL); const CONNECT_WAIT: Duration = Duration::from_secs(3);
let url = url();
let mut last_connect: Option<Instant> = None;
'outer: loop { 'outer: loop {
log::info!("connecting to {url}"); if let Some(last_connect) = last_connect.as_ref() {
let time_since_last = Instant::now() - *last_connect;
if time_since_last <= CONNECT_WAIT {
log::debug!("waiting to reconnect");
yew::platform::time::sleep(CONNECT_WAIT.saturating_sub(time_since_last)).await;
log::debug!("wait over");
continue;
}
log::debug!("reconnecting");
}
last_connect = Some(Instant::now());
log::debug!("connecting to {url}");
let mut ws = connect_ws().await.fuse(); let mut ws = connect_ws().await.fuse();
log::info!("connected to {url}"); log::debug!("connected to {url}");
log::debug!("sending GetState message");
if let Err(err) = ws.send(encode_message(&HostMessage::GetState)).await { if let Err(err) = ws.send(encode_message(&HostMessage::GetState)).await {
log::error!("sending request for state: {err}"); log::error!("sending request for state: {err}");
continue 'outer; continue 'outer;
} }
log::debug!("initial GetState message sent");
loop { loop {
let msg = futures::select! { let msg = futures::select! {
@ -137,7 +159,8 @@ async fn worker(mut recv: Receiver<HostMessage>, scope: Scope<Host>) {
}; };
match parse { match parse {
Ok(msg) => { Ok(msg) => {
log::debug!("got message: {msg:?}"); log::debug!("got message: {:?}", msg.title());
log::trace!("message content: {msg:?}");
scope.send_message::<HostEvent>(msg.into()) scope.send_message::<HostEvent>(msg.into())
} }
Err(err) => { Err(err) => {
@ -553,7 +576,11 @@ impl Component for Host {
} }
if state { if state {
self.send.close_channel(); let (discard_send, mut discard_recv) = futures::channel::mpsc::channel(10);
self.send = discard_send;
yew::platform::spawn_local(async move {
while discard_recv.next().await.is_some() {}
});
} }
self.debug = false; self.debug = false;
self.error_callback = Callback::noop(); self.error_callback = Callback::noop();

View File

@ -0,0 +1,10 @@
pub mod client {
include!("client/client.rs");
}
pub mod host {
include!("host/host.rs");
}
// mod socket;
const DEBUG_URL: &str = "ws://192.168.1.162:8080/connect/";
const LIVE_URL: &str = "wss://wolf.emilis.dev/connect/";

View File

@ -1,4 +1,5 @@
mod assets; mod assets;
mod clients;
mod storage; mod storage;
mod components { mod components {
werewolves_macros::include_path!("werewolves/src/components"); werewolves_macros::include_path!("werewolves/src/components");
@ -13,7 +14,7 @@ mod pages {
mod callback; mod callback;
use core::num::NonZeroU8; use core::num::NonZeroU8;
use pages::{Client, ErrorComponent, Host, WerewolfError}; use pages::{ErrorComponent, WerewolfError};
use web_sys::Url; use web_sys::Url;
use werewolves_proto::{ use werewolves_proto::{
message::{Identification, PublicIdentity}, message::{Identification, PublicIdentity},
@ -21,7 +22,10 @@ use werewolves_proto::{
}; };
use yew::prelude::*; use yew::prelude::*;
use crate::pages::ClientProps; use crate::clients::{
client::{Client, ClientProps, Message},
host::{Host, HostEvent},
};
fn main() { fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace)); wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
@ -39,9 +43,9 @@ fn main() {
if path.starts_with("/host") { if path.starts_with("/host") {
let host = yew::Renderer::<Host>::with_root(app_element).render(); let host = yew::Renderer::<Host>::with_root(app_element).render();
host.send_message(pages::HostEvent::SetErrorCallback(error_callback)); host.send_message(HostEvent::SetErrorCallback(error_callback));
if path.starts_with("/host/big") { if path.starts_with("/host/big") {
host.send_message(pages::HostEvent::SetBigScreenState(true)); host.send_message(HostEvent::SetBigScreenState(true));
} }
} else if path.starts_with("/many-client") { } else if path.starts_with("/many-client") {
let mut number = 1..=0xFFu8; let mut number = 1..=0xFFu8;
@ -85,7 +89,7 @@ fn main() {
let client = let client =
yew::Renderer::<Client>::with_root_and_props(dupe, ClientProps { auto_join: true }) yew::Renderer::<Client>::with_root_and_props(dupe, ClientProps { auto_join: true })
.render(); .render();
client.send_message(pages::Message::ForceIdentity(Identification { client.send_message(Message::ForceIdentity(Identification {
player_id, player_id,
public: PublicIdentity { public: PublicIdentity {
name: name.to_string(), name: name.to_string(),
@ -93,7 +97,7 @@ fn main() {
number: NonZeroU8::new(number.next().unwrap()).unwrap(), number: NonZeroU8::new(number.next().unwrap()).unwrap(),
}, },
})); }));
client.send_message(pages::Message::SetErrorCallback(error_callback.clone())); client.send_message(Message::SetErrorCallback(error_callback.clone()));
} }
} else { } else {
let client = yew::Renderer::<Client>::with_root_and_props( let client = yew::Renderer::<Client>::with_root_and_props(
@ -101,6 +105,6 @@ fn main() {
ClientProps { auto_join: false }, ClientProps { auto_join: false },
) )
.render(); .render();
client.send_message(pages::Message::SetErrorCallback(error_callback)); client.send_message(Message::SetErrorCallback(error_callback));
} }
} }

View File

@ -13,8 +13,6 @@ pub enum WerewolfError {
InvalidTarget, InvalidTarget,
#[error("send error: {0}")] #[error("send error: {0}")]
SendError(#[from] futures::channel::mpsc::SendError), SendError(#[from] futures::channel::mpsc::SendError),
#[error("[{0}] {1}")]
NamedGameError(&'static str, GameError),
} }
impl From<StorageError> for WerewolfError { impl From<StorageError> for WerewolfError {