From 2e7f1ee492be200fe2fe1b6204d471adec1d656b Mon Sep 17 00:00:00 2001 From: Max Audron Date: Sun, 3 Oct 2021 12:39:06 +0200 Subject: split StatefulSyncable into client and server side traits This allows to more easily put each side behind a feature flag, maintaing ease of use when only one is selected, while still allowing a consumer to enable both sides and use them. --- src/message/signalproxy/mod.rs | 92 +++++++++++++++++-------- src/message/signalproxy/objects/aliasmanager.rs | 43 +++++++----- src/message/signalproxy/translation/mod.rs | 11 ++- src/session/mod.rs | 44 ++++++++---- 4 files changed, 133 insertions(+), 57 deletions(-) diff --git a/src/message/signalproxy/mod.rs b/src/message/signalproxy/mod.rs index d5cdd80..b1e235a 100644 --- a/src/message/signalproxy/mod.rs +++ b/src/message/signalproxy/mod.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use crate::{ deserialize::Deserialize, primitive::{Variant, VariantList}, @@ -50,54 +52,90 @@ pub trait Syncable { /// } /// } /// ``` - fn sync(&self, session: impl SyncProxy, function: &str, params: VariantList); + fn send_sync(&self, session: impl SyncProxy, function: &str, params: VariantList); /// Send a RpcCall - fn rpc(&self, session: impl SyncProxy, function: &str, params: VariantList) { + fn send_rpc(&self, session: impl SyncProxy, function: &str, params: VariantList) { session.rpc(function, params); } } -/// A Stateful Syncable Object -#[allow(unused_variables)] -pub trait StatefulSyncable: Syncable + translation::NetworkMap -// where -// ::Item: ToString, +/// Methods for a Stateful Syncable object on the client side. +pub trait StatefulSyncableServer: Syncable + translation::NetworkMap where Variant: From<::Item>, { - /// Client -> Server: Update the whole object with received data - fn update(&mut self, session: impl SyncProxy, param: ::Item) + fn sync(&mut self, session: impl SyncProxy, mut msg: crate::message::SyncMessage) where Self: Sized, { - #[cfg(feature = "client")] - { - self.sync(session, "update", vec![self.to_network_map().into()]); + match msg.slot_name.as_str() { + "requestUpdate" => self.request_update(msg.params.pop().unwrap().try_into().unwrap()), + _ => self.sync_custom(session, msg), } - #[cfg(feature = "server")] - { - *self = Self::from_network_map(&mut param); + } + + #[allow(unused_mut, unused_variables)] + fn sync_custom(&mut self, session: impl SyncProxy, mut msg: crate::message::SyncMessage) + where + Self: Sized, + { + match msg.slot_name.as_str() { + _ => (), } } + /// Client -> Server: Update the whole object with received data + fn update(&mut self, session: impl SyncProxy) + where + Self: Sized, + { + self.send_sync(session, "update", vec![self.to_network_map().into()]); + } + /// Server -> Client: Update the whole object with received data - fn request_update( - &mut self, - session: impl SyncProxy, - mut param: ::Item, - ) where + fn request_update(&mut self, mut param: ::Item) + where Self: Sized, { - #[cfg(feature = "client")] - { - *self = Self::from_network_map(&mut param); - } - #[cfg(feature = "server")] - { - self.sync(session, "requestUpdate", vec![self.to_network_map().into()]); + *self = Self::from_network_map(&mut param); + } +} + +/// Methods for a Stateful Syncable object on the server side. +pub trait StatefulSyncableClient: Syncable + translation::NetworkMap { + fn sync(&mut self, session: impl SyncProxy, mut msg: crate::message::SyncMessage) + where + Self: Sized, + { + match msg.slot_name.as_str() { + "update" => self.update(msg.params.pop().unwrap().try_into().unwrap()), + _ => self.sync_custom(session, msg), } } + + fn sync_custom(&mut self, _session: impl SyncProxy, _msg: crate::message::SyncMessage) + where + Self: Sized, + { + () + } + + /// Client -> Server: Update the whole object with received data + fn update(&mut self, mut param: ::Item) + where + Self: Sized, + { + *self = Self::from_network_map(&mut param); + } + + /// Server -> Client: Update the whole object with received data + fn request_update(&mut self, session: impl SyncProxy) + where + Self: Sized, + { + self.send_sync(session, "requestUpdate", vec![self.to_network_map().into()]); + } } #[derive(Clone, Debug, std::cmp::PartialEq)] diff --git a/src/message/signalproxy/objects/aliasmanager.rs b/src/message/signalproxy/objects/aliasmanager.rs index d696aae..61a68ce 100644 --- a/src/message/signalproxy/objects/aliasmanager.rs +++ b/src/message/signalproxy/objects/aliasmanager.rs @@ -1,10 +1,16 @@ -use std::convert::TryInto; +use std::convert::TryFrom; use libquassel_derive::{NetworkList, NetworkMap}; -use crate::message::{StatefulSyncable, SyncProxy, Syncable}; +#[allow(unused_imports)] +use crate::message::StatefulSyncableClient; +#[allow(unused_imports)] +use crate::message::StatefulSyncableServer; + +use crate::message::{SyncProxy, Syncable}; use crate::message::signalproxy::translation::NetworkMap; +use crate::primitive::VariantMap; /// AliasManager /// keeps a list of all registered aliases @@ -22,28 +28,33 @@ impl AliasManager { self.aliases.push(alias) } } +} - pub fn handle_syncmessage( - &mut self, - session: impl SyncProxy, - msg: crate::message::SyncMessage, - ) { +#[cfg(feature = "client")] +impl StatefulSyncableClient for AliasManager {} + +#[cfg(feature = "server")] +impl StatefulSyncableServer for AliasManager { + fn sync_custom(&mut self, _session: impl SyncProxy, mut msg: crate::message::SyncMessage) + where + Self: Sized, + { match msg.slot_name.as_str() { - "requestUpdate" => { - self.request_update(session, msg.params.get(0).unwrap().try_into().unwrap()) - } - "update" => { - *self = - AliasManager::from_network_map(&mut msg.params[0].clone().try_into().unwrap()) - } + "addAlias" => self.add_alias(Alias::from_network_map( + &mut VariantMap::try_from(msg.params.pop().unwrap()).unwrap(), + )), _ => (), } } } -impl StatefulSyncable for AliasManager {} impl Syncable for AliasManager { - fn sync(&self, session: impl SyncProxy, function: &str, params: crate::primitive::VariantList) { + fn send_sync( + &self, + session: impl SyncProxy, + function: &str, + params: crate::primitive::VariantList, + ) { session.sync("AliasManager", None, function, params) } } diff --git a/src/message/signalproxy/translation/mod.rs b/src/message/signalproxy/translation/mod.rs index f6bbbb9..a6e26b4 100644 --- a/src/message/signalproxy/translation/mod.rs +++ b/src/message/signalproxy/translation/mod.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + /** Quassel has 3 main ways to represent an object over the Network: @@ -84,7 +86,7 @@ VariantMap({ }) ``` **/ -use crate::primitive::VariantList; +use crate::primitive::{Variant, VariantList}; pub trait Network { type Item; @@ -93,7 +95,12 @@ pub trait Network { fn from_network(input: &mut Self::Item) -> Self; } -pub trait NetworkMap { +pub trait NetworkMap +where + // TODO correct this error type + Self::Item: TryFrom, + Self::Item: Into, +{ type Item; fn to_network_map(&self) -> Self::Item; diff --git a/src/session/mod.rs b/src/session/mod.rs index 7fa5c29..07dc527 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -1,25 +1,25 @@ -use crate::message::{objects::AliasManager, SyncMessage, SyncProxy}; +use crate::message::{objects::AliasManager, StatefulSyncableClient, SyncMessage, SyncProxy}; /// The Session Trait is the main point of entry and implements the basic logic pub trait Session: SyncProxy { - fn alias_manager(&self) -> AliasManager; + fn alias_manager(&mut self) -> &mut AliasManager; - fn handle_syncmessage(&self, msg: SyncMessage) - where - Self: Sized, - { - match msg.class_name.as_str() { - "AliasManager" => self.alias_manager().handle_syncmessage(self, msg), - _ => (), - } - } + // fn sync(&mut self, msg: SyncMessage) + // where + // Self: Sized, + // { + // match msg.class_name.as_str() { + // "AliasManager" => self.alias_manager().sync(self, msg), + // _ => (), + // } + // } } impl Session for &T where T: Session, { - fn alias_manager(&self) -> AliasManager { + fn alias_manager(&mut self) -> &mut AliasManager { todo!() } } @@ -43,3 +43,23 @@ where todo!() } } + +#[allow(unused_variables)] +impl SyncProxy for &mut T +where + T: SyncProxy, +{ + fn sync( + &self, + class_name: &str, + object_name: Option<&str>, + function: &str, + params: crate::primitive::VariantList, + ) { + todo!() + } + + fn rpc(&self, function: &str, params: crate::primitive::VariantList) { + todo!() + } +} -- cgit v1.2.3