Browse Source

Add simple (blocking) factory API for ease of use a compatibility

tags/v0.5.1
NGnius 3 years ago
parent
commit
9211fe7dbe
9 changed files with 310 additions and 7 deletions
  1. +9
    -5
      Cargo.toml
  2. +1
    -0
      src/cardlife_simple/mod.rs
  3. +4
    -0
      src/lib.rs
  4. +1
    -1
      src/robocraft/factory.rs
  5. +3
    -1
      src/robocraft/mod.rs
  6. +76
    -0
      src/robocraft_simple/factory.rs
  7. +131
    -0
      src/robocraft_simple/factory_request_builder.rs
  8. +4
    -0
      src/robocraft_simple/mod.rs
  9. +81
    -0
      tests/robocraft_factory_simple.rs

+ 9
- 5
Cargo.toml View File

@@ -8,10 +8,14 @@ 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

[dependencies]
serde = { version = "1.0", features = ["derive"]}
serde_json = "1.0"
reqwest = { version = "0.11.1", features = ["json"]}
url = "2.2.1"
serde = { version = "^1", features = ["derive"]}
serde_json = "^1"
reqwest = { version = "^0.11", features = ["json"]}
url = "^2.2"
ureq = { version = "^2", features = ["json"], optional = true}

[dev-dependencies]
tokio = { version = "1.4.0", features = ["macros"]}
tokio = { version = "1.4.0", features = ["macros"]}

[features]
simple = ["ureq"]

+ 1
- 0
src/cardlife_simple/mod.rs View File

@@ -0,0 +1 @@
// TODO

+ 4
- 0
src/lib.rs View File

@@ -1,2 +1,6 @@
pub mod cardlife;
pub mod robocraft;
#[cfg(feature = "simple")]
pub mod robocraft_simple;
#[cfg(feature = "simple")]
pub mod cardlife_simple;

+ 1
- 1
src/robocraft/factory.rs View File

@@ -4,7 +4,7 @@ use url::{Url};
use crate::robocraft::{ITokenProvider, DefaultTokenProvider, FactoryInfo, FactorySearchBuilder, RoboShopItemsInfo, FactoryRobotGetInfo};
use crate::robocraft::factory_json::ListPayload;

const FACTORY_DOMAIN: &str = "https://factory.robocraftgame.com/";
pub const FACTORY_DOMAIN: &str = "https://factory.robocraftgame.com/";

