use std::collections::BTreeMap; use std::convert::TryInto; use crate::entity::account::*; use crate::entity::character::*; use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::item::*; use std::sync::{Arc, Mutex}; #[derive(Clone)] pub struct InMemoryGateway { users: Arc>>, user_settings: Arc>>, characters: Arc>>, character_meseta: Arc>>, bank_meseta: Arc>>, items: Arc>>, inventories: Arc>>, banks: Arc>>, equips: Arc>>, mag_modifiers: Arc>>>, weapon_modifiers: Arc>>>, guildcard_entities: Arc>>, } impl Default for InMemoryGateway { fn default() -> InMemoryGateway { InMemoryGateway { users: Arc::new(Mutex::new(BTreeMap::new())), user_settings: Arc::new(Mutex::new(BTreeMap::new())), characters: Arc::new(Mutex::new(BTreeMap::new())), character_meseta: Arc::new(Mutex::new(BTreeMap::new())), bank_meseta: Arc::new(Mutex::new(BTreeMap::new())), items: Arc::new(Mutex::new(BTreeMap::new())), inventories: Arc::new(Mutex::new(BTreeMap::new())), banks: Arc::new(Mutex::new(BTreeMap::new())), equips: Arc::new(Mutex::new(BTreeMap::new())), mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())), weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())), guildcard_entities: Arc::new(Mutex::new(BTreeMap::new())), } } } impl InMemoryGateway { fn apply_modifiers(&self, inventory: InventoryEntity ) -> InventoryEntity { let items = self.items.lock().unwrap(); let inventory_items = inventory.items.into_iter() .map(|item| { item.map_individual(|mut item| { item.item = match item.item { ItemDetail::Weapon(mut weapon) => { if let Some(weapon_modifiers) = self.weapon_modifiers.lock().unwrap().get(&item.id) { for weapon_modifier in weapon_modifiers.iter() { weapon.apply_modifier(weapon_modifier); } } ItemDetail::Weapon(weapon) }, ItemDetail::Mag(mag) => { let mut mag = mag::Mag::baby_mag(mag.color as u16); if let Some(mag_modifiers) = self.mag_modifiers.lock().unwrap().get(&item.id) { for mag_modifier in mag_modifiers.iter() { match mag_modifier { mag::MagModifier::FeedMag {food} => { if let Some(mag_feed) = items.get(food) { if let ItemDetail::Tool(mag_feed) = mag_feed.item { mag.feed(mag_feed.tool) } } }, mag::MagModifier::OwnerChange(class, section_id) => { mag.change_owner(*class, *section_id) }, mag::MagModifier::MagCell(mag_cell_id) => { if let Some(mag_cell) = items.get(mag_cell_id) { if let ItemDetail::Tool(mag_cell) = mag_cell.item { mag.apply_mag_cell(mag_cell.tool.try_into().unwrap()) } } }, _ => {} } } } ItemDetail::Mag(mag) } _ => { item.item } }; item }) }) .collect(); InventoryEntity::new(inventory_items) } } #[async_trait::async_trait] impl EntityGateway for InMemoryGateway { async fn create_user(&mut self, user: NewUserAccountEntity) -> Result { let mut users = self.users.lock().unwrap(); let mut guildcards = self.guildcard_entities.lock().unwrap(); let id = users .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) + 1; let user = UserAccountEntity { id: UserAccountId(id), username: user.username, password: user.password, guildcard: id, team_id: user.team_id, banned_until: user.banned_until, muted_until: user.muted_until, created_at: chrono::Utc::now(), flags: user.flags, activated: user.activated, at_login: false, at_character: false, at_ship: false, }; let guildcard = GuildCardDataEntity::new(UserAccountId(id)); // TODO: NewGuildcardDataEntity ? users.insert(user.id, user.clone()); guildcards.insert(user.id, guildcard); Ok(user) } async fn get_user_by_id(&self, id: UserAccountId) -> Result { let users = self.users.lock().unwrap(); users.get(&id).cloned().ok_or(GatewayError::Error) } async fn get_user_by_name(&self, username: String) -> Result { let users = self.users.lock().unwrap(); users .iter() .find(|(_, k)| k.username == username) .map(|(_, k)| k.clone()) .ok_or(GatewayError::Error) } async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> { let mut users = self.users.lock().unwrap(); users.insert(user.id, user.clone()); Ok(()) } async fn create_user_settings(&mut self, settings: NewUserSettingsEntity) -> Result { let mut user_settings = self.user_settings.lock().unwrap(); let id = user_settings .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) + 1; let new_settings = UserSettingsEntity { id: UserSettingsId(id), user_id: settings.user_id, settings: settings.settings, }; user_settings.insert(new_settings.id, new_settings.clone()); Ok(new_settings) } async fn get_user_settings_by_user(&self, user: &UserAccountEntity) -> Result { let user_settings = self.user_settings.lock().unwrap(); user_settings .iter() .find(|(_, k)| k.user_id == user.id) .map(|(_, k)| k.clone()) .ok_or(GatewayError::Error) } async fn get_characters_by_user(&self, user: &UserAccountEntity) -> Result<[Option; 4], GatewayError> { let characters = self.characters.lock().unwrap(); const NONE: Option = None; let mut chars = [NONE; 4]; characters .iter() .filter(|(_, c)| c.user_id == user.id) .for_each(|(_, c)| chars[c.slot as usize] = Some(c.clone())); Ok(chars) } async fn create_character(&mut self, character: NewCharacterEntity) -> Result { let mut characters = self.characters.lock().unwrap(); let id = characters .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) + 1; let new_character = CharacterEntity { id: CharacterEntityId(id), user_id: character.user_id, slot: character.slot, name: character.name, exp: character.exp, char_class: character.char_class, section_id: character.section_id, appearance: character.appearance, techs: character.techs, config: character.config, info_board: character.info_board, guildcard: character.guildcard, materials: character.materials, tech_menu: character.tech_menu, option_flags: character.option_flags, }; characters.insert(new_character.id, new_character.clone()); Ok(new_character) } async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> { let mut characters = self.characters.lock().unwrap(); characters.insert(char.id, char.clone()); Ok(()) } // TODO: ok_or a real error ? async fn get_guild_card_data_by_user(&self, user: &UserAccountEntity) -> Result { let guildcards = self.guildcard_entities.lock().unwrap(); guildcards .iter() .find(|(_, g)| g.user_id == user.id) .map(|(_, g)| g.clone()) .ok_or(GatewayError::Error) } async fn create_item(&mut self, item: NewItemEntity) -> Result { let mut items = self.items.lock().unwrap(); let id = items .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) + 1; let new_item = ItemEntity { id: ItemEntityId(id), item: item.item, }; items.insert(ItemEntityId(id), new_item.clone()); Ok(new_item) } async fn add_item_note(&mut self, _item_id: &ItemEntityId, _item_note: ItemNote) -> Result<(), GatewayError> { Ok(()) } async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { self.mag_modifiers.lock().unwrap() .entry(*mag_item_id) .or_insert_with(Vec::new) .push(mag::MagModifier::FeedMag { food: *tool_item_id }); Ok(()) } async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { self.mag_modifiers.lock().unwrap() .entry(*mag_item_id) .or_insert_with(Vec::new) .push(mag::MagModifier::OwnerChange(character.char_class, character.section_id)); Ok(()) } async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { self.mag_modifiers.lock().unwrap() .entry(*mag_item_id) .or_insert_with(Vec::new) .push(mag::MagModifier::MagCell(*mag_cell_id)); Ok(()) } async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> { self.weapon_modifiers.lock().unwrap() .entry(*item_id) .or_insert_with(Vec::new) .push(modifier); Ok(()) } async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { let inventories = self.inventories.lock().unwrap(); Ok(inventories .iter() .find(|(id, _)| **id == *char_id) .map(|(_, inv)| inv.clone()) .map(|inv| self.apply_modifiers(inv)) .unwrap_or_default()) } async fn get_character_bank(&mut self, char_id: &CharacterEntityId, _bank_name: BankName) -> Result { let banks = self.banks.lock().unwrap(); Ok(banks .iter() .find(|(id, _)| **id == *char_id) .map(|(_, b)| b.clone()) .unwrap_or_default()) } async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { let mut inventories = self.inventories.lock().unwrap(); inventories.insert(*char_id, inventory.clone()); Ok(()) } // TOOD: impl bank name async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, _bank_name: BankName) -> Result<(), GatewayError> { let mut banks = self.banks.lock().unwrap(); banks.insert(*char_id, bank.clone()); Ok(()) } async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result { let equips = self.equips.lock().unwrap(); Ok(equips .iter() .find(|(id, _)| **id == *char_id) .map(|(_, inv)| inv.clone()) .unwrap_or_default()) } async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equipped: &EquippedEntity) -> Result<(), GatewayError> { let mut equips = self.equips.lock().unwrap(); equips.insert(*char_id, equipped.clone()); Ok(()) } async fn set_character_meseta(&mut self, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { let mut character_meseta = self.character_meseta.lock().unwrap(); character_meseta.insert(*char_id, meseta); Ok(()) } async fn get_character_meseta(&mut self, char_id: &CharacterEntityId) -> Result { let mut character_meseta = self.character_meseta.lock().unwrap(); if let Some(meseta) = character_meseta.get_mut(char_id) { Ok(*meseta) } else { Err(GatewayError::Error) } } async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: BankName, meseta: Meseta) -> Result<(), GatewayError> { let mut bank_meseta = self.bank_meseta.lock().unwrap(); bank_meseta.insert((*char_id, bank), meseta); Ok(()) } async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: BankName) -> Result { let mut bank_meseta = self.bank_meseta.lock().unwrap(); if let Some(meseta) = bank_meseta.get_mut(&(*char_id, bank)) { Ok(*meseta) } else { Err(GatewayError::Error) } } async fn set_guild_card(&mut self, id: UserAccountId, gc_data: GuildCardDataEntity) -> Result<(), GatewayError> { let mut guildcard = self.guildcard_entities.lock().unwrap(); guildcard.insert(id, gc_data); Ok(()) } }