use tungstenite::Message; use tungstenite::protocol::WebSocket; use tungstenite::Message::Binary; use postgres::transaction::Transaction; use std::net::{TcpStream}; // demo use std::iter; use rand::{thread_rng, Rng}; use rand::distributions::{Alphanumeric}; use serde_cbor::{from_slice, to_vec}; use uuid::Uuid; use failure::Error; use failure::err_msg; use net::Db; use cryp::{Cryp, cryp_spawn}; use game::{Game, game_state, game_skill}; use account::{Account, account_create, account_login, account_from_token, account_cryps, account_instances}; use skill::{Skill}; // use zone::{Zone, zone_create, zone_join, zone_close}; use spec::{Spec}; use player::{Score, player_mm_cryps_set, Player}; use instance::{Instance, instance_state, instance_new, instance_ready, instance_join}; use vbox::{Var, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip}; pub struct Rpc; impl Rpc { pub fn receive(&self, msg: Message, db: &Db, client: &mut WebSocket) -> Result { // consume the ws data into bytes let data = msg.into_data(); // cast the msg to this type to receive method name match from_slice::(&data) { Ok(v) => { let mut tx = db.transaction()?; let account: Option = match v.token { Some(t) => Some(account_from_token(t, &mut tx)?), None => None, }; // check the method // if no auth required match v.method.as_ref() { "account_create" => (), "account_login" => (), "account_demo" => (), _ => match account { Some(_) => (), None => return Err(err_msg("auth required")), }, }; // now we have the method name // match on that to determine what fn to call let response = match v.method.as_ref() { // no auth methods "account_create" => Rpc::account_create(data, &mut tx, client), "account_login" => Rpc::account_login(data, &mut tx, client), "account_demo" => Rpc::account_demo(data, &mut tx, client), // auth methods "account_cryps" => Rpc::account_cryps(data, &mut tx, account.unwrap(), client), "account_instances" => Rpc::account_instances(data, &mut tx, account.unwrap(), client), // "account_zone" => Rpc::account_zone(data, &mut tx, account.unwrap(), client), "cryp_spawn" => Rpc::cryp_spawn(data, &mut tx, account.unwrap(), client), "game_state" => Rpc::game_state(data, &mut tx, account.unwrap(), client), "game_skill" => Rpc::game_skill(data, &mut tx, account.unwrap(), client), "instance_join" => Rpc::instance_join(data, &mut tx, account.unwrap(), client), "instance_ready" => Rpc::instance_ready(data, &mut tx, account.unwrap(), client), "instance_new" => Rpc::instance_new(data, &mut tx, account.unwrap(), client), "instance_state" => Rpc::instance_state(data, &mut tx, account.unwrap(), client), "player_mm_cryps_set" => Rpc::player_mm_cryps_set(data, &mut tx, account.unwrap(), client), "player_vbox_accept" => Rpc::player_vbox_accept(data, &mut tx, account.unwrap(), client), "player_vbox_apply" => Rpc::player_vbox_apply(data, &mut tx, account.unwrap(), client), "player_vbox_combine" => Rpc::player_vbox_combine(data, &mut tx, account.unwrap(), client), "player_vbox_discard" => Rpc::player_vbox_discard(data, &mut tx, account.unwrap(), client), "player_vbox_reclaim" => Rpc::player_vbox_reclaim(data, &mut tx, account.unwrap(), client), "player_vbox_unequip" => Rpc::player_vbox_unequip(data, &mut tx, account.unwrap(), client), _ => Err(format_err!("unknown method - {:?}", v.method)), }; tx.commit()?; return response; }, Err(e) => { println!("{:?}", e); Err(err_msg("unknown error")) }, } } fn send_msg(client: &mut WebSocket, msg: RpcResponse) -> Result<(), Error> { let bytes = to_vec(&msg)?; match client.write_message(Binary(bytes)) { Ok(()) => Ok(()), Err(e) => Err(err_msg(e)) } } fn game_state(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> 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_state(msg.params, tx, &account)?) }; return Ok(game_response); } // fn game_pve(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> 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 game_skill(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> 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_skill(msg.params, tx, &account)?) }; return Ok(game_response); } fn cryp_spawn(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Rpc::send_msg(client, RpcResponse { method: "cryp_spawn".to_string(), params: RpcResult::CrypSpawn(cryp_spawn(msg.params, tx, &account)?) })?; let cryp_list = RpcResponse { method: "account_cryps".to_string(), params: RpcResult::CrypList(account_cryps(tx, &account)?) }; Ok(cryp_list) } fn account_create(data: Vec, tx: &mut Transaction, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let account = account_create(msg.params, tx)?; Ok(RpcResponse { method: "account_create".to_string(), params: RpcResult::Account(account) }) } fn account_login(data: Vec, tx: &mut Transaction, _client: &mut WebSocket) -> Result { match from_slice::(&data) { Ok(v) => Ok(RpcResponse { method: v.method, params: RpcResult::Account(account_login(v.params, tx)?) }), Err(_e) => Err(err_msg("invalid params")), } } fn account_demo(_data: Vec, tx: &mut Transaction, _client: &mut WebSocket) -> Result { let mut rng = thread_rng(); let acc_name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); let account = account_create(AccountCreateParams { name: acc_name, password: "grepgrepgrep".to_string() }, tx)?; let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let res = RpcResponse { method: "account_create".to_string(), params: RpcResult::Account(account), }; return Ok(res); } fn account_cryps(_data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { Ok(RpcResponse { method: "account_cryps".to_string(), params: RpcResult::CrypList(account_cryps(tx, &account)?) }) } fn account_instances(_data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { Ok(RpcResponse { method: "account_instances".to_string(), params: RpcResult::InstanceList(account_instances(tx, &account)?) }) } fn instance_new(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(instance_new(msg.params, tx, &account)?) }; return Ok(response); } fn instance_ready(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(instance_ready(msg.params, tx, &account)?) }; return Ok(response); } fn instance_join(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(instance_join(msg.params, tx, &account)?) }; return Ok(response); } // fn instance_ready(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; // let response = RpcResponse { // method: "game_state".to_string(), // params: RpcResult::GameState(instance_ready(msg.params, tx, &account)?) // }; // return Ok(response); // } fn instance_state(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; match instance_state(msg.params, tx, &account)? { RpcResult::GameState(p) => Ok(RpcResponse { method: "game_state".to_string(), params: RpcResult::GameState(p), }), RpcResult::InstanceState(p) => Ok(RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(p), }), _ => Err(err_msg("unhandled instance state")) } } fn player_mm_cryps_set(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(player_mm_cryps_set(msg.params, tx, &account)?) }; return Ok(response); } fn player_vbox_accept(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(vbox_accept(msg.params, tx, &account)?) }; return Ok(response); } fn player_vbox_discard(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(vbox_discard(msg.params, tx, &account)?) }; return Ok(response); } fn player_vbox_combine(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(vbox_combine(msg.params, tx, &account)?) }; return Ok(response); } fn player_vbox_apply(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(vbox_apply(msg.params, tx, &account)?) }; Rpc::send_msg(client, RpcResponse { method: "account_cryps".to_string(), params: RpcResult::CrypList(account_cryps(tx, &account)?) })?; return Ok(response); } fn player_vbox_reclaim(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(vbox_reclaim(msg.params, tx, &account)?) }; return Ok(response); } fn player_vbox_unequip(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { method: "instance_state".to_string(), params: RpcResult::InstanceState(vbox_unequip(msg.params, tx, &account)?) }; Rpc::send_msg(client, RpcResponse { method: "account_cryps".to_string(), params: RpcResult::CrypList(account_cryps(tx, &account)?) })?; return Ok(response); } } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct RpcResponse { method: String, params: RpcResult, } #[derive(Debug,Clone,Serialize,Deserialize)] pub enum RpcResult { CrypSpawn(Cryp), CrypForget(Cryp), CrypLearn(Cryp), CrypUnspec(Cryp), Account(Account), CrypList(Vec), GameState(Game), InstanceScores(Vec<(String, Score)>), // ZoneState(Zone), // ZoneClose(()), InstanceList(Vec), InstanceState(Instance), } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct RpcMessage { method: String, token: Option, } #[derive(Debug,Clone,Serialize,Deserialize)] struct CrypSpawnMsg { method: String, params: CrypSpawnParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct CrypSpawnParams { pub name: String, } #[derive(Debug,Clone,Serialize,Deserialize)] struct CrypLearnMsg { method: String, params: CrypLearnParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct CrypLearnParams { pub id: Uuid, pub skill: Skill, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct CrypForgetParams { pub id: Uuid, pub skill: Skill, } #[derive(Debug,Clone,Serialize,Deserialize)] struct CrypForgetMsg { method: String, params: CrypForgetParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct CrypUnspecParams { pub id: Uuid, pub spec: Spec, } #[derive(Debug,Clone,Serialize,Deserialize)] struct CrypUnspecMsg { method: String, params: CrypUnspecParams, } #[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 GamePveMsg { // method: String, // params: GamePveParams, // } // #[derive(Debug,Clone,Serialize,Deserialize)] // pub struct GamePveParams { // pub cryp_ids: Vec, // } #[derive(Debug,Clone,Serialize,Deserialize)] struct GameSkillMsg { method: String, params: GameSkillParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct GameSkillParams { pub game_id: Uuid, pub cryp_id: Uuid, pub target_cryp_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, } #[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 AccountCrypsMsg { method: String, params: (), } #[derive(Debug,Clone,Serialize,Deserialize)] struct InstanceLobbyMsg { method: String, params: InstanceLobbyParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct InstanceLobbyParams { pub cryp_ids: Vec, pub name: String, pub players: usize, 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 cryp_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 PlayerCrypsSetMsg { method: String, params: PlayerCrypsSetParams, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct PlayerCrypsSetParams { pub cryp_ids: Vec, } #[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 cryp_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 cryp_id: Uuid, pub target: Var, } #[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, } // #[cfg(test)] // mod tests { // use super::*; // use serde_cbor::to_vec; // #[test] // fn rpc_parse() { // let rpc = Rpc {}; // let msg = GenerateMsg { method: "cryp_generate".to_string(), params: GenerateParams { level: 64 } }; // let v = to_vec(&msg).unwrap(); // let received = rpc.receive(Message::Binary(v)); // } // }