mnml/server/src/rpc.rs
2019-06-29 14:42:34 +10:00

469 lines
15 KiB
Rust

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<MnmlSocket>;
pub fn receive(data: Vec<u8>, db: &Db, _client: &mut MnmlWs, begin: Instant, account: Option<&Account>) -> Result<RpcResult, Error> {
// cast the msg to this type to receive method name
match from_slice::<RpcMessage>(&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<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<GameStateMsg>(&data).or(Err(err_msg("invalid params")))?;
return Ok(RpcResult::GameState(game_state(msg.params, tx, &account)?));
}
// fn handle_game_pve(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, 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 handle_game_skill(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<GameSkillMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::GameState(game_skill(msg.params, tx, &account)?))
}
fn handle_game_ready(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<GameStateMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::GameState(game_ready(msg.params, tx, &account)?))
}
fn handle_construct_spawn(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<ConstructSpawnMsg>(&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<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<ConstructDeleteMsg>(&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<u8>, tx: &mut Transaction) -> Result<RpcResult, Error> {
// let msg = from_slice::<AccountCreateMsg>(&data).or(Err(err_msg("invalid params")))?;
// let account = account_create(msg.params, tx)?;
// Ok(RpcResult::Account(account))
// }
// fn handle_account_login(data: Vec<u8>, tx: &mut Transaction) -> Result<RpcResult, Error> {
// let msg = from_slice::<AccountLoginMsg>(&data).or(Err(err_msg("invalid params")))?;
// Ok(RpcResult::Account(account_login(msg.params, tx)?))
// }
fn handle_account_constructs(_data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?))
}
fn handle_account_instances(_data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
Ok(RpcResult::AccountInstances(account_instances(tx, &account)?))
}
fn handle_instance_new(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceLobbyMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(instance_new(msg.params, tx, &account)?))
}
fn handle_instance_ready(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(instance_ready(msg.params, tx, &account)?))
}
fn handle_instance_join(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceJoinMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(instance_join(msg.params, tx, &account)?))
}
fn handle_instance_list(_data: Vec<u8>, tx: &mut Transaction, _account: &Account) -> Result<RpcResult, Error> {
Ok(RpcResult::OpenInstances(instance_list(tx)?))
}
fn handle_instance_state(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceStateMsg>(&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<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxAcceptMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_accept(msg.params, tx, &account)?))
}
fn handle_vbox_discard(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxDiscardMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_discard(msg.params, tx, &account)?))
}
fn handle_vbox_combine(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxCombineMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_combine(msg.params, tx, &account)?))
}
fn handle_vbox_apply(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxApplyMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_apply(msg.params, tx, &account)?))
}
fn handle_vbox_reclaim(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxReclaimMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_reclaim(msg.params, tx, &account)?))
}
fn handle_vbox_unequip(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxUnequipMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_unequip(msg.params, tx, &account)?))
}
fn handle_dev_resolve(data: Vec<u8>) -> Result<RpcResult, Error> {
let msg = from_slice::<DevResolveMsg>(&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<Construct>),
AccountInstances(Vec<Instance>),
GameState(Game),
ItemInfo(ItemInfoCtr),
OpenInstances(Vec<Instance>),
InstanceState(Instance),
Pong(()),
DevResolutions(Resolutions),
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct RpcMessage {
method: String,
token: Option<String>,
}
#[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<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,
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<Uuid>,
pub name: String,
pub pve: bool,
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 construct_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 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 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));
// }
// }