use mnml_core::mob::anim_test_game; use mnml_core::item::item_info; use std::time::Instant; use uuid::Uuid; use failure::Error; use failure::err_msg; use crossbeam_channel::{Sender as CbSender}; use stripe::{Client as StripeClient}; use serde_cbor::{from_slice}; use pg::{ game_concede, game_offer_draw, game_ready, game_skill, game_skill_clear, game_state, instance_abandon, instance_practice, instance_ready, instance_state, vbox_apply, vbox_buy, vbox_combine, vbox_refill, vbox_refund, vbox_unequip, }; use account::{Account}; use account; use events::{Event}; use mtx; use mail; use payments; use pg::{PgPool}; use rpc::{RpcMessage, RpcRequest, User}; #[derive(Debug,Clone)] pub struct Authenticated { pub account: Account, pub id: Uuid, events: CbSender, ws: CbSender, pool: PgPool, } impl Authenticated { pub fn new(account: Account, ws: CbSender, events: CbSender, pool: PgPool) -> Authenticated { Authenticated { id: account.id, account, ws, events, pool, } } } impl User for Authenticated { 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::AccountState(ref v) => { self.events.send(Event::Subscribe(self.id, v.id))? }, RpcMessage::GameState(ref v) => self.events.send(Event::Subscribe(self.id, v.id))?, RpcMessage::InstanceState(ref v) => self.events.send(Event::Subscribe(self.id, v.id))?, _ => (), }; self.ws.send(msg)?; Ok(()) } fn connected(&mut self) -> Result<(), Error> { info!("authenticated connection account={:?}", self.account); let a = &self.account; self.ws.send(RpcMessage::AccountAuthenticated(a.clone()))?; // tell events we have connected self.events.send(Event::Connect(self.id, a.clone(), self.ws.clone()))?; self.ws.send(RpcMessage::AccountState(a.clone()))?; self.events.send(Event::Subscribe(self.id, a.id))?; // check if they have an image that needs to be generated account::img_check(&a)?; let db = self.pool.get()?; let mut tx = db.transaction()?; // send account constructs let account_constructs = account::constructs(&mut tx, &a)?; self.ws.send(RpcMessage::AccountConstructs(account_constructs))?; // get account instances // and send them to the client let account_instances = account::account_instances(&mut tx, &a)?; self.ws.send(RpcMessage::AccountInstances(account_instances))?; let shop = mtx::account_shop(&mut tx, &a)?; self.ws.send(RpcMessage::AccountShop(shop))?; let team = account::team(&mut tx, &a)?; self.ws.send(RpcMessage::AccountTeam(team))?; let wheel = account::chat_wheel(&db, a.id)?; self.ws.send(RpcMessage::ChatWheel(wheel))?; if let Some(instance) = account::tutorial(&mut tx, &a)? { self.ws.send(RpcMessage::InstanceState(instance))?; } // tx should do nothing tx.commit()?; Ok(()) } fn receive(&mut self, data: Vec, stripe: &StripeClient) -> Result { // cast the msg to this type to receive method name let begin = Instant::now(); let db = self.pool.get()?; match from_slice::(&data) { Ok(v) => { let request = v.clone(); let response = match v { RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), RpcRequest::ItemInfo {} => return Ok(RpcMessage::ItemInfo(item_info())), RpcRequest::DevResolve { skill } => return Ok(RpcMessage::GameState(anim_test_game(skill))), RpcRequest::InstanceQueue {} => { self.events.send(Event::Queue(self.id))?; Ok(RpcMessage::QueueRequested(())) }, RpcRequest::InstanceInvite {} => { self.events.send(Event::Invite(self.id))?; Ok(RpcMessage::InviteRequested(())) }, RpcRequest::InstanceJoin { code } => { self.events.send(Event::Join(self.id, code))?; Ok(RpcMessage::Joining(())) }, RpcRequest::InstanceLeave {} => { self.events.send(Event::Leave(self.id))?; Ok(RpcMessage::Processing(())) }, RpcRequest::InstanceChat { instance_id, index } => { if !self.account.subscribed { return Err(err_msg("subscribe to unlock chat")) } let wheel = account::chat_wheel(&db, self.account.id)?; if let Some(c) = wheel.get(index) { self.events.send(Event::Chat(self.id, instance_id, c.to_string()))?; } else { return Err(err_msg("invalid chat index")); } Ok(RpcMessage::Processing(())) }, _ => { // all good, let's make a tx and process let mut tx = db.transaction()?; let res = match v { RpcRequest::AccountState {} => Ok(RpcMessage::AccountState(self.account.clone())), RpcRequest::AccountConstructs {} => Ok(RpcMessage::AccountConstructs(account::constructs(&mut tx, &self.account)?)), RpcRequest::AccountInstances {} => Ok(RpcMessage::AccountInstances(account::account_instances(&mut tx, &self.account)?)), RpcRequest::AccountSetTeam { ids } => Ok(RpcMessage::AccountTeam(account::set_team(&mut tx, &self.account, ids)?)), RpcRequest::EmailState {} => Ok(RpcMessage::EmailState(mail::select_account(&db, self.account.id)?)), RpcRequest::SubscriptionState {} => Ok(RpcMessage::SubscriptionState(payments::account_subscription(&db, stripe, &self.account)?)), // RpcRequest::AccountShop {} => // Ok(RpcMessage::AccountShop(mtx::account_shop(&mut tx, &account)?)), // RpcRequest::ConstructDelete" => handle_construct_delete(data, &mut tx, account), RpcRequest::GameState { id } => Ok(RpcMessage::GameState(game_state(&mut tx, &self.account, id)?)), RpcRequest::GameSkill { game_id, construct_id, target_construct_id, skill } => Ok(RpcMessage::GameState(game_skill(&mut tx, &self.account, game_id, construct_id, target_construct_id, skill)?)), RpcRequest::GameSkillClear { game_id } => Ok(RpcMessage::GameState(game_skill_clear(&mut tx, &self.account, game_id)?)), RpcRequest::GameReady { id } => Ok(RpcMessage::GameState(game_ready(&mut tx, &self.account, id)?)), RpcRequest::GameConcede { game_id } => Ok(RpcMessage::GameState(game_concede(&mut tx, &self.account, game_id)?)), RpcRequest::GameOfferDraw { game_id } => Ok(RpcMessage::GameState(game_offer_draw(&mut tx, &self.account, game_id)?)), RpcRequest::InstancePractice {} => Ok(RpcMessage::InstanceState(instance_practice(&mut tx, &self.account)?)), // these two can return GameState or InstanceState RpcRequest::InstanceReady { instance_id } => Ok(instance_ready(&mut tx, &self.account, instance_id)?), RpcRequest::InstanceState { instance_id } => Ok(instance_state(&mut tx, instance_id)?), RpcRequest::InstanceAbandon { instance_id } => Ok(instance_abandon(&mut tx, &self.account, instance_id)?), RpcRequest::VboxBuy { instance_id, group, index, construct_id } => Ok(RpcMessage::InstanceState(vbox_buy(&mut tx, &self.account, instance_id, group, index, construct_id)?)), RpcRequest::VboxApply { instance_id, construct_id, index } => Ok(RpcMessage::InstanceState(vbox_apply(&mut tx, &self.account, instance_id, construct_id, index)?)), RpcRequest::VboxCombine { instance_id, inv_indices, vbox_indices } => Ok(RpcMessage::InstanceState(vbox_combine(&mut tx, &self.account, instance_id, inv_indices, vbox_indices)?)), RpcRequest::VboxRefill { instance_id } => Ok(RpcMessage::InstanceState(vbox_refill(&mut tx, &self.account, instance_id)?)), RpcRequest::VboxRefund { instance_id, index } => Ok(RpcMessage::InstanceState(vbox_refund(&mut tx, &self.account, instance_id, index)?)), RpcRequest::VboxUnequip { instance_id, construct_id, target } => Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, &self.account, instance_id, construct_id, target, None)?)), RpcRequest::VboxUnequipApply { instance_id, construct_id, target, target_construct_id } => Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, &self.account, instance_id, construct_id, target, Some(target_construct_id))?)), RpcRequest::MtxConstructSpawn {} => Ok(RpcMessage::ConstructSpawn(mtx::new_construct(&mut tx, &self.account)?)), RpcRequest::MtxConstructApply { mtx, construct_id, name } => Ok(RpcMessage::AccountTeam(mtx::apply(&mut tx, &self.account, mtx, construct_id, name)?)), RpcRequest::MtxAccountApply { mtx } => Ok(RpcMessage::AccountState(mtx::account_apply(&mut tx, &self.account, mtx)?)), RpcRequest::MtxBuy { mtx } => Ok(RpcMessage::AccountShop(mtx::buy(&mut tx, &self.account, mtx)?)), RpcRequest::SubscriptionEnding { ending } => Ok(RpcMessage::SubscriptionState(payments::subscription_ending(&mut tx, stripe, &self.account, ending)?)), _ => Err(format_err!("unknown request request={:?}", request)), }; tx.commit()?; res } }; info!("request={:?} account={:?} duration={:?}", request, self.account.name, begin.elapsed()); return response; }, Err(e) => { warn!("{:?}", e); Err(err_msg("invalid message")) }, } } }