pub struct FactoryAPI {
client: Client,


+ 3
- 1
src/robocraft/mod.rs View File

@@ -1,9 +1,11 @@
mod factory;
mod factory_json;
mod factory_request_builder;
pub use self::factory::{FactoryAPI};
pub use self::factory::{FactoryAPI, FACTORY_DOMAIN};
pub use self::factory_json::{FactoryInfo, FactoryRobotListInfo, RoboShopItemsInfo, FactoryRobotGetInfo};
pub use self::factory_request_builder::{FactorySearchBuilder, FactoryMovementType, FactoryOrderType, FactoryWeaponType, FactoryTextSearchType};
#[cfg(feature = "simple")]
pub(crate) use self::factory_json::{ListPayload};

mod auth;
pub use self::auth::{ITokenProvider, DefaultTokenProvider};


+ 76
- 0
src/robocraft_simple/factory.rs View File

@@ -0,0 +1,76 @@
use ureq::{Agent, Error, Response};
use url::Url;
use serde_json::{to_string};

use crate::robocraft::{ITokenProvider, DefaultTokenProvider, FACTORY_DOMAIN, FactoryInfo, RoboShopItemsInfo, FactoryRobotGetInfo};
use crate::robocraft::{ListPayload};
use crate::robocraft_simple::FactorySearchBuilder;

pub struct FactoryAPI {
client: Agent,
token: Box<dyn ITokenProvider>,
}

impl FactoryAPI {
pub fn new() -> FactoryAPI {
FactoryAPI {
client: Agent::new(),
token: Box::new(DefaultTokenProvider{}),
}
}
pub fn list(&self) -> Result<FactoryInfo<RoboShopItemsInfo>, Error> {
let url = Url::parse(FACTORY_DOMAIN)
.unwrap()
.join("/api/roboShopItems/list")
.unwrap();
let payload = ListPayload::default();
let mut request_builder = self.client.post(url.as_str())
.set("Content-Type", "application/json");
if let Ok(token) = self.token.token() {
request_builder = request_builder.set("Authorization", &("Web ".to_owned() + &token));
}
let result = request_builder.send_string(&to_string(&payload).unwrap());
if let Ok(response) = result {
let json_res = response.into_json::<FactoryInfo<RoboShopItemsInfo>>();
if let Ok(json) = json_res {
return Ok(json);
}
return Err(Error::Status(500, Response::new(500, "Malformed JSON", "").unwrap())); // server returned malformed data
}
Err(result.err().unwrap())
}
pub fn list_builder(&self) -> FactorySearchBuilder {
let url = Url::parse(FACTORY_DOMAIN)
.unwrap()
.join("/api/roboShopItems/list")
.unwrap();
let mut token_opt = None;
if let Ok(token) = self.token.token() {
token_opt = Some(token);
}
let request_builder = self.client.post(url.as_str());
FactorySearchBuilder::new(request_builder, token_opt)
}
pub fn get(&self, item_id: usize) -> Result<FactoryInfo<FactoryRobotGetInfo>, Error> {
let url = Url::parse(FACTORY_DOMAIN)
.unwrap()
.join(&format!("/api/roboShopItems/get/{}", item_id))
.unwrap();
let mut request_builder = self.client.get(url.as_str());
if let Ok(token) = self.token.token() {
request_builder = request_builder.set("Authorization", &("Web ".to_owned() + &token));
}
let result = request_builder.call();
if let Ok(response) = result {
let json_res = response.into_json::<FactoryInfo<FactoryRobotGetInfo>>();
if let Ok(json) = json_res {
return Ok(json);
}
return Err(Error::Status(500, Response::new(500, "Malformed JSON", "").unwrap())); // server returned malformed data
}
Err(result.err().unwrap())
}
}

+ 131
- 0
src/robocraft_simple/factory_request_builder.rs View File

@@ -0,0 +1,131 @@
use ureq::{Request, Response, Error};

use crate::robocraft::{FactoryInfo, RoboShopItemsInfo, FactoryTextSearchType, FactoryWeaponType, FactoryMovementType, FactoryOrderType};
use crate::robocraft::{ListPayload};

pub struct FactorySearchBuilder {
reqwest_builder: Request,
payload: ListPayload,
token: Option<String>,
}

impl FactorySearchBuilder {
pub(crate) fn new(request_builder: Request, token: Option<String>) -> FactorySearchBuilder {
FactorySearchBuilder {
reqwest_builder: request_builder.set("Content-Type", "application/json"),
payload: ListPayload::empty(),
token,
}
}
pub fn page(mut self, page_number: isize) -> Self {
self.payload.page = page_number;
self
}
pub fn items_per_page(mut self, page_size: isize) -> Self {
self.payload.page_size = page_size;
self
}
pub fn order(mut self, order_type: FactoryOrderType) -> Self {
self.payload.order = order_type as isize;
self
}
/* // this appears to not do anything (removed to prevent confusion)
// use text_search_type(FactoryTextSearchType::Player) instead
pub fn players_only(mut self, p: bool) -> Self {
self.payload.player_filter = p;
self
}
*/
pub fn movement_or(mut self, movement_type: FactoryMovementType) -> Self {
if self.payload.movement_filter == "" {
self.payload.movement_filter = format!("{},{}", &self.payload.movement_filter, movement_type as isize);
} else {
self.payload.movement_filter = (movement_type as isize).to_string();
}
self.payload.movement_category_filter = self.payload.movement_filter.clone();
self
}
pub fn weapon_or(mut self, weapon_type: FactoryWeaponType) -> Self {
if self.payload.weapon_filter == "" {
self.payload.weapon_filter = format!("{},{}", &self.payload.weapon_filter, weapon_type as isize);
} else {
self.payload.weapon_filter = (weapon_type as isize).to_string();
}
self.payload.weapon_category_filter = self.payload.weapon_filter.clone();
self
}
pub fn cpu_range(mut self, min: isize, max: isize) -> Self {
self.payload.minimum_cpu = min;
self.payload.maximum_cpu = max;
self
}
pub fn min_cpu(mut self, min: isize) -> Self {
self.payload.minimum_cpu = min;
self
}
pub fn max_cpu(mut self, max: isize) -> Self {
self.payload.maximum_cpu = max;
self
}
pub fn no_minimum_cpu(mut self) -> Self {
self.payload.minimum_cpu = -1;
self
}
pub fn no_maximum_cpu(mut self) -> Self {
self.payload.maximum_cpu = -1;
self
}
pub fn text(mut self, t: String) -> Self {
self.payload.text_filter = t;
self
}
pub fn text_search_type(mut self, search_type: FactoryTextSearchType) -> Self {
self.payload.text_search_field = search_type as isize;
self
}
// setting buyable to false while using the default token provider will cause HTTP status 500 error
pub fn buyable(mut self, b: bool) -> Self {
self.payload.buyable = b;
self
}
pub fn prepend_featured(mut self, b: bool) -> Self {
self.payload.prepend_featured_robot = b;
self
}
pub fn default_page(mut self, b: bool) -> Self {
self.payload.default_page = b;
self
}
pub fn send(mut self) -> Result<FactoryInfo<RoboShopItemsInfo>, Error> {
self.reqwest_builder = self.reqwest_builder;
if let Some(token) = self.token.clone() {
self.reqwest_builder = self.reqwest_builder.set("Authorization", &("Web ".to_owned() + &token));
}
let result = self.reqwest_builder.send_string(&serde_json::to_string(&self.payload).unwrap());
if let Ok(response) = result {
let json_res = response.into_json::<FactoryInfo<RoboShopItemsInfo>>();
if let Ok(json) = json_res {
return Ok(json);
}
return Err(Error::Status(500, Response::new(500, "Malformed JSON", "").unwrap())); // server returned malformed data
}
Err(result.err().unwrap())
}
}

+ 4
- 0
src/robocraft_simple/mod.rs View File

@@ -0,0 +1,4 @@
mod factory;
mod factory_request_builder;
pub use factory::{FactoryAPI};
pub use factory_request_builder::{FactorySearchBuilder};

+ 81
- 0
tests/robocraft_factory_simple.rs View File

@@ -0,0 +1,81 @@
#[cfg(feature = "simple")]
use libfj::robocraft_simple;
#[cfg(feature = "simple")]
use libfj::robocraft;

#[cfg(feature = "simple")]
#[test]
fn robocraft_factory_api_init_simple() -> Result<(), ()> {
robocraft_simple::FactoryAPI::new();
Ok(())
}

#[cfg(feature = "simple")]
fn builder() -> robocraft_simple::FactorySearchBuilder {
robocraft_simple::FactoryAPI::new().list_builder()
}

#[cfg(feature = "simple")]
fn assert_factory_list(robo_info: robocraft::FactoryInfo<robocraft::RoboShopItemsInfo>) -> Result<(), ()> {
assert_ne!(robo_info.response.roboshop_items.len(), 0);
assert_eq!(robo_info.status_code, 200);
for robot in &robo_info.response.roboshop_items {
assert_ne!(robot.item_name, "");
assert_ne!(robot.added_by, "");
assert_ne!(robot.added_by_display_name, "");
assert_ne!(robot.thumbnail, "");
println!("FactoryRobotListInfo.to_string() -> `{}`", robot.to_string());
}
Ok(())
}

#[test]
#[cfg(feature = "simple")]
fn robocraft_factory_custom_query_simple() -> Result<(), ()> {
let result = builder()
.movement_or(robocraft::FactoryMovementType::Wheels)
.weapon_or(robocraft::FactoryWeaponType::Laser)
.page(2)
.items_per_page(10)
.send();
assert!(result.is_ok());
let robo_info = result.unwrap();
assert_ne!(robo_info.response.roboshop_items.len(), 0);
//assert_eq!(robo_info.response.roboshop_items.len(), 16); the API behaviour is weird, I swear it's not me!
assert!(robo_info.response.roboshop_items.len() >= 10);
assert_eq!(robo_info.status_code, 200);
for robot in &robo_info.response.roboshop_items {
assert_ne!(robot.item_name, "");
assert_ne!(robot.added_by, "");
assert_ne!(robot.added_by_display_name, "");
assert_ne!(robot.thumbnail, "");
println!("FactoryRobotListInfo.to_string() -> `{}`", robot.to_string());
}
Ok(())
}

#[test]
#[cfg(feature = "simple")]
fn robocraft_factory_player_query() -> Result<(), ()> {
let result = builder()
.text("Baerentoeter".to_string())
.text_search_type(robocraft::FactoryTextSearchType::Player)
.items_per_page(10)
.send();
assert!(result.is_ok());
assert_factory_list(result.unwrap())
}

#[test]
#[cfg(feature = "simple")]
fn robocraft_factory_robot_query() -> Result<(), ()> {
let api = robocraft_simple::FactoryAPI::new();
let result = api.get(6478345 /* featured robot id*/);
assert!(result.is_ok());
let bot_info = result.unwrap();
assert_ne!(bot_info.response.item_name, "");
assert_eq!(bot_info.response.item_id, 6478345);
assert_ne!(bot_info.response.cube_data, "");
assert_ne!(bot_info.response.colour_data, "");
Ok(())
}

Loading…
Cancel
Save