Geoffrey-rs/geoffrey_api/src/commands/selling.rs

189 lines
5.7 KiB
Rust

use std::sync::Arc;
use geoffrey_models::models::item::ItemListing;
use geoffrey_models::models::locations::{LocationDataDb, LocationDb};
use geoffrey_models::models::parameters::selling_params::{ItemSort, Order, SellingParams};
use geoffrey_models::models::player::Player;
use geoffrey_models::models::response::selling_listing::SellingListing;
use geoffrey_models::models::CommandLevel;
use crate::api_endpoint::{ApiEndpoint, RequestType};
use crate::commands::Command;
use crate::context::Context;
use crate::Result;
pub struct Selling {}
impl ApiEndpoint for Selling {
fn endpoint_name() -> String {
"selling".to_string()
}
fn request_type() -> RequestType {
RequestType::GET
}
}
impl Command for Selling {
type Req = SellingParams;
type Resp = Vec<SellingListing>;
fn command_level() -> CommandLevel {
CommandLevel::ALL
}
fn run_command(ctx: Arc<Context>, req: &Self::Req, _: Option<Player>) -> Result<Self::Resp> {
let mut listings: Vec<SellingListing> = ctx
.db
.filter(|_, loc: &LocationDb| {
if let LocationDataDb::Shop(shop_data) = loc.loc_data.clone() {
shop_data.item_listings.iter().any(|item| {
item.item
.name
.to_lowercase()
.contains(&req.query.to_lowercase())
})
} else {
false
}
})?
.filter_map(|shop: LocationDb| {
if let LocationDataDb::Shop(shop_data) = shop.clone().loc_data {
let listings: Vec<SellingListing> = shop_data
.item_listings
.iter()
.filter_map(|item| {
if item.item.name.to_lowercase().contains(&req.query) {
Some(SellingListing {
listing: item.clone(),
shop_name: shop.name.clone(),
shop_loc: shop.position,
portal: shop.portal.clone(),
})
} else {
None
}
})
.collect();
Some(listings)
} else {
None
}
})
.flatten()
.collect();
let sort = req.sort.as_ref().unwrap_or(&ItemSort::Restock);
match sort {
ItemSort::Price => {
listings.sort_by(|a, b| ItemListing::order_by_price(&a.listing, &b.listing))
}
ItemSort::Restock => {
listings.sort_by(|a, b| ItemListing::order_by_restock(&a.listing, &b.listing))
}
}
let ordering = if let Some(order) = &req.order {
order
} else {
match sort {
ItemSort::Price => &Order::Low,
ItemSort::Restock => &Order::High,
}
};
if *ordering == Order::High {
listings.reverse();
}
Ok(listings)
}
}
#[cfg(test)]
mod test {
use std::path::PathBuf;
use std::time::Instant;
use geoffrey_models::models::item::ItemListing;
use geoffrey_models::models::locations::shop::Shop;
use geoffrey_models::models::locations::{LocationDataDb, LocationDb};
use geoffrey_models::models::parameters::selling_params::SellingParams;
use geoffrey_models::models::settings::GeoffreySettings;
use geoffrey_models::models::Position;
use crate::commands::selling::Selling;
use crate::commands::Command;
use crate::config::{GeoffreyAPIConfig, ServerConfig};
use crate::context::Context;
use crate::Args;
fn test_selling_lookup_speed(iter: i32, shop_count: i32, items_for_sale: i32) -> f32 {
let config = GeoffreyAPIConfig {
server_config: ServerConfig {
db_path: PathBuf::from("test_db/"),
host: "".to_string(),
},
geoffrey_settings: GeoffreySettings::default(),
};
let ctx = Context::new(config.clone(), Args::default()).unwrap();
let mut shop_data = Shop::default();
for _ in 0..items_for_sale {
shop_data
.item_listings
.insert(ItemListing::new("sed", 5, 5));
}
for i in 0..shop_count {
let shop = LocationDb::new(
format!("Test Shop {} {}", iter, i).as_str(),
Position::default(),
0,
None,
LocationDataDb::Shop(shop_data.clone()),
);
ctx.db.insert(shop).unwrap();
}
let start = Instant::now();
Selling::run_command(
ctx,
&SellingParams {
query: "sed".to_string(),
sort: None,
order: None,
},
None,
)
.unwrap();
let query_dur = start.elapsed().as_secs_f32();
return query_dur;
}
#[test]
fn stress_test() {
std::fs::remove_dir_all(PathBuf::from("test_db")).ok();
println!("Shop Count,Item Count,Query Time,Query Time / Shop");
for shop_count in (100..=500).step_by(100) {
let query_dur = test_selling_lookup_speed(shop_count, 100, 10);
println!(
"{},{},{},{}",
shop_count,
10,
query_dur,
query_dur / (shop_count as f32)
);
}
std::fs::remove_dir_all(PathBuf::from("test_db")).ok();
}
}