use std::time::{Instant}; use actix_web_actors::ws; use postgres::transaction::Transaction; use serde_cbor::{from_slice}; use uuid::Uuid; use failure::Error; use failure::err_msg; use net::{Db}; use ws::{MnmlSocket}; use construct::{Construct, construct_spawn, construct_delete}; use game::{Game, game_state, game_skill, game_ready}; use account::{Account, account_constructs, account_instances}; use skill::{Skill, dev_resolve, Resolutions}; use instance::{Instance, instance_state, instance_list, instance_new, instance_ready, instance_join}; use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip}; use item::{Item, ItemInfoCtr, item_info}; type MnmlWs = ws::WebsocketContext; pub fn receive(data: Vec, db: &Db, _client: &mut MnmlWs, begin: Instant, account: Option<&Account>) -> Result { // cast the msg to this type to receive method name match from_slice::(&data) { Ok(v) => { if v.method == "ping" { return Ok(RpcResult::Pong(())); } let mut tx = db.transaction()?; let account_name = match account { Some(a) => a.name.clone(), None => "none".to_string(), }; // check the method // if no auth required match v.method.as_ref() { "item_info" => return Ok(RpcResult::ItemInfo(item_info())), "dev_game_resolve" => return handle_dev_resolve(data), _ => match account { Some(_) => (), None => return Err(err_msg("auth required")), }, }; let account = account.unwrap(); // now we have the method name // match on that to determine what fn to call let response = match v.method.as_ref() { "account_state" => return Ok(RpcResult::AccountState(account.clone())), "account_constructs" => handle_account_constructs(data, &mut tx, account), "account_instances" => handle_account_instances(data, &mut tx, account), "construct_spawn" => handle_construct_spawn(data, &mut tx, account), "construct_delete" => handle_construct_delete(data, &mut tx, account), "game_state" => handle_game_state(data, &mut tx, account), "game_skill" => handle_game_skill(data, &mut tx, account), "game_ready" => handle_game_ready(data, &mut tx, account), "instance_list" => handle_instance_list(data, &mut tx, account), "instance_join" => handle_instance_join(data, &mut tx, account), "instance_ready" => handle_instance_ready(data, &mut tx, account), "instance_new" => handle_instance_new(data, &mut tx, account), "instance_state" => handle_instance_state(data, &mut tx, account), "vbox_accept" => handle_vbox_accept(data, &mut tx, account), "vbox_apply" => handle_vbox_apply(data, &mut tx, account), "vbox_combine" => handle_vbox_combine(data, &mut tx, account), "vbox_discard" => handle_vbox_discard(data, &mut tx, account), "vbox_reclaim" => handle_vbox_reclaim(data, &mut tx, account), "vbox_unequip" => handle_vbox_unequip(data, &mut tx, account), _ => Err(format_err!("unknown method - {:?}", v.method)), }; tx.commit()?; info!("method={:?} account={:?} duration={:?}", v.method, account_name, begin.elapsed()); return response; }, Err(e) => { info!("{:?}", e); Err(err_msg("unknown error")) }, } } fn handle_game_state(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; return Ok(RpcResult::GameState(game_state(msg.params, tx, &account)?)); } // fn handle_game_pve(data: Vec, tx: &mut Transaction, account: &Account) -> Result { // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; // let game_response = RpcResponse { // method: "game_state".to_string(), // params: RpcResult::GameState(game_pve(msg.params, tx, &account)?) // }; // return Ok(game_response); // } fn handle_game_skill(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::GameState(game_skill(msg.params, tx, &account)?)) } fn handle_game_ready(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::GameState(game_ready(msg.params, tx, &account)?)) } fn handle_construct_spawn(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; construct_spawn(msg.params, tx, &account)?; Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?)) } fn handle_construct_delete(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; construct_delete(tx, msg.params.id, account.id)?; Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?)) } // fn handle_account_create(data: Vec, tx: &mut Transaction) -> Result { // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; // let account = account_create(msg.params, tx)?; // Ok(RpcResult::Account(account)) // } // fn handle_account_login(data: Vec, tx: &mut Transaction) -> Result { // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; // Ok(RpcResult::Account(account_login(msg.params, tx)?)) // } fn handle_account_constructs(_data: Vec, tx: &mut Transaction, account: &Account) -> Result { Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?)) } fn handle_account_instances(_data: Vec, tx: &mut Transaction, account: &Account) -> Result { Ok(RpcResult::AccountInstances(account_instances(tx, &account)?)) } fn handle_instance_new(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(instance_new(msg.params, tx, &account)?)) } fn handle_instance_ready(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(instance_ready(msg.params, tx, &account)?)) } fn handle_instance_join(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(instance_join(msg.params, tx, &account)?)) } fn handle_instance_list(_data: Vec, tx: &mut Transaction, _account: &Account) -> Result { Ok(RpcResult::OpenInstances(instance_list(tx)?)) } fn handle_instance_state(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; match instance_state(msg.params, tx, &account)? { RpcResult::GameState(p) => Ok(RpcResult::GameState(p)), RpcResult::InstanceState(p) => Ok(RpcResult::InstanceState(p)), _ => Err(err_msg("unhandled instance state")) } } fn handle_vbox_accept(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_accept(msg.params, tx, &account)?)) } fn handle_vbox_discard(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_discard(msg.params, tx, &account)?)) } fn handle_vbox_combine(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_combine(msg.params, tx, &account)?)) } fn handle_vbox_apply(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_apply(msg.params, tx, &account)?)) } fn handle_vbox_reclaim(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_reclaim(msg.params, tx, &account)?)) } fn handle_vbox_unequip(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_unequip(msg.params, tx, &account)?)) } fn handle_dev_resolve(data: Vec) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::DevResolutions(dev_resolve(msg.params.a, msg.params.b, msg.params.skill))) } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct RpcErrorResponse { pub err: String } #[derive(Debug,Clone,Serialize,Deserialize)] pub enum RpcResult { AccountState(Account), AccountConstructs(Vec), AccountInstances(Vec), GameState(Game), ItemInfo(ItemInfoCtr), OpenInstances(Vec), InstanceState(Instance), Pong(()), DevResolutions(Resolutions), } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct RpcMessage { method: String, token: Option, } #[derive(Debug,Clone,Serialize,Deserialize)] struct ConstructSpawnMsg { method: String, params: ConstructSpawnParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct ConstructSpawnParams { pub name: String, } #[derive(Debug,Clone,Serialize,Deserialize)] struct ConstructDeleteMsg { method: String, params: ConstructDeleteParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct ConstructDeleteParams { pub id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] struct GameStateMsg { method: String, params: GameStateParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct GameStateParams { pub id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] struct GameSkillMsg { method: String, params: GameSkillParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct GameSkillParams { pub game_id: Uuid, pub construct_id: Uuid, pub target_construct_id: Option, pub skill: Skill, } #[derive(Debug,Clone,Serialize,Deserialize)] struct AccountCreateMsg { method: String, params: AccountCreateParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct AccountCreateParams { pub name: String, pub password: String, pub code: String, } #[derive(Debug,Clone,Serialize,Deserialize)] struct AccountLoginMsg { method: String, params: AccountLoginParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct AccountLoginParams { pub name: String, pub password: String, } #[derive(Debug,Clone,Serialize,Deserialize)] struct AccountConstructsMsg { method: String, params: (), } #[derive(Debug,Clone,Serialize,Deserialize)] struct InstanceLobbyMsg { method: String, params: InstanceLobbyParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct InstanceLobbyParams { pub construct_ids: Vec, pub name: String, pub pve: bool, pub password: Option, } #[derive(Debug,Clone,Serialize,Deserialize)] struct InstanceJoinMsg { method: String, params: InstanceJoinParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct InstanceJoinParams { pub instance_id: Uuid, pub construct_ids: Vec, } #[derive(Debug,Clone,Serialize,Deserialize)] struct InstanceReadyMsg { method: String, params: InstanceReadyParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct InstanceReadyParams { pub instance_id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] struct InstanceStateMsg { method: String, params: InstanceStateParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct InstanceStateParams { pub instance_id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] struct VboxAcceptMsg { method: String, params: VboxAcceptParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxAcceptParams { pub instance_id: Uuid, pub group: usize, pub index: usize, } #[derive(Debug,Clone,Serialize,Deserialize)] struct VboxDiscardMsg { method: String, params: VboxDiscardParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxDiscardParams { pub instance_id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] struct VboxCombineMsg { method: String, params: VboxCombineParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxCombineParams { pub instance_id: Uuid, pub indices: Vec, } #[derive(Debug,Clone,Serialize,Deserialize)] struct VboxApplyMsg { method: String, params: VboxApplyParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxApplyParams { pub instance_id: Uuid, pub construct_id: Uuid, pub index: usize, } #[derive(Debug,Clone,Serialize,Deserialize)] struct VboxUnequipMsg { method: String, params: VboxUnequipParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxUnequipParams { pub instance_id: Uuid, pub construct_id: Uuid, pub target: Item, } #[derive(Debug,Clone,Serialize,Deserialize)] struct VboxReclaimMsg { method: String, params: VboxReclaimParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxReclaimParams { pub instance_id: Uuid, pub index: usize, } #[derive(Debug,Clone,Serialize,Deserialize)] struct DevResolveMsg { method: String, params: DevResolveParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct DevResolveParams { pub a: Uuid, pub b: Uuid, pub skill: Skill, } // #[cfg(test)] // mod tests { // use super::*; // use serde_cbor::to_vec; // #[test] // fn rpc_parse() { // let rpc = Rpc {}; // let msg = GenerateMsg { method: "construct_generate".to_string(), params: GenerateParams { level: 64 } }; // let v = to_vec(&msg).unwrap(); // let received = rpc.receive(Message::Binary(v)); // } // }