diff --git a/.gitignore b/.gitignore index 5bf44a7..75654b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /log /target +/server_config.yml \ No newline at end of file diff --git a/phira-mp-server/Cargo.toml b/phira-mp-server/Cargo.toml index 5ea403e..9c9061a 100644 --- a/phira-mp-server/Cargo.toml +++ b/phira-mp-server/Cargo.toml @@ -8,6 +8,7 @@ anyhow = { version = "1.0", features = ["backtrace"] } phira-mp-common = { path = "../phira-mp-common" } reqwest = { version = "0.11.18", features = ["json"] } serde = { version = "1.0.163", features = ["derive"] } +serde_yaml = "0.9" tap = "1.0.1" tokio = "*" tracing = "0.1.37" diff --git a/phira-mp-server/src/server.rs b/phira-mp-server/src/server.rs index a6859ad..62e1083 100644 --- a/phira-mp-server/src/server.rs +++ b/phira-mp-server/src/server.rs @@ -2,7 +2,7 @@ use crate::{vacant_entry, IdMap, Room, SafeMap, Session, User}; use anyhow::Result; use phira_mp_common::RoomId; use serde::Deserialize; -use std::sync::Arc; +use std::{fs, sync::Arc}; use tokio::{net::TcpListener, sync::mpsc, task::JoinHandle}; use tracing::{info, warn}; use uuid::Uuid; @@ -13,6 +13,18 @@ pub struct Chart { pub name: String, } +#[derive(Debug, Deserialize)] +pub struct ServerConfig { + pub monitors: Vec +} +impl Default for ServerConfig { + fn default() -> Self { + Self { + monitors: vec![2], + } + } +} + #[derive(Debug, Deserialize)] pub struct Record { pub id: i32, @@ -30,6 +42,7 @@ pub struct Record { } pub struct ServerState { + pub config: ServerConfig, pub sessions: IdMap>, pub users: SafeMap>, @@ -41,14 +54,140 @@ pub struct ServerState { pub struct Server { state: Arc, listener: TcpListener, + lost_con_handle: JoinHandle<()>, +} + +impl From for Server {use crate::{vacant_entry, IdMap, Room, SafeMap, Session, User}; +use anyhow::Result; +use phira_mp_common::RoomId; +use serde::Deserialize; +use std::{fs::File, sync::Arc}; +use tokio::{net::TcpListener, sync::mpsc, task::JoinHandle}; +use tracing::{info, warn}; +use uuid::Uuid; + +#[derive(Debug, Deserialize)] +pub struct Chart { + pub id: i32, + pub name: String, +} +#[derive(Debug, Deserialize)] +pub struct ServerConfig { + pub monitors: Vec, +} +impl Default for ServerConfig { + fn default() -> Self { + Self { monitors: vec![2] } + } +} + +#[derive(Debug, Deserialize)] +pub struct Record { + pub id: i32, + pub player: i32, + pub score: i32, + pub perfect: i32, + pub good: i32, + pub bad: i32, + pub miss: i32, + pub max_combo: i32, + pub accuracy: f32, + pub full_combo: bool, + pub std: f32, + pub std_score: f32, +} + +pub struct ServerState { + pub config: ServerConfig, + pub sessions: IdMap>, + pub users: SafeMap>, + + pub rooms: SafeMap>, + + pub lost_con_tx: mpsc::Sender, +} + +pub struct Server { + state: Arc, + listener: TcpListener, lost_con_handle: JoinHandle<()>, } impl From for Server { fn from(listener: TcpListener) -> Self { let (lost_con_tx, mut lost_con_rx) = mpsc::channel(16); + let config: ServerConfig = File::open("server_config.yml") + .ok() + .and_then(|f| serde_yaml::from_reader(f).ok()) + .unwrap_or_default(); + let state = Arc::new(ServerState { + config, + sessions: IdMap::default(), + users: SafeMap::default(), + + rooms: SafeMap::default(), + + lost_con_tx, + }); + let lost_con_handle = tokio::spawn({ + let state = Arc::clone(&state); + async move { + while let Some(id) = lost_con_rx.recv().await { + warn!("lost connection with {id}"); + if let Some(session) = state.sessions.write().await.remove(&id) { + if session + .user + .session + .read() + .await + .as_ref() + .map_or(false, |it| it.ptr_eq(&Arc::downgrade(&session))) + { + Arc::clone(&session.user).dangle().await; + } + } + } + } + }); + + Self { + listener, + state, + + lost_con_handle, + } + } +} + +impl Server { + pub async fn accept(&self) -> Result<()> { + let (stream, addr) = self.listener.accept().await?; + let mut guard = self.state.sessions.write().await; + let entry = vacant_entry(&mut guard); + let session = Session::new(*entry.key(), stream, Arc::clone(&self.state)).await?; + info!( + "received connections from {addr} ({}), version: {}", + session.id, + session.version() + ); + entry.insert(session); + Ok(()) + } +} + +impl Drop for Server { + fn drop(&mut self) { + self.lost_con_handle.abort(); + } +} + + fn from(listener: TcpListener) -> Self { + let (lost_con_tx, mut lost_con_rx) = mpsc::channel(16); + let config: + let config: ServerConfig = serde_yaml::from_str(&fs::read_to_string("server_config.yml").unwrap(); let state = Arc::new(ServerState { + config, sessions: IdMap::default(), users: SafeMap::default(), diff --git a/phira-mp-server/src/session.rs b/phira-mp-server/src/session.rs index 07a9932..278a4f6 100644 --- a/phira-mp-server/src/session.rs +++ b/phira-mp-server/src/session.rs @@ -27,7 +27,6 @@ use tracing::{debug, debug_span, error, info, trace, warn, Instrument}; use uuid::Uuid; const HOST: &str = "https://phira.5wyxi.com"; -const MONITORS: &[i32] = &[2, 143245]; pub struct User { pub id: i32, @@ -71,7 +70,7 @@ impl User { } pub fn can_monitor(&self) -> bool { - MONITORS.contains(&self.id) + self.server.config.monitors.contains(&self.id) } pub async fn set_session(&self, session: Weak) {