mnml/server/src/rpc.rs
2019-04-25 19:34:53 +10:00

665 lines
22 KiB
Rust

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, instance_scores};
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<TcpStream>) -> Result<RpcResponse, Error> {
// consume the ws data into bytes
let data = msg.into_data();
// cast the msg to this type to receive method name
match from_slice::<RpcMessage>(&data) {
Ok(v) => {
let mut tx = db.transaction()?;
let account: Option<Account> = 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_scores" => Rpc::instance_scores(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<TcpStream>, 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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<GameStateMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
// let msg = from_slice::<GamePveMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<GameSkillMsg>(&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<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<CrypSpawnMsg>(&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<u8>, tx: &mut Transaction, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<AccountCreateMsg>(&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<u8>, tx: &mut Transaction, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
match from_slice::<AccountLoginMsg>(&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<u8>, tx: &mut Transaction, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
Ok(RpcResponse {
method: "account_cryps".to_string(),
params: RpcResult::CrypList(account_cryps(tx, &account)?)
})
}
fn account_instances(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
Ok(RpcResponse {
method: "account_instances".to_string(),
params: RpcResult::InstanceList(account_instances(tx, &account)?)
})
}
fn instance_new(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceLobbyMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceReadyMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceJoinMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
// let msg = from_slice::<InstanceReadyMsg>(&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_scores(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "instance_scores".to_string(),
params: RpcResult::InstanceScores(instance_scores(msg.params, tx, &account)?)
};
return Ok(response);
}
fn instance_state(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceStateMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<PlayerCrypsSetMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxAcceptMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxDiscardMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxCombineMsg>(&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<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxApplyMsg>(&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<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxReclaimMsg>(&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<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxUnequipMsg>(&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<Cryp>),
GameState(Game),
InstanceScores(Vec<(String, Score)>),
// ZoneState(Zone),
// ZoneClose(()),
InstanceList(Vec<Instance>),
InstanceState(Instance),
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct RpcMessage {
method: String,
token: Option<String>,
}
#[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<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 cryp_id: Uuid,
pub target_cryp_id: Option<Uuid>,
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<Uuid>,
pub name: String,
pub players: usize,
pub password: Option<String>,
}
#[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<Uuid>,
}
#[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<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<usize>,
}
#[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));
// }
// }