use uuid::Uuid; use failure::Error; use failure::err_msg; use crossbeam_channel::{Sender as CbSender}; use serde_cbor::{from_slice}; use stripe::{Client as StripeClient}; use account::{Account}; use pg; use rpc::{RpcMessage, RpcRequest, User}; use mnml_core::game::Game; use mnml_core::item::item_info; use mnml_core::instance::Instance; #[derive(Debug,Clone)] pub struct Anonymous { pub account: Account, pub id: Uuid, pub instance: Option, pub game: Option, ws: CbSender, } impl Anonymous { pub fn new(account: Account, ws: CbSender) -> Anonymous { Anonymous { id: account.id, account, ws, instance: None, game: None, } } } impl User for Anonymous { fn send(&mut self, msg: RpcMessage) -> Result<(), Error> { // if the user queries the state of something // we tell events to push updates to them match msg { RpcMessage::GameState(ref v) => self.game = Some(v.clone()), RpcMessage::InstanceState(ref v) => self.instance = Some(v.clone()), _ => (), }; // last minute redactions and processing // this happens after the state setting as we need to keep // all the skills to prevent forfeiting let msg = match msg { RpcMessage::InstanceState(v) => RpcMessage::InstanceState(v.redact(self.id)), RpcMessage::GameState(v) => RpcMessage::GameState(v.redact(self.id)), _ => msg, }; self.ws.send(msg)?; Ok(()) } fn connected(&mut self) -> Result<(), Error> { info!("anonymous connection"); self.ws.send(RpcMessage::AccountState(self.account.clone()))?; Ok(()) } fn disconnected(&self) -> Result<(), Error> { Ok(()) } fn receive(&mut self, data: Vec, _stripe: &StripeClient) -> Result { match from_slice::(&data) { Ok(v) => { let get_instance = || { match self.instance { Some(ref i) => Ok(i.clone()), None => return Err(err_msg("instance missing")), } }; let get_game = || { match self.game { Some(ref i) => Ok(i.clone()), None => return Err(err_msg("game missing")), } }; match v { RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), RpcRequest::ItemInfo {} => return Ok(RpcMessage::ItemInfo(item_info())), RpcRequest::AccountInstances {} => return Ok(RpcMessage::Pong(())), RpcRequest::InstancePractice {} => Ok(RpcMessage::InstanceState(pg::instance_demo(&self.account)?)), RpcRequest::InstanceReady { instance_id: _ } => { match get_instance()?.player_ready(self.account.id)? { Some(g) => Ok(RpcMessage::GameState(g)), None => Ok(RpcMessage::InstanceState(get_instance()?)), } }, RpcRequest::InstanceState { instance_id: _ } => Ok(RpcMessage::InstanceState(get_instance()?)), RpcRequest::InstanceAbandon { instance_id: _ } => { let mut instance = get_instance()?; instance.finish(); Ok(RpcMessage::InstanceState(instance)) }, RpcRequest::VboxBuy { instance_id: _, group, index, construct_id } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_buy(self.account.id, group, index, construct_id)?)), RpcRequest::VboxApply { instance_id: _, construct_id, index } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_apply(self.account.id, index, construct_id)?)), RpcRequest::VboxCombine { instance_id: _, inv_indices, vbox_indices } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_combine(self.account.id, inv_indices, vbox_indices)?)), RpcRequest::VboxRefill { instance_id: _ } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_refill(self.account.id)?)), RpcRequest::VboxRefund { instance_id: _, index } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_refund(self.account.id, index)?)), RpcRequest::VboxUnequip { instance_id: _, construct_id, target } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_unequip(self.account.id, target, construct_id, None)?)), RpcRequest::VboxUnequipApply { instance_id: _, construct_id, target, target_construct_id } => Ok(RpcMessage::InstanceState(get_instance()?.vbox_unequip(self.account.id, target, construct_id, Some(target_construct_id))?)), RpcRequest::GameState { id: _ } => Ok(RpcMessage::GameState(get_game()?)), RpcRequest::GameSkill { game_id: _, construct_id, target_construct_id, skill } => { let mut game = get_game()?; game.add_skill(self.account.id, construct_id, target_construct_id, skill)?; Ok(RpcMessage::GameState(game)) }, RpcRequest::GameSkillClear { game_id: _ } => { let mut game = get_game()?; game.clear_skill(self.account.id)?; Ok(RpcMessage::GameState(game)) }, RpcRequest::GameReady { id: _ } => { let mut game = get_game()?; game.player_ready(self.account.id)?; if game.skill_phase_finished() { game = game.resolve_phase_start(); } if game.finished() { self.ws.send(RpcMessage::PromptRegister(()))?; } Ok(RpcMessage::GameState(game)) }, RpcRequest::GameConcede { game_id: _ } => Ok(RpcMessage::GameState(get_game()?.concede(self.account.id)?)), RpcRequest::GameOfferDraw { game_id: _ } => Ok(RpcMessage::GameState(get_game()?.offer_draw(self.account.id)?)), _ => Err(format_err!("unhandled anonymous request request={:?}", v)), } }, Err(e) => { warn!("{:?}", e); Err(err_msg("invalid message")) }, } } }