diff --git a/crates/lib/src/http.rs b/crates/lib/src/http.rs index eb34cfe..7837688 100644 --- a/crates/lib/src/http.rs +++ b/crates/lib/src/http.rs @@ -113,7 +113,9 @@ impl HttpClient { /// Send a HTTP GET request and parse the JSON resonse. #[cfg(feature = "serde")] - pub fn get_json(&mut self, path: &str) -> GDResult { self.request_json("GET", path) } + pub fn get_json(&mut self, path: &str) -> GDResult { + self.request_json("GET", path) + } /// Send a HTTP Post request with JSON data and parse a JSON response. #[cfg(feature = "serde")] @@ -121,6 +123,12 @@ impl HttpClient { self.request_with_json_data("POST", path, data) } + /// Send a HTTP Post request with form data and parse a JSON response. + #[cfg(feature = "serde")] + pub fn post_form(&mut self, path: &str, data: &[(&str, &str)]) -> GDResult { + self.request_with_form_data("POST", path, data) + } + // NOTE: More methods can be added here as required /// Send a HTTP request without any data and parse the JSON response. @@ -153,4 +161,22 @@ impl HttpClient { .into_json::() .map_err(|e| ProtocolFormat.context(e)) } + + /// Send a HTTP request with form data and parse the JSON response. + #[inline] + #[cfg(feature = "serde")] + fn request_with_form_data( + &mut self, + method: &str, + path: &str, + data: &[(&str, &str)], + ) -> GDResult { + self.address.set_path(path); + self.client + .request_url(method, &self.address) + .send_form(data) + .map_err(|e| PacketSend.context(e))? + .into_json::() + .map_err(|e| ProtocolFormat.context(e)) + } } diff --git a/crates/lib/src/protocols/epic/mod.rs b/crates/lib/src/protocols/epic/mod.rs new file mode 100644 index 0000000..3d98ab9 --- /dev/null +++ b/crates/lib/src/protocols/epic/mod.rs @@ -0,0 +1,7 @@ +/// The implementation. +pub mod protocol; +/// All types used by the implementation. +pub mod types; + +pub use protocol::*; +pub use types::*; diff --git a/crates/lib/src/protocols/epic/protocol.rs b/crates/lib/src/protocols/epic/protocol.rs new file mode 100644 index 0000000..547a3da --- /dev/null +++ b/crates/lib/src/protocols/epic/protocol.rs @@ -0,0 +1,52 @@ +use crate::http::{HTTPSettings, HttpClient}; +use crate::protocols::epic::{ClientTokenResponse, Request, Response, SessionFilter}; +use crate::{GDResult, TimeoutSettings}; +use std::net::{IpAddr, SocketAddr}; + +/* +/// Query a epic server. +#[inline] +pub fn query(address: &IpAddr, port: Option) -> GDResult { + query_with_timeout(address, port, &None) +} + +/// Query a epic server. +pub fn query_with_timeout( + address: &IpAddr, + port: Option, + timeout_settings: &Option, +) -> GDResult { + let address = &SocketAddr::new(*address, port.unwrap_or(3001)); + let mut client = HttpClient::new( + address, + timeout_settings, + HTTPSettings { + protocol: crate::http::Protocol::HTTP, + hostname: None, + }, + )?; + + Ok(response.into()) +} +*/ + +pub fn get_client_oauth_token(client: &mut HttpClient, deployment_id: &str) -> GDResult { + let form_data = [ + ("grant_type", "client_credentials"), + ("deployment_id", deployment_id), + ]; + + let response = client.post_form::("/auth/v1/oauth/token", &form_data)?; + + Ok(response.into()) +} + +pub fn get_server_info(client: &mut HttpClient, deployment_id: &str) -> GDResult { + let filter = SessionFilter::new("deployment_id", "eq", deployment_id); + let request = Request::new().add_filter(filter); + + let path = format!("/matchmaking/v1/{}/filter", deployment_id); + let response = client.post_json::(&path, request)?; + + Ok(response.into()) +} diff --git a/crates/lib/src/protocols/epic/types.rs b/crates/lib/src/protocols/epic/types.rs new file mode 100644 index 0000000..2f3591e --- /dev/null +++ b/crates/lib/src/protocols/epic/types.rs @@ -0,0 +1,90 @@ +use serde_derive::Deserialize; +use serde_derive::Serialize; +use serde_json::Value; +use std::collections::HashMap; + +use crate::protocols::types::CommonPlayer; +use crate::protocols::types::CommonResponse; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ClientTokenResponse { + pub access_token: String, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub criteria: Vec, +} + +impl Request { + pub fn new() -> Self { + Self { + criteria: Vec::new(), + } + } + + pub fn add_filter(mut self, filter: SessionFilter) -> Self { + self.criteria.push(filter); + self + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionFilter { + pub key: String, + pub op: String, + pub value: String, +} + +impl SessionFilter { + pub fn new(key: &str, op: &str, value: &str) -> Self { + Self { + key: key.to_string(), + op: op.to_string(), + value: value.to_string(), + } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Response { + pub sessions: Vec, + pub count: u32, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Session { + pub deployment: String, + pub id: String, + pub bucket: String, + pub settings: Settings, + pub total_players: u32, + pub open_public_players: u32, + pub public_players: Vec, + pub started: bool, + pub last_updated: Option, + pub attributes: HashMap, + pub owner: String, + pub owner_platform_id: Option, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Settings { + pub max_public_players: u32, + pub allow_invites: bool, + pub should_advertise: bool, + pub allow_read_by_id: bool, + pub allow_join_via_presence: bool, + pub allow_join_in_progress: bool, + pub allow_conference_room: bool, + pub check_sanctions: bool, + pub allow_migration: bool, + pub rejoin_after_kick: String, + pub platforms: Option>, +} diff --git a/crates/lib/src/protocols/mod.rs b/crates/lib/src/protocols/mod.rs index 639fbf8..5e9a7b6 100644 --- a/crates/lib/src/protocols/mod.rs +++ b/crates/lib/src/protocols/mod.rs @@ -15,4 +15,8 @@ pub mod unreal2; /// Reference: [Server Query](https://developer.valvesoftware.com/wiki/Server_queries) pub mod valve; +/// Reference: [EOS Web API](https://dev.epicgames.com/docs/web-api-ref) +#[cfg(feature = "serde")] +pub mod epic; + pub use types::{ExtraRequestSettings, GenericResponse, Protocol};