@@ -0,0 +1,3 @@ | |||||
/target | |||||
Cargo.lock | |||||
/.idea |
@@ -0,0 +1,16 @@ | |||||
[package] | |||||
name = "libfj" | |||||
version = "0.1.0" | |||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"] | |||||
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"]} |
@@ -0,0 +1,6 @@ | |||||
mod client; | |||||
mod server; | |||||
mod server_json; | |||||
pub use self::server_json::{GameInfo, StatusInfo}; | |||||
pub use self::server::{CLreServer}; |
@@ -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<U: IntoUrl>(url: U) -> Result<CLreServer, ()> { | |||||
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<GameInfo, Error> { | |||||
let response = self.client.get(self.addr.join("/c/game.json").unwrap()) | |||||
.send().await; | |||||
if let Ok(resp) = response { | |||||
return resp.json::<GameInfo>().await | |||||
} | |||||
Err(response.err().unwrap()) | |||||
} | |||||
pub async fn status_info(&self) -> Result<StatusInfo, Error> { | |||||
let response = self.client.get(self.addr.join("/status.json").unwrap()) | |||||
.send().await; | |||||
if let Ok(resp) = response { | |||||
return resp.json::<StatusInfo>().await | |||||
} | |||||
Err(response.err().unwrap()) | |||||
} | |||||
} | |||||
@@ -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<PlayerStatusInfo> | |||||
} | |||||
#[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) | |||||
} | |||||
} |
@@ -0,0 +1,4 @@ | |||||
pub mod cardlife; | |||||
#[cfg(test)] | |||||
mod tests {} |
@@ -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(()) | |||||
} |