@@ -3,6 +3,7 @@ name = "libfj" | |||
version = "0.1.0" | |||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"] | |||
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 | |||
@@ -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<AuthenticationInfo>, | |||
} | |||
impl LiveAPI { | |||
pub fn new() -> LiveAPI { | |||
LiveAPI { | |||
client: Client::new(), | |||
auth: None, | |||
} | |||
} | |||
pub async fn login_email(email: &str, password: &str) -> Result<LiveAPI, Error> { | |||
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<AuthenticationInfo, Error> { | |||
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::<AuthenticationInfo>().await; | |||
if let Ok(auth) = &res { | |||
self.auth = Some(auth.clone()); | |||
} | |||
return res; | |||
} | |||
Err(result.err().unwrap()) | |||
} | |||
pub async fn lobbies(&self) -> Result<LobbyInfo, Error> { | |||
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::<LobbyInfo>().await; | |||
} | |||
Err(result.err().unwrap()) | |||
} | |||
} |
@@ -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<String>, // ??? | |||
#[serde(rename = "Flags")] | |||
flags: Vec<String>, // ??? | |||
#[serde(rename = "Confirmed")] | |||
pub confirmed: bool, | |||
#[serde(rename = "Token")] | |||
pub token: String, | |||
#[serde(rename = "SteamId")] | |||
steam_id: Option<String>, // ??? | |||
#[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<LiveGameInfo>, | |||
} | |||
#[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) | |||
} | |||
} |
@@ -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}; |
@@ -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) | |||
} | |||
} |
@@ -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(()) | |||
} |
@@ -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(()) |