diff --git a/.gitignore b/.gitignore index ea8c4bf..9de102b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/*/target diff --git a/server/Cargo.lock b/server/Cargo.lock new file mode 100644 index 0000000..68eebab --- /dev/null +++ b/server/Cargo.lock @@ -0,0 +1,100 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "binrw" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b" +dependencies = [ + "array-init", + "binrw_derive", + "bytemuck", +] + +[[package]] +name = "binrw_derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "polariton" +version = "0.1.0" +dependencies = [ + "binrw", +] + +[[package]] +name = "polariton_server" +version = "0.1.0" +dependencies = [ + "polariton", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..3c6ba83 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "polariton_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +polariton = { version = "0.1.0", path = "../" } diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 0000000..6bb043e --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,2 @@ +pub mod events; +pub mod operations; diff --git a/server/src/operations/ack.rs b/server/src/operations/ack.rs new file mode 100644 index 0000000..c678306 --- /dev/null +++ b/server/src/operations/ack.rs @@ -0,0 +1,24 @@ +#[derive(Default)] +pub struct Ack { + _user_ty: std::marker::PhantomData, +} + +impl super::Operation for Ack { + type State = (); + type User = U; + + fn handle(&self, _: polariton::operation::ParameterTable, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse { + polariton::operation::OperationResponse { + code: CODE, + return_code: 0, + message: polariton::operation::Typed::Null, + params: std::collections::HashMap::default().into(), + } + } +} + +impl super::OperationCode for Ack { + fn op_code() -> u8 { + CODE + } +} diff --git a/server/src/operations/functional.rs b/server/src/operations/functional.rs new file mode 100644 index 0000000..ee3e94d --- /dev/null +++ b/server/src/operations/functional.rs @@ -0,0 +1,79 @@ +use polariton::operation::{ParameterTable, OperationResponse}; + +pub struct Func OperationResponse) + Send + Sync> { + _state_ty: std::marker::PhantomData, + _user_ty: std::marker::PhantomData, + func: F, +} + +impl OperationResponse) + Send + Sync> Func { + pub fn new(f: F) -> Self { + Self { + _state_ty: std::marker::PhantomData::default(), + _user_ty: std::marker::PhantomData::default(), + func: f, + } + } +} + +impl OperationResponse) + Send + Sync> super::Operation for Func { + type State = S; + type User = U; + + fn handle(&self, p: polariton::operation::ParameterTable, s: &mut Self::State, u: &Self::User) -> OperationResponse { + (self.func)(p, s, u) + } +} + +impl OperationResponse) + Send + Sync> super::OperationCode for Func { + fn op_code() -> u8 { + CODE + } +} + +pub struct SimpleFunc Result) + Send + Sync> { + _user_ty: std::marker::PhantomData, + func: F, +} + +impl Result) + Send + Sync> SimpleFunc { + pub fn new(f: F) -> Self { + Self { + _user_ty: std::marker::PhantomData::default(), + func: f, + } + } +} + +impl Result) + Send + Sync> super::Operation for SimpleFunc { + type State = (); + type User = U; + + fn handle(&self, p: polariton::operation::ParameterTable, _: &mut Self::State, u: &Self::User) -> OperationResponse { + match (self.func)(p, u) { + Ok(p_out) => { + OperationResponse { + code: CODE, + return_code: 0, + message: polariton::operation::Typed::Null, + params: p_out, + } + }, + Err(e_code) => { + OperationResponse { + code: CODE, + return_code: e_code, + message: polariton::operation::Typed::Null, + params: std::collections::HashMap::new().into(), + } + } + } + + } +} + +impl Result) + Send + Sync> super::OperationCode for SimpleFunc { + fn op_code() -> u8 { + CODE + } +} diff --git a/server/src/operations/handler.rs b/server/src/operations/handler.rs new file mode 100644 index 0000000..2d4493a --- /dev/null +++ b/server/src/operations/handler.rs @@ -0,0 +1,92 @@ +use std::collections::HashMap; +use std::sync::Mutex; + +use polariton::operation::{OperationResponse, ParameterTable, OperationRequest}; + +use super::{Operation, OperationCode}; + +trait WrappedOperation: Send + Sync { + fn handle(&self, params: ParameterTable, user: &U) -> OperationResponse; +} + +struct SyncedOpWrapper> { + state: Mutex, + handler: O, +} + + +impl > WrappedOperation for SyncedOpWrapper { + fn handle(&self, params: ParameterTable, user: &U) -> OperationResponse { + self.handler.handle(params, &mut *self.state.lock().unwrap(), user) + } +} + +struct StatelessOpWrapper> { + handler: O, +} + + +impl > WrappedOperation for StatelessOpWrapper { + fn handle(&self, params: ParameterTable, user: &U) -> OperationResponse { + self.handler.handle(params, &mut (), user) + } +} + +pub struct OperationsHandler { + op_map: HashMap>>, +} + +impl OperationsHandler { + const SERVICE_MAPPING_KEY: u8 = 0; + + pub fn new() -> Self { + Self { + op_map: Default::default(), + } + } + + pub fn with_state + OperationCode + 'static>(mut self, op: O, state: S) -> Self { + self.op_map.insert(O::op_code(), Box::new(SyncedOpWrapper { + state: Mutex::new(state), + handler: op, + })); + self + } + + pub fn without_state + OperationCode + 'static>(mut self, op: O) -> Self { + self.op_map.insert(O::op_code(), Box::new(StatelessOpWrapper { + handler: op, + })); + self + } + + fn try_pass_to_handler(&self, code: u8, params: ParameterTable, user:&U) -> OperationResponse { + if let Some(handler) = self.op_map.get(&code) { + handler.handle(params, user) + } else { + #[cfg(debug_assertions)] + panic!("No handler for op code {}, pls fix!! params: {:?}", code, params.clone().to_dict()); + #[cfg(not(debug_assertions))] + { + log::debug!("No handler for op code {}, echoing params {:?}", code, params.clone().to_dict()); + OperationResponse { + code, + return_code: 0, + message: polariton::operation::Typed::Null, + params, + } + } + } + } + + pub fn handle_op(&self, user: &U, req: OperationRequest) -> OperationResponse { + let mut op_resp = self.try_pass_to_handler(req.code, req.params.clone(), user); + if let Some(svelto_service_id) = req.params.clone().to_dict().remove(&Self::SERVICE_MAPPING_KEY) { + // make sure to do GUID passthrough + let mut dict_params = op_resp.params.to_dict(); + dict_params.insert(Self::SERVICE_MAPPING_KEY, svelto_service_id); + op_resp.params = dict_params.into(); + } + op_resp + } +} diff --git a/server/src/operations/mod.rs b/server/src/operations/mod.rs new file mode 100644 index 0000000..83c768f --- /dev/null +++ b/server/src/operations/mod.rs @@ -0,0 +1,11 @@ +mod handler; +pub use handler::OperationsHandler; + +mod traits; +pub use traits::{Operation, OperationCode}; + +mod ack; +pub use ack::Ack; + +mod functional; +pub use functional::{Func, SimpleFunc}; diff --git a/server/src/operations/traits.rs b/server/src/operations/traits.rs new file mode 100644 index 0000000..73689f9 --- /dev/null +++ b/server/src/operations/traits.rs @@ -0,0 +1,12 @@ +use polariton::operation::{OperationResponse, ParameterTable}; + +pub trait Operation: Send + Sync { + type State; + type User; + + fn handle(&self, params: ParameterTable, state: &mut Self::State, user: &Self::User) -> OperationResponse; +} + +pub trait OperationCode { + fn op_code() -> u8; +}