commit b02215b22397c51a1018c87f7d3e1578b227b26d Author: NGnius (Graham) Date: Fri Apr 2 10:38:30 2021 -0400 Implement existing CLre server functionality diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2de3917 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +/.idea diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..22d3be7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "libfj" +version = "0.1.0" +authors = ["NGnius (Graham) "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0", features = ["derive"]} +serde_json = "1.0" +reqwest = { version = "0.11.1", features = ["json"]} +url = "2.2.1" + +[dev-dependencies] +tokio = { version = "1.4.0", features = ["macros"]} \ No newline at end of file diff --git a/src/cardlife/client.rs b/src/cardlife/client.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/cardlife/mod.rs b/src/cardlife/mod.rs new file mode 100644 index 0000000..0cc9dc0 --- /dev/null +++ b/src/cardlife/mod.rs @@ -0,0 +1,6 @@ +mod client; + +mod server; +mod server_json; +pub use self::server_json::{GameInfo, StatusInfo}; +pub use self::server::{CLreServer}; diff --git a/src/cardlife/server.rs b/src/cardlife/server.rs new file mode 100644 index 0000000..81b8cbb --- /dev/null +++ b/src/cardlife/server.rs @@ -0,0 +1,46 @@ +use reqwest::{Client, IntoUrl, Error}; +use url::{Origin, Url}; +use crate::cardlife::{GameInfo, StatusInfo}; + +pub struct CLreServer { + client: Client, + addr: Url, +} + +impl CLreServer { + pub fn new(url: U) -> Result { + let url_result = url.into_url(); + if let Ok(uri) = url_result { + if let Origin::Tuple(scheme, host, port) = uri.origin() { + if let Ok(addr) = Url::parse(&format!("{}://{}:{}", scheme, host.to_string(), port)) { + return Ok( + CLreServer { + client: Client::new(), + addr, + } + ); + } + } + } + Err(()) + } + + pub async fn game_info(&self) -> Result { + let response = self.client.get(self.addr.join("/c/game.json").unwrap()) + .send().await; + if let Ok(resp) = response { + return resp.json::().await + } + Err(response.err().unwrap()) + } + + pub async fn status_info(&self) -> Result { + let response = self.client.get(self.addr.join("/status.json").unwrap()) + .send().await; + if let Ok(resp) = response { + return resp.json::().await + } + Err(response.err().unwrap()) + } +} + diff --git a/src/cardlife/server_json.rs b/src/cardlife/server_json.rs new file mode 100644 index 0000000..600373e --- /dev/null +++ b/src/cardlife/server_json.rs @@ -0,0 +1,63 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone)] +pub struct GameInfo { + #[serde(rename = "MaxPlayers")] + pub max_players: usize, + #[serde(rename = "GameId")] + pub game_id: usize, + #[serde(rename = "GameGuid")] + pub game_guid: String, + #[serde(rename = "WorldName")] + pub world_name: String, + #[serde(rename = "GameHostType")] + pub game_host_type: usize, + #[serde(rename = "PvP")] + pub pvp: bool, + #[serde(rename = "PhotonRegionOverride")] + pub photon_region_override: String, + #[serde(rename = "ServerPassword")] + pub server_password: String, + #[serde(rename = "AdminPassword")] + pub admin_password: String, +} + +impl std::string::ToString for GameInfo { + fn to_string(&self) -> String { + format!("{} ({})", self.world_name, self.game_guid) + } +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct StatusInfo { + #[serde(rename = "PlayersMax")] + pub max_players: usize, + #[serde(rename = "PlayerCount")] + pub player_count: usize, + #[serde(rename = "Status")] + pub status: String, + #[serde(rename = "OnlinePlayers")] + pub online_players: Vec +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct PlayerStatusInfo { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "isDev")] + pub is_dev: bool, + #[serde(rename = "x")] + pub x: f32, + #[serde(rename = "y")] + pub y: f32, + #[serde(rename = "z")] + pub z: f32, +} + +impl std::string::ToString for PlayerStatusInfo { + fn to_string(&self) -> String { + format!("{} ({})", self.name, self.id) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e208aaf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,4 @@ +pub mod cardlife; + +#[cfg(test)] +mod tests {} diff --git a/tests/cardlife_server.rs b/tests/cardlife_server.rs new file mode 100644 index 0000000..4cee6e4 --- /dev/null +++ b/tests/cardlife_server.rs @@ -0,0 +1,40 @@ +use libfj::cardlife; + +#[test] +#[allow(unused_variables)] +fn clre_server_init() -> Result<(), ()> { + assert!(cardlife::CLreServer::new("http://localhost:5030").is_ok()); + Ok(()) +} + +#[tokio::test] +async fn clre_server_game() -> Result<(), ()> { + let server = cardlife::CLreServer::new("http://localhost:5030").unwrap(); + let result = server.game_info().await; + assert!(result.is_ok()); + let game_info = result.unwrap(); + assert_eq!(game_info.admin_password, ""); + assert_eq!(game_info.game_host_type, 1); + println!("GameInfo.to_string() -> `{}`", game_info.to_string()); + Ok(()) +} + +#[tokio::test] +async fn clre_server_status() -> Result<(), ()> { + let server = cardlife::CLreServer::new("http://localhost:5030").unwrap(); + let result = server.status_info().await; + assert!(result.is_ok()); + let status_info = result.unwrap(); + assert_eq!(status_info.status, "Online"); + assert_eq!(status_info.max_players, 10); + assert_eq!(status_info.player_count, status_info.online_players.len()); + if status_info.online_players.len() != 0 { + for player in &status_info.online_players { + assert_ne!(player.name, ""); + assert_ne!(player.id, ""); + assert!(!player.is_dev); + println!("PlayerStatusInfo.to_string() -> `{}`", player.to_string()); + } + } + Ok(()) +} \ No newline at end of file