use lootalot_db::{self as db, DbConnection, QueryResult}; /// Every possible update which can happen during a query #[derive(Serialize, Debug)] pub enum Update { Wealth(db::Wealth), ItemAdded(db::Item), ItemRemoved(db::Item), ClaimAdded(db::Claim), ClaimRemoved(db::Claim), } /// Every value which can be queried #[derive(Debug)] pub enum Value { Player(db::Player), Item(db::Item), Claim(db::Claim), ItemList(Vec), ClaimList(Vec), PlayerList(Vec), } impl serde::Serialize for Value { fn serialize(&self, serializer: S) -> Result { match self { Value::Player(v) => v.serialize(serializer), Value::Item(v) => v.serialize(serializer), Value::Claim(v) => v.serialize(serializer), Value::ItemList(v) => v.serialize(serializer), Value::ClaimList(v) => v.serialize(serializer), Value::PlayerList(v) => v.serialize(serializer), } } } /// A generic response for all queries #[derive(Serialize, Debug, Default)] pub struct ApiResponse { /// The value requested, if any pub value: Option, /// A text to notify user, if relevant pub notification: Option, /// A list of updates, if any pub updates: Option>, /// A text describing errors, if any pub errors: Option, } impl ApiResponse { fn push_update(&mut self, update: Update) { if let Some(v) = self.updates.as_mut() { v.push(update); } else { self.updates = Some(vec![update]); } } fn push_error>(&mut self, error: S) { if let Some(errors) = self.errors.as_mut() { *errors = format!("{}\n{}", errors, error.into()); } else { self.errors = Some(error.into()) } } fn set_value(&mut self, value: Value) { self.value = Some(value); } fn notify>(&mut self, text: S) { self.notification = Some(text.into()); } } pub enum ApiError { DieselError(diesel::result::Error), InvalidAction(String), } /// Every allowed queries on the database pub enum ApiActions { FetchPlayers, FetchInventory, FetchClaims, // Player actions FetchPlayer(i32), FetchLoot(i32), UpdateWealth(i32, f32), BuyItems(i32, Vec<(i32, Option)>), SellItems(i32, Vec<(i32, Option)>), ClaimItem(i32, i32), UnclaimItem(i32, i32), // Group actions AddLoot(Vec), } pub enum AdminActions { AddPlayer(String, f32), //AddInventoryItem(pub String, pub i32), ResolveClaims, //SetClaimsTimeout(pub i32), } pub fn execute( conn: &DbConnection, query: ApiActions, ) -> Result { let mut response = ApiResponse::default(); match query { ApiActions::FetchPlayers => { response.set_value(Value::PlayerList(db::Players(conn).all()?)); } ApiActions::FetchInventory => { response.set_value(Value::ItemList(db::Inventory(conn).all()?)); } ApiActions::FetchClaims => { response.set_value(Value::ClaimList(db::fetch_claims(conn)?)); } ApiActions::FetchPlayer(id) => { response.set_value(Value::Player(db::Players(conn).find(id)?)); } ApiActions::FetchLoot(id) => { response.set_value(Value::ItemList(db::LootManager(conn, id).all()?)); } ApiActions::UpdateWealth(id, amount) => { response.push_update(Update::Wealth( db::AsPlayer(conn, id).update_wealth(amount)?, )); response.notify(format!("Mis à jour ({}po)!", amount)); } ApiActions::BuyItems(id, params) => { let mut cumulated_diff: Vec = Vec::with_capacity(params.len()); let mut added_items: u16 = 0; for (item_id, price_mod) in params.into_iter() { if let Ok((item, diff)) = db::buy_item_from_inventory(conn, id, item_id, price_mod) { cumulated_diff.push(diff); response.push_update(Update::ItemAdded(item)); added_items += 1; } else { response.push_error(format!("Error adding {}", item_id)); } } let total_amount = cumulated_diff .into_iter() .fold(db::Wealth::from_gp(0.0), |acc, i| acc + i); response.notify(format!("{} objets achetés pour {}po", added_items, total_amount.to_gp())); response.push_update(Update::Wealth(total_amount)); } ApiActions::SellItems(id, params) => { let mut all_results: Vec = Vec::with_capacity(params.len()); let mut sold_items: u16 = 0; for (loot_id, price_mod) in params.into_iter() { if let Ok((deleted, diff)) = db::sell_item_transaction(conn, id, loot_id, price_mod) { all_results.push(diff); response.push_update(Update::ItemRemoved(deleted)); sold_items += 1; } else { response.push_error(format!("Error selling {}", loot_id)); } } let total_amount = all_results .into_iter() .fold(db::Wealth::from_gp(0.0), |acc, i| acc + i); response.notify(format!("{} objet(s) vendu(s) pour {} po", sold_items, total_amount.to_gp())); response.push_update(Update::Wealth(total_amount)); } ApiActions::ClaimItem(id, item) => { response.push_update(Update::ClaimAdded( db::Claims(conn).add(id, item)?, )); response.notify(format!("Pour moi !")); } ApiActions::UnclaimItem(id, item) => { response.push_update(Update::ClaimRemoved( db::Claims(conn).remove(id, item)?, )); response.notify(format!("Bof! Finalement non.")); } // Group actions ApiActions::AddLoot(items) => {} } Ok(response) }