From 31fb40158c22bd88c8eb2eedc65110f992c6ae79 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 4 Apr 2021 15:49:59 -0400 Subject: [PATCH] Implement Cardlife live lobby api functionality --- Cargo.toml | 1 + src/cardlife/live.rs | 73 +++++++++++++++++ src/cardlife/live_json.rs | 85 ++++++++++++++++++++ src/cardlife/mod.rs | 6 ++ src/cardlife/server_json.rs | 4 +- tests/cardlife_live.rs | 46 +++++++++++ tests/{cardlife_server.rs => clre_server.rs} | 1 - 7 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 src/cardlife/live.rs create mode 100644 src/cardlife/live_json.rs create mode 100644 tests/cardlife_live.rs rename tests/{cardlife_server.rs => clre_server.rs} (97%) diff --git a/Cargo.toml b/Cargo.toml index 22d3be7..84e858d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "libfj" version = "0.1.0" authors = ["NGnius (Graham) "] edition = "2018" +description = "An unofficial collection of APIs used in FreeJam games and mods" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/cardlife/live.rs b/src/cardlife/live.rs new file mode 100644 index 0000000..19a293b --- /dev/null +++ b/src/cardlife/live.rs @@ -0,0 +1,73 @@ +use reqwest::{Client, Error}; +use url::{Url}; + +use crate::cardlife::{AuthenticationInfo, AuthenticationPayload, LobbyInfo, LobbyPayload}; + +const AUTHENTICATION_DOMAIN: &str = "https://live-auth.cardlifegame.com/"; +const LOBBY_DOMAIN: &str = "https://live-lobby.cardlifegame.com/"; + +pub struct LiveAPI { + client: Client, + auth: Option, +} + +impl LiveAPI { + pub fn new() -> LiveAPI { + LiveAPI { + client: Client::new(), + auth: None, + } + } + + pub async fn login_email(email: &str, password: &str) -> Result { + let mut instance = LiveAPI::new(); + let result = instance.authenticate_email(email, password).await; + if let Ok(response) = result { + instance.auth = Some(response); + return Ok(instance); + } else { + return Err(result.err().unwrap()); + } + } + + pub async fn authenticate_email(&mut self, email: &str, password: &str) -> Result { + let url = Url::parse(AUTHENTICATION_DOMAIN) + .unwrap() + .join("/api/auth/authenticate") + .unwrap(); + let payload = AuthenticationPayload { + email_address: email.to_string(), + password: password.to_string() + }; + let result = self.client.post(url) + .json(&payload) + .send().await; + if let Ok(response) = result { + let res = response.json::().await; + if let Ok(auth) = &res { + self.auth = Some(auth.clone()); + } + return res; + } + Err(result.err().unwrap()) + } + + pub async fn lobbies(&self) -> Result { + let url = Url::parse(LOBBY_DOMAIN) + .unwrap() + .join("/api/client/games") + .unwrap(); + let public_id; + if let Some(auth) = &self.auth { + public_id = auth.public_id.clone(); + } else { + public_id = "".to_string(); + } + let payload = LobbyPayload{public_id}; + let result = self.client.post(url).json(&payload).send().await; + if let Ok(response) = result { + return response.json::().await; + } + Err(result.err().unwrap()) + } +} \ No newline at end of file diff --git a/src/cardlife/live_json.rs b/src/cardlife/live_json.rs new file mode 100644 index 0000000..91cef35 --- /dev/null +++ b/src/cardlife/live_json.rs @@ -0,0 +1,85 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone)] +pub(crate) struct AuthenticationPayload { + #[serde(rename = "EmailAddress")] + pub email_address: String, + #[serde(rename = "Password")] + pub password: String, +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct AuthenticationInfo { + #[serde(rename = "PublicId")] + pub public_id: String, + #[serde(rename = "EmailAddress")] + pub email_address: String, + #[serde(rename = "DisplayName")] + pub display_name: String, + #[serde(rename = "Purchases")] + purchases: Vec, // ??? + #[serde(rename = "Flags")] + flags: Vec, // ??? + #[serde(rename = "Confirmed")] + pub confirmed: bool, + #[serde(rename = "Token")] + pub token: String, + #[serde(rename = "SteamId")] + steam_id: Option, // ??? + #[serde(rename = "ID")] + pub id: usize, +} + +impl std::string::ToString for AuthenticationInfo { + fn to_string(&self) -> String { + format!("{} ({})", &self.display_name, &self.public_id) + } +} + +#[derive(Deserialize, Serialize, Clone)] +pub(crate) struct LobbyPayload { + #[serde(rename = "PublicId")] + pub public_id: String, +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct LobbyInfo { + #[serde(rename = "Games")] + pub games: Vec, +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct LiveGameInfo { + #[serde(rename = "Id")] + pub id: usize, + #[serde(rename = "WorldName")] + pub world_name: String, + #[serde(rename = "MaxPlayers")] + pub max_players: usize, + #[serde(rename = "CurrentPlayers")] + pub current_players: usize, + #[serde(rename = "GameVersion")] + pub game_version: String, + #[serde(rename = "Ping")] + pub ping: usize, + #[serde(rename = "HasPlayed")] + pub has_played: bool, + #[serde(rename = "HasPassword")] + pub has_password: bool, + #[serde(rename = "IsPvp")] + pub is_pvp: bool, + #[serde(rename = "IsAntiCheatEnabled")] + pub is_anticheat_enabled: bool, + #[serde(rename = "IsOfficial")] + pub is_official: bool, + #[serde(rename = "ModInfo")] + pub mod_info: String, + #[serde(rename = "Region")] + pub region: String, +} + +impl std::string::ToString for LiveGameInfo { + fn to_string(&self) -> String { + format!("{} ({}):{}/{}", self.world_name, self.id, self.current_players, self.max_players) + } +} \ No newline at end of file diff --git a/src/cardlife/mod.rs b/src/cardlife/mod.rs index 0cc9dc0..05545a9 100644 --- a/src/cardlife/mod.rs +++ b/src/cardlife/mod.rs @@ -4,3 +4,9 @@ mod server; mod server_json; pub use self::server_json::{GameInfo, StatusInfo}; pub use self::server::{CLreServer}; + +mod live; +mod live_json; +pub use self::live::{LiveAPI}; +pub use self::live_json::{AuthenticationInfo, LobbyInfo, LiveGameInfo}; +pub(crate) use self::live_json::{AuthenticationPayload, LobbyPayload}; diff --git a/src/cardlife/server_json.rs b/src/cardlife/server_json.rs index 600373e..bc3f046 100644 --- a/src/cardlife/server_json.rs +++ b/src/cardlife/server_json.rs @@ -24,7 +24,7 @@ pub struct GameInfo { impl std::string::ToString for GameInfo { fn to_string(&self) -> String { - format!("{} ({})", self.world_name, self.game_guid) + format!("{} ({})", &self.world_name, &self.game_guid) } } @@ -58,6 +58,6 @@ pub struct PlayerStatusInfo { impl std::string::ToString for PlayerStatusInfo { fn to_string(&self) -> String { - format!("{} ({})", self.name, self.id) + format!("{} ({})", &self.name, &self.id) } } diff --git a/tests/cardlife_live.rs b/tests/cardlife_live.rs new file mode 100644 index 0000000..84ecb54 --- /dev/null +++ b/tests/cardlife_live.rs @@ -0,0 +1,46 @@ +use libfj::cardlife; + +const EMAIL: &str = ""; +const PASSWORD: &str = ""; + +#[test] +fn live_api_init() -> Result<(), ()> { + cardlife::LiveAPI::new(); + Ok(()) +} + +#[tokio::test] +async fn live_api_init_auth() -> Result<(), ()> { + let live = cardlife::LiveAPI::login_email(EMAIL, PASSWORD).await; + assert!(live.is_err()); // invalid credentials + Ok(()) +} + +#[tokio::test] +async fn live_api_authenticate() -> Result<(), ()> { + let mut live = cardlife::LiveAPI::new(); + let result = live.authenticate_email(EMAIL, PASSWORD).await; + assert!(result.is_err()); // invalid credentials + /*let auth_info = result.unwrap(); + assert_ne!(auth_info.token, ""); + assert_ne!(auth_info.display_name, ""); + assert_eq!(auth_info.email_address, EMAIL); + assert_ne!(auth_info.public_id, ""); + println!("AuthenticationInfo.to_string() -> `{}`", auth_info.to_string());*/ + Ok(()) +} + +#[tokio::test] +async fn live_api_lobbies() -> Result<(), ()> { + //let live = cardlife::LiveAPI::login_email(EMAIL, PASSWORD).await.unwrap(); + let live = cardlife::LiveAPI::new(); + let result = live.lobbies().await; + assert!(result.is_err()); + /* + let lobby_info = result.unwrap(); + assert_ne!(lobby_info.games.len(), 0); + for game in &lobby_info.games { + println!("LiveGameInfo.to_string() -> `{}`", game.to_string()); + }*/ + Ok(()) +} \ No newline at end of file diff --git a/tests/cardlife_server.rs b/tests/clre_server.rs similarity index 97% rename from tests/cardlife_server.rs rename to tests/clre_server.rs index 4cee6e4..99b6e0d 100644 --- a/tests/cardlife_server.rs +++ b/tests/clre_server.rs @@ -1,7 +1,6 @@ use libfj::cardlife; #[test] -#[allow(unused_variables)] fn clre_server_init() -> Result<(), ()> { assert!(cardlife::CLreServer::new("http://localhost:5030").is_ok()); Ok(())