diff options
Diffstat (limited to '')
31 files changed, 1056 insertions, 888 deletions
diff --git a/src/bin/quassel-client.rs b/src/bin/quassel-client.rs deleted file mode 100644 index fa3fdf8..0000000 --- a/src/bin/quassel-client.rs +++ /dev/null @@ -1,97 +0,0 @@ -use failure::Error; - -extern crate libquassel; - -extern crate tokio; -extern crate pretty_env_logger; - -use libquassel::primitive::*; -use libquassel::message::*; -use libquassel::client::*; - -use tokio::io::{AsyncRead, AsyncWrite}; -use core::marker::Unpin; -use futures::SinkExt; -use std::future::Future; - -use log::*; - -#[tokio::main] -async fn main() -> Result<(), Error> { - pretty_env_logger::init(); - -// let mut client = client::Client::<tokio::net::TcpStream>::connect( -// "cocaine.farm", -// 4242, -// true, -// ).await.unwrap(); - - let username = std::env::args().nth(1).expect("no username given"); - let password = std::env::args().nth(2).expect("no password given"); - - let funcs = Funcs { - init: InitFuncs { - client_init_ack, - client_init_reject, - client_login_ack, - client_login_reject, - session_init - }, - message: MessageFuncs { - sync_message, - rpc_call, - init_request, - init_data, - heart_beat, - heart_beat_reply - } - }; - - let mut client = Client::<tokio_tls::TlsStream<tokio::net::TcpStream>>::connect_tls( - "cocaine.farm", - 4242, - true, - User { - name: username, - password, - }, - //funcs, - ).await.unwrap(); - - client.run().await; - - Ok(()) -} - -async fn client_init_ack<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: &mut Client<T, F>, item: VariantMap) { - use libquassel::{HandshakeSerialize, HandshakeDeserialize}; - - info!(target: "init", "Initialization successfull"); - info!(target: "login", "Starting Login"); - let login = ClientLogin {user: client.user.name.clone(), password: client.user.password.clone()}; - client.stream.send(login.serialize().unwrap()).await.unwrap(); -} - -async fn client_init_reject<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: VariantMap) { - error!(target: "init", "Initialization failed: {:?}", item); -} - -async fn client_login_ack<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: VariantMap) { - info!(target: "login", "Login successfull"); -} - -async fn client_login_reject<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: VariantMap) { - error!(target: "login", "Login failed: {:?}", item); -} - -async fn session_init<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: &mut Client<T, F>, item: VariantMap) { - info!(target: "login", "Session Initialization finished. Switching to Connected state"); - client.state = ClientState::Connected; -} - -async fn sync_message<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: SyncMessage) { unimplemented!() } -async fn rpc_call<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: RpcCall) { unimplemented!() } -async fn init_request<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: InitRequest) { unimplemented!() } -async fn init_data<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: InitData) { unimplemented!() } -async fn heart_beat<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: HeartBeat) { unimplemented!() } -async fn heart_beat_reply<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: Client<T, F>, item: HeartBeatReply) { unimplemented!() } diff --git a/src/client/mod.rs b/src/client/mod.rs deleted file mode 100644 index cded8c9..0000000 --- a/src/client/mod.rs +++ /dev/null @@ -1,291 +0,0 @@ -//use std::io::BufWriter; -use std::result::Result; -use std::vec::Vec; - -use tokio::io::{AsyncRead, AsyncWrite}; -use core::marker::Unpin; -use tokio::net::TcpStream; -use tokio::prelude::*; - -use native_tls::TlsConnector; - -use tokio_tls; -use tokio_tls::TlsStream; -use tokio_util::codec::Framed; -use futures_util::stream::StreamExt; -use futures::SinkExt; -use std::future::Future; - -use crate::frame::QuasselCodec; - -use failure::Error; - -use log::{trace, debug, info, error}; - -use crate::message::*; -use crate::primitive::*; - -extern crate log; - -pub struct Client<T, F> -where - F: Future, - T: 'static + AsyncRead + AsyncWrite + Unpin, -{ - pub stream: Framed<T, QuasselCodec>, - pub tls: bool, - pub compression: bool, - pub state: ClientState, - pub user: User, - pub funcs: Funcs<T, F>, -} - -pub struct User { - pub name: String, - pub password: String, -} - -pub enum ClientState { - Handshake, - Connected, -} - -impl <T: AsyncRead + AsyncWrite + Unpin, F: Future> Client<T, F> { - pub async fn run(&mut self) { - use crate::primitive::StringList; - use crate::message::ClientInit; - use crate::HandshakeSerialize; - - info!(target: "init", "Setting Features"); - - let mut features = StringList::new(); - features.push("SynchronizedMarkerLine".to_string()); - features.push("Authenticators".to_string()); - features.push("ExtendedFeatures".to_string()); - features.push("BufferActivitySync".to_string()); - let client_init = ClientInit { - client_version:String::from("Rust 0.0.0"), - client_date: String::from("1579009211"), - feature_list: features, - client_features: 0x00008000, - }; - - self.stream.send(client_init.serialize().unwrap()).await.unwrap(); - - // Start event loop - while let Some(msg) = self.stream.next().await { - let msg = msg.unwrap(); - match self.state { - ClientState::Handshake => handle_login_message(self, &msg).await.unwrap(), - ClientState::Connected => handle_message(self, &msg).await.unwrap(), - } - }; - } - - pub async fn connect( - address: &'static str, - port: u64, - compression: bool, - user: User, - funcs: Funcs<TcpStream, impl Future> - ) -> Result<Client<TcpStream, impl Future>, Error> { - let mut stream = TcpStream::connect(format!("{}:{}", address, port)).await?; - - info!(target: "init", "Establishing Connection"); - let connack = init(&mut stream, false, compression).await?; - - debug!(target: "init", "{:?}", connack); - - let codec = QuasselCodec::builder() - .compression(compression) - .new_codec(); - - let framed_stream = Framed::new(stream, codec); - - info!(target: "init", "Established Connection"); - - return Ok(Client { - stream: framed_stream, - tls: false, - compression, - state: ClientState::Handshake, - user, - funcs, - }); - } - - pub async fn connect_tls( - address: &'static str, - port: u64, - compression: bool, - user: User, - funcs: Funcs<TlsStream<TcpStream>, impl Future> - ) -> Result<Client<TlsStream<TcpStream>, impl Future>, Error> { - let mut stream: TcpStream = TcpStream::connect(format!("{}:{}", address, port)).await?; - - info!(target: "init", "Establishing Connection"); - let connack = init(&mut stream, true, compression).await?; - - debug!(target: "init", "{:?}", connack); - - let codec = QuasselCodec::builder() - .compression(compression) - .new_codec(); - - let tls_connector = tokio_tls::TlsConnector::from(TlsConnector::builder().build().unwrap()); - - let tls_stream = tls_connector.connect(address, stream).await?; - - let framed_stream = Framed::new(tls_stream, codec); - - info!(target: "init", "Established Connection"); - - return Ok(Client { - stream: framed_stream, - tls: true, - compression, - state: ClientState::Handshake, - user, - funcs, - }); - } - -} - -pub async fn handle_login_message<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: &mut Client<T, F>, buf: &[u8]) -> Result<(), Error> { - use crate::{HandshakeSerialize, HandshakeDeserialize}; - use crate::message::ClientLogin; - use crate::primitive::{VariantMap, Variant}; - - trace!(target: "message", "Received bytes: {:x?}", buf); - let (_, res) = VariantMap::parse(buf)?; - debug!(target: "init", "Received Messsage: {:#?}", res); - - let msgtype = match_variant!(&res["MsgType"], Variant::String); - match msgtype.as_str() { - "ClientInitAck" => { - info!(target: "init", "Initialization successfull"); - info!(target: "login", "Starting Login"); - let login = ClientLogin {user: client.user.name.clone(), password: client.user.password.clone()}; - client.stream.send(login.serialize()?).await?; - }, - "ClientInitReject" => { - error!(target: "init", "Initialization failed: {:?}", res); - }, - "ClientLoginAck" => { - info!(target: "login", "Login successfull"); - }, - "SessionInit" => { - info!(target: "login", "Session Initialization finished. Switching to Connected state"); - client.state = ClientState::Connected; - } - "ClientLoginReject" => { - error!(target: "login", "Login failed: {:?}", res); - }, - _ => { - error!(target: "client", "Error: WrongMsgType: {:#?}", res); - } - } - - return Ok(()); -} - -pub async fn handle_message<T: AsyncRead + AsyncWrite + Unpin, F: Future>(client: &mut Client<T, F>, buf: &[u8]) -> Result<(), Error> { - use crate::message::Message; - use crate::primitive::VariantList; - use crate::Deserialize; - use crate::Serialize; - - trace!(target: "message", "Received bytes: {:x?}", buf); - let (_, res) = Message::parse(buf)?; - debug!(target: "init", "Received Messsage: {:#?}", res); - - match res { - Message::SyncMessage(_) => {} - Message::RpcCall(_) => {} - Message::InitRequest(_) => {} - Message::InitData(_) => {} - Message::HeartBeat(_) => {} - Message::HeartBeatReply(_) => {} - } - - return Ok(()); -} - -pub struct Funcs<T, F> -where - T: 'static + AsyncRead + AsyncWrite + Unpin, - F: std::future::Future, -{ - pub init: InitFuncs<T, F>, - pub message: MessageFuncs<T, F>, -} - -pub struct InitFuncs<T, F> -where - T: 'static + AsyncRead + AsyncWrite + Unpin, - F: std::future::Future, -{ - pub client_init_ack: fn(&mut Client<T, F>, VariantMap) -> F, - pub client_init_reject: fn(Client<T, F>, VariantMap) -> F, - pub client_login_ack: fn(Client<T, F>, VariantMap) -> F, - pub client_login_reject: fn(Client<T, F>, VariantMap) -> F, - pub session_init: fn(&mut Client<T, F>, VariantMap) -> F, -} - -pub struct MessageFuncs<T, F> -where - T: 'static + AsyncRead + AsyncWrite + Unpin, - F: std::future::Future, -{ - pub sync_message: fn(Client<T, F>, SyncMessage) -> F, - pub rpc_call: fn(Client<T, F>, RpcCall) -> F, - pub init_request: fn(Client<T, F>, InitRequest) -> F, - pub init_data: fn(Client<T, F>, InitData) -> F, - pub heart_beat: fn(Client<T, F>, HeartBeat) -> F, - pub heart_beat_reply: fn(Client<T, F>, HeartBeatReply) -> F, -} - -// Send the initialization message to the stream -pub async fn init(stream: &mut TcpStream, tls: bool, compression: bool) -> Result<ConnAck, Error> { - use crate::Deserialize; - - // Buffer for our initialization - let mut init: Vec<u8> = vec![]; - - // The handshake message - let mut handshake: u32 = 0x42b33f00; - - // If TLS is enabled set the TLS bit on the handshake - if tls { - info!(target: "init", "Enabled TLS"); - handshake |= 0x01; - } - - // If COMPRESSION is enabled set the COMPRESSION bit on the handshake - if compression { - info!(target: "init", "Enabled Compression"); - handshake |= 0x02; - } - - // Select Protocol 2: Datastream - let mut proto: u32 = 0x00000002; - - // Flag proto as the last protocol - let fin: u32 = 0x80000000; - proto |= fin; - - // Add handshake and protocol to our buffer - init.extend(handshake.to_be_bytes().iter()); - init.extend(proto.to_be_bytes().iter()); - - // Send Buffer - stream.write(&init).await?; - - // Read Response - let mut buf = [0; 4]; - stream.read(&mut buf).await?; - - let (_, connack) = ConnAck::parse(&buf)?; - Ok(connack) -} diff --git a/src/frame/mod.rs b/src/frame/mod.rs index 709d3af..cbeddb0 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -195,8 +195,7 @@ impl Decoder for QuasselCodec { } } -impl Encoder for QuasselCodec { - type Item = Vec<u8>; +impl Encoder<Vec<u8>> for QuasselCodec { type Error = io::Error; fn encode(&mut self, data: Vec<u8>, dst: &mut BytesMut) -> Result<(), io::Error> { @@ -1,23 +1,32 @@ +#![feature(external_doc)] +#![feature(doc_cfg)] +#![doc(include = "../README.md")] +#[cfg_attr(docsrs, feature(doc_cfg))] #[macro_use] mod util; -#[cfg(feature = "client")] -pub mod client; - #[cfg(test)] pub mod tests; #[macro_use] extern crate failure; +/// Quassel Structures for serialization and deserialization pub mod message; + +/// Quassels QT based primitive types that make up the more complex messages pub mod primitive; +pub mod session; + #[allow(dead_code)] +/// Error Types pub mod error; #[allow(unused_variables, dead_code)] #[cfg(feature = "framing")] +#[cfg_attr(docsrs, doc(cfg(feature = "framing")))] +/// Framing impl to be used with [`tokio_util::codec::Framed`] pub mod frame; use failure::Error; diff --git a/src/message/handshake/clientinit.rs b/src/message/handshake/clientinit.rs index 17ec9a1..d21d6aa 100644 --- a/src/message/handshake/clientinit.rs +++ b/src/message/handshake/clientinit.rs @@ -1,6 +1,5 @@ -use crate::error::ProtocolError; use crate::primitive::{StringList, Variant, VariantMap}; -use crate::{HandshakeDeserialize, HandshakeSerialize}; +use crate::HandshakeSerialize; use failure::Error; @@ -32,7 +31,7 @@ use failure::Error; /// | -- | EcdsaCertfpKeys | ECDSA keys for CertFP in identities | /// | -- | LongMessageId | 64-bit IDs for messages | /// | -- | SyncedCoreInfo | CoreInfo dynamically updated using signals | -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClientInit { /// Version of the client pub client_version: String, @@ -68,24 +67,13 @@ impl HandshakeSerialize for ClientInit { } } -impl HandshakeDeserialize for ClientInit { - fn parse(b: &[u8]) -> Result<(usize, Self), Error> { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - - let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8); - - if msgtype == "ClientInit" { - return Ok(( - len, - Self { - client_version: match_variant!(values["ClientVersion"], Variant::String), - client_date: match_variant!(values["ClientDate"], Variant::String), - feature_list: match_variant!(values["FeatureList"], Variant::StringList), - client_features: match_variant!(values["Features"], Variant::u32), - }, - )); - } else { - bail!(ProtocolError::WrongMsgType); +impl From<VariantMap> for ClientInit { + fn from(input: VariantMap) -> Self { + ClientInit { + client_version: match_variant!(input.get("ClientVersion").unwrap(), Variant::String), + client_date: match_variant!(input.get("ClientDate").unwrap(), Variant::String), + client_features: match_variant!(input.get("Features").unwrap(), Variant::u32), + feature_list: match_variant!(input.get("FeatureList").unwrap(), Variant::StringList), } } } diff --git a/src/message/handshake/clientinitack.rs b/src/message/handshake/clientinitack.rs index 637b989..f881113 100644 --- a/src/message/handshake/clientinitack.rs +++ b/src/message/handshake/clientinitack.rs @@ -1,11 +1,10 @@ -use crate::error::ProtocolError; -use crate::primitive::{StringList, Variant, VariantList, VariantMap}; -use crate::{HandshakeDeserialize, HandshakeSerialize}; +use crate::primitive::{Variant, VariantList, VariantMap}; +use crate::HandshakeSerialize; use failure::Error; /// ClientInitAck is received when the initialization was successfull -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClientInitAck { /// Flags of supported legacy features pub core_features: u32, @@ -16,7 +15,7 @@ pub struct ClientInitAck { /// List of VariantMaps of info on available authenticators pub authenticators: VariantList, /// List of supported extended features - pub feature_list: StringList, + pub feature_list: Vec<String>, } impl HandshakeSerialize for ClientInitAck { @@ -47,28 +46,21 @@ impl HandshakeSerialize for ClientInitAck { } } -impl HandshakeDeserialize for ClientInitAck { - fn parse(b: &[u8]) -> Result<(usize, Self), Error> { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - - let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8); - - if msgtype == "ClientInitAck" { - return Ok(( - len, - Self { - core_features: 0x00008000, - core_configured: match_variant!(values["Configured"], Variant::bool), - storage_backends: match_variant!( - values["StorageBackends"], - Variant::VariantList - ), - authenticators: match_variant!(values["Authenticators"], Variant::VariantList), - feature_list: match_variant!(values["FeatureList"], Variant::StringList), - }, - )); - } else { - bail!(ProtocolError::WrongMsgType); +impl From<VariantMap> for ClientInitAck { + fn from(input: VariantMap) -> Self { + ClientInitAck { + // TODO make this compatible with older clients + core_features: 0, + core_configured: match_variant!(input.get("Configured").unwrap(), Variant::bool), + storage_backends: match_variant!( + input.get("StorageBackends").unwrap(), + Variant::VariantList + ), + authenticators: match_variant!( + input.get("Authenticators").unwrap(), + Variant::VariantList + ), + feature_list: match_variant!(input.get("FeatureList").unwrap(), Variant::StringList), } } } diff --git a/src/message/handshake/clientinitreject.rs b/src/message/handshake/clientinitreject.rs index 06960b7..d93413d 100644 --- a/src/message/handshake/clientinitreject.rs +++ b/src/message/handshake/clientinitreject.rs @@ -1,14 +1,13 @@ -use crate::error::ProtocolError; use crate::primitive::{Variant, VariantMap}; -use crate::{HandshakeDeserialize, HandshakeSerialize}; +use crate::HandshakeSerialize; use failure::Error; /// ClientInitReject is received when the initialization fails -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClientInitReject { /// String with an error message of what went wrong - pub error_string: String, + pub error: String, } impl HandshakeSerialize for ClientInitReject { @@ -20,27 +19,16 @@ impl HandshakeSerialize for ClientInitReject { ); values.insert( "ErrorString".to_string(), - Variant::String(self.error_string.clone()), + Variant::String(self.error.clone()), ); return HandshakeSerialize::serialize(&values); } } -impl HandshakeDeserialize for ClientInitReject { - fn parse(b: &[u8]) -> Result<(usize, Self), Error> { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - - let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8); - - if msgtype == "ClientInitReject" { - return Ok(( - len, - Self { - error_string: match_variant!(values["ErrorString"], Variant::String), - }, - )); - } else { - bail!(ProtocolError::WrongMsgType); +impl From<VariantMap> for ClientInitReject { + fn from(input: VariantMap) -> Self { + ClientInitReject { + error: match_variant!(input.get("ErrorString").unwrap(), Variant::String), } } } diff --git a/src/message/handshake/clientlogin.rs b/src/message/handshake/clientlogin.rs index 769245b..dffd996 100644 --- a/src/message/handshake/clientlogin.rs +++ b/src/message/handshake/clientlogin.rs @@ -1,12 +1,11 @@ -use crate::error::ProtocolError; use crate::primitive::{Variant, VariantMap}; -use crate::{HandshakeDeserialize, HandshakeSerialize}; +use crate::HandshakeSerialize; use failure::Error; /// Login to the core with user data /// username and password are transmitted in plain text -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClientLogin { pub user: String, pub password: String, @@ -28,22 +27,11 @@ impl HandshakeSerialize for ClientLogin { } } -impl HandshakeDeserialize for ClientLogin { - fn parse(b: &[u8]) -> Result<(usize, Self), Error> { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - - let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8); - - if msgtype == "ClientLogin" { - return Ok(( - len, - Self { - user: match_variant!(values["User"], Variant::String), - password: match_variant!(values["Password"], Variant::String), - }, - )); - } else { - bail!(ProtocolError::WrongMsgType); +impl From<VariantMap> for ClientLogin { + fn from(input: VariantMap) -> Self { + ClientLogin { + user: match_variant!(input.get("User").unwrap(), Variant::String), + password: match_variant!(input.get("Password").unwrap(), Variant::String), } } } diff --git a/src/message/handshake/clientloginack.rs b/src/message/handshake/clientloginack.rs index 674d307..e385a81 100644 --- a/src/message/handshake/clientloginack.rs +++ b/src/message/handshake/clientloginack.rs @@ -6,7 +6,7 @@ use failure::Error; /// ClientLoginAck is received after the client has successfully logged in /// it has no fields -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClientLoginAck; impl HandshakeSerialize for ClientLoginAck { diff --git a/src/message/handshake/clientloginreject.rs b/src/message/handshake/clientloginreject.rs index e8380d6..0c0fc85 100644 --- a/src/message/handshake/clientloginreject.rs +++ b/src/message/handshake/clientloginreject.rs @@ -1,14 +1,13 @@ -use crate::error::ProtocolError; use crate::primitive::{Variant, VariantMap}; -use crate::{HandshakeDeserialize, HandshakeSerialize}; +use crate::HandshakeSerialize; use failure::Error; /// ClientLoginReject is received after the client failed to login /// It contains an error message as String -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClientLoginReject { - error: String, + pub error: String, } impl HandshakeSerialize for ClientLoginReject { @@ -26,21 +25,10 @@ impl HandshakeSerialize for ClientLoginReject { } } -impl HandshakeDeserialize for ClientLoginReject { - fn parse(b: &[u8]) -> Result<(usize, Self), Error> { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - - let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8); - - if msgtype == "ClientLogin" { - return Ok(( - len, - Self { - error: match_variant!(values["ErrorString"], Variant::String), - }, - )); - } else { - bail!(ProtocolError::WrongMsgType); +impl From<VariantMap> for ClientLoginReject { + fn from(input: VariantMap) -> Self { + ClientLoginReject { + error: match_variant!(input.get("ErrorString").unwrap(), Variant::String), } } } diff --git a/src/message/handshake/init.rs b/src/message/handshake/init.rs index e4c0fa9..b4604b6 100644 --- a/src/message/handshake/init.rs +++ b/src/message/handshake/init.rs @@ -2,6 +2,7 @@ use crate::Deserialize; use crate::Serialize; /// The first few bytes sent to the core to initialize the connection and setup if we want to use tls and compression +#[derive(Clone, Debug)] pub struct Init { pub tls: bool, pub compression: bool, @@ -37,7 +38,15 @@ impl Init { handshake |= 0x02; } - return handshake.serialize().unwrap(); + // Select Protocol 2: Datastream + + let mut init: Vec<u8> = vec![]; + + // Add handshake and protocol to our buffer + init.extend(handshake.serialize().unwrap()); + init.extend(crate::message::Protocol::Datastream.serialize()); + + return init; } pub fn parse(buf: &[u8]) -> Self { diff --git a/src/message/handshake/mod.rs b/src/message/handshake/mod.rs index 9b3bcee..9885012 100644 --- a/src/message/handshake/mod.rs +++ b/src/message/handshake/mod.rs @@ -21,3 +21,49 @@ pub use init::*; pub use protocol::*; pub use sessioninit::*; pub use types::*; + +use crate::primitive::{Variant, VariantMap}; +use crate::{HandshakeDeserialize, HandshakeSerialize}; + +#[derive(Debug, Clone)] +pub enum HandshakeMessage { + ClientInit(ClientInit), + ClientInitAck(ClientInitAck), + ClientInitReject(ClientInitReject), + ClientLogin(ClientLogin), + ClientLoginAck, + ClientLoginReject(ClientLoginReject), + SessionInit(SessionInit), +} + +impl HandshakeSerialize for HandshakeMessage { + fn serialize(&self) -> Result<Vec<u8>, failure::Error> { + match self { + HandshakeMessage::ClientInit(inner) => inner.serialize(), + HandshakeMessage::ClientInitAck(inner) => inner.serialize(), + HandshakeMessage::ClientInitReject(inner) => inner.serialize(), + HandshakeMessage::ClientLogin(inner) => inner.serialize(), + HandshakeMessage::ClientLoginAck => ClientLoginAck.serialize(), + HandshakeMessage::ClientLoginReject(inner) => inner.serialize(), + HandshakeMessage::SessionInit(inner) => inner.serialize(), + } + } +} + +impl HandshakeDeserialize for HandshakeMessage { + fn parse(b: &[u8]) -> Result<(usize, Self), failure::Error> { + let (size, res) = VariantMap::parse(b)?; + + let msgtype = match_variant!(&res["MsgType"], Variant::String); + match msgtype.as_str() { + "ClientInit" => Ok((size, HandshakeMessage::ClientInit(res.into()))), + "ClientInitAck" => Ok((size, HandshakeMessage::ClientInitAck(res.into()))), + "ClientInitReject" => Ok((size, HandshakeMessage::ClientInitReject(res.into()))), + "ClientLogin" => Ok((size, HandshakeMessage::ClientLogin(res.into()))), + "ClientLoginAck" => Ok((size, HandshakeMessage::ClientLoginAck)), + "ClientLoginReject" => Ok((size, HandshakeMessage::ClientLoginReject(res.into()))), + "SessionInit" => Ok((size, HandshakeMessage::SessionInit(res.into()))), + _ => unimplemented!(), + } + } +} diff --git a/src/message/handshake/sessioninit.rs b/src/message/handshake/sessioninit.rs index eca4c10..d1b4b90 100644 --- a/src/message/handshake/sessioninit.rs +++ b/src/message/handshake/sessioninit.rs @@ -1,61 +1,81 @@ -use crate::error::ProtocolError; -use crate::primitive::{Variant, VariantList, VariantMap}; -use crate::{HandshakeDeserialize, HandshakeSerialize}; +use crate::message::objects::Identity; +use crate::primitive::{BufferInfo, Variant, VariantMap}; +use crate::HandshakeSerialize; use failure::Error; /// SessionInit is received along with ClientLoginAck to initialize that user Session // TODO Replace with proper types -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SessionInit { /// List of all configured identities - identities: VariantList, + pub identities: Vec<Identity>, /// List of all existing buffers - buffers: VariantList, + pub buffers: Vec<BufferInfo>, /// Ids of all networks - network_ids: VariantList, + pub network_ids: Vec<i32>, +} + +impl From<VariantMap> for SessionInit { + fn from(input: VariantMap) -> Self { + let state = match_variant!(input.get("SessionState").unwrap(), Variant::VariantMap); + SessionInit { + identities: match_variant!(state.get("Identities").unwrap(), Variant::VariantList) + .iter() + .map(|ident| Identity::from(match_variant!(ident, Variant::VariantMap))) + .collect(), + buffers: match_variant!(state.get("BufferInfos").unwrap(), Variant::VariantList) + .iter() + .map(|buffer| match buffer { + Variant::BufferInfo(buffer) => buffer.clone(), + _ => unimplemented!(), + }) + .collect(), + network_ids: match_variant!(state.get("NetworkIds").unwrap(), Variant::VariantList) + .iter() + .map(|network| match network { + Variant::i32(network) => network.clone(), + _ => unimplemented!(), + }) + .collect(), + } + } } impl HandshakeSerialize for SessionInit { fn serialize(&self) -> Result<Vec<u8>, Error> { - let mut values: VariantMap = VariantMap::with_capacity(1); + let mut values: VariantMap = VariantMap::with_capacity(4); values.insert( "MsgType".to_string(), Variant::String("SessionInit".to_string()), ); values.insert( "Identities".to_string(), - Variant::VariantList(self.identities.clone()), + Variant::VariantList( + self.identities + .iter() + .map(|ident| Variant::VariantMap(ident.clone().into())) + .collect(), + ), ); values.insert( "BufferInfos".to_string(), - Variant::VariantList(self.buffers.clone()), + Variant::VariantList( + self.buffers + .iter() + .map(|buffer| Variant::BufferInfo(buffer.clone())) + .collect(), + ), ); values.insert( "NetworkIds".to_string(), - Variant::VariantList(self.network_ids.clone()), + Variant::VariantList( + self.network_ids + .iter() + .map(|id| Variant::i32(id.clone())) + .collect(), + ), ); return HandshakeSerialize::serialize(&values); } } - -impl HandshakeDeserialize for SessionInit { - fn parse(b: &[u8]) -> Result<(usize, Self), Error> { - let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?; - - let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8); - - if msgtype == "ClientLogin" { - return Ok(( - len, - Self { - identities: match_variant!(values["Identities"], Variant::VariantList), - buffers: match_variant!(values["BufferInfos"], Variant::VariantList), - network_ids: match_variant!(values["NetworkIds"], Variant::VariantList), - }, - )); - } else { - bail!(ProtocolError::WrongMsgType); - } - } -} diff --git a/src/message/signalproxy.rs b/src/message/signalproxy.rs deleted file mode 100644 index 22a498a..0000000 --- a/src/message/signalproxy.rs +++ /dev/null @@ -1,309 +0,0 @@ -use crate::primitive::{DateTime, Variant, VariantList}; -use crate::{Deserialize, Serialize}; - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub enum Message { - /// Bidirectional - SyncMessage(SyncMessage), - /// Bidirectional - RpcCall(RpcCall), - InitRequest(InitRequest), - InitData(InitData), - /// Bidirectional - HeartBeat(HeartBeat), - /// Bidirectional - HeartBeatReply(HeartBeatReply), -} - -impl Serialize for Message { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - match &self { - Message::SyncMessage(value) => value.serialize(), - Message::RpcCall(value) => value.serialize(), - Message::InitRequest(value) => value.serialize(), - Message::InitData(value) => value.serialize(), - Message::HeartBeat(value) => value.serialize(), - Message::HeartBeatReply(value) => value.serialize(), - } - } -} - -impl Deserialize for Message { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (_, message_type) = i32::parse(&b[9..13])?; - - match MessageType::from(message_type) { - MessageType::SyncMessage => { - let (size, res) = SyncMessage::parse(&b)?; - - Ok((size, Message::SyncMessage(res))) - } - MessageType::RpcCall => { - let (size, res) = RpcCall::parse(&b)?; - - Ok((size, Message::RpcCall(res))) - } - MessageType::InitRequest => { - let (size, res) = InitRequest::parse(&b)?; - - Ok((size, Message::InitRequest(res))) - } - MessageType::InitData => { - let (size, res) = InitData::parse(&b)?; - - Ok((size, Message::InitData(res))) - } - MessageType::HeartBeat => { - let (size, res) = HeartBeat::parse(&b)?; - - Ok((size, Message::HeartBeat(res))) - } - MessageType::HeartBeatReply => { - let (size, res) = HeartBeatReply::parse(&b)?; - - Ok((size, Message::HeartBeatReply(res))) - } - } - } -} - -/// Type of an SignalProxy Message -/// The first element in the VariantList that is received -#[repr(i32)] -#[derive(Copy, Clone, Debug, std::cmp::PartialEq)] -pub enum MessageType { - /// Bidirectional - SyncMessage = 0x00000001, - /// Bidirectional - RpcCall = 0x00000002, - InitRequest = 0x00000003, - InitData = 0x00000004, - /// Bidirectional - HeartBeat = 0x00000005, - /// Bidirectional - HeartBeatReply = 0x00000006, -} - -impl From<i32> for MessageType { - fn from(val: i32) -> Self { - match val { - 0x00000001 => MessageType::SyncMessage, - 0x00000002 => MessageType::RpcCall, - 0x00000003 => MessageType::InitRequest, - 0x00000004 => MessageType::InitData, - 0x00000005 => MessageType::HeartBeat, - 0x00000006 => MessageType::HeartBeatReply, - _ => unimplemented!(), - } - } -} - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct SyncMessage { - class_name: String, - object_name: String, - slot_name: String, - params: VariantList, -} - -impl Serialize for SyncMessage { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - let mut res = VariantList::new(); - - res.push(Variant::i32(MessageType::SyncMessage as i32)); - res.push(Variant::StringUTF8(self.class_name.clone())); - res.push(Variant::StringUTF8(self.object_name.clone())); - res.push(Variant::StringUTF8(self.slot_name.clone())); - - res.append(&mut self.params.clone()); - - res.serialize() - } -} - -impl Deserialize for SyncMessage { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (size, mut res) = VariantList::parse(&b)?; - - res.remove(0); - - Ok(( - size, - Self { - class_name: match_variant!(res.remove(0), Variant::StringUTF8), - object_name: match_variant!(res.remove(0), Variant::StringUTF8), - slot_name: match_variant!(res.remove(0), Variant::StringUTF8), - params: res, - }, - )) - } -} - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct RpcCall { - slot_name: String, - params: VariantList, -} - -impl Serialize for RpcCall { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - let mut res = VariantList::new(); - - res.push(Variant::i32(MessageType::RpcCall as i32)); - res.push(Variant::StringUTF8(self.slot_name.clone())); - - res.append(&mut self.params.clone()); - - res.serialize() - } -} - -impl Deserialize for RpcCall { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (size, mut res) = VariantList::parse(&b)?; - - res.remove(0); - - Ok(( - size, - Self { - slot_name: match_variant!(res.remove(0), Variant::StringUTF8), - params: res, - }, - )) - } -} - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct InitRequest { - class_name: String, - object_name: String, -} - -impl Serialize for InitRequest { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - let mut res = VariantList::new(); - - res.push(Variant::i32(MessageType::InitRequest as i32)); - res.push(Variant::StringUTF8(self.class_name.clone())); - res.push(Variant::StringUTF8(self.object_name.clone())); - - res.serialize() - } -} - -impl Deserialize for InitRequest { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (size, mut res) = VariantList::parse(&b)?; - - res.remove(0); - - Ok(( - size, - Self { - class_name: match_variant!(res.remove(0), Variant::StringUTF8), - object_name: match_variant!(res.remove(0), Variant::StringUTF8), - }, - )) - } -} - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct InitData { - class_name: String, - object_name: String, - init_data: VariantList, -} - -impl Serialize for InitData { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - let mut res = VariantList::new(); - - res.push(Variant::i32(MessageType::InitData as i32)); - res.push(Variant::StringUTF8(self.class_name.clone())); - res.push(Variant::StringUTF8(self.object_name.clone())); - - res.append(&mut self.init_data.clone()); - - res.serialize() - } -} - -impl Deserialize for InitData { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (size, mut res) = VariantList::parse(&b)?; - - res.remove(0); - - Ok(( - size, - Self { - class_name: match_variant!(res.remove(0), Variant::StringUTF8), - object_name: match_variant!(res.remove(0), Variant::StringUTF8), - init_data: res, - }, - )) - } -} - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct HeartBeat { - timestamp: DateTime, -} - -impl Serialize for HeartBeat { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - let mut res = VariantList::new(); - - res.push(Variant::i32(MessageType::HeartBeat as i32)); - res.push(Variant::DateTime(self.timestamp.clone())); - - res.serialize() - } -} - -impl Deserialize for HeartBeat { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (size, mut res) = VariantList::parse(&b)?; - - res.remove(0); - - Ok(( - size, - Self { - timestamp: match_variant!(res.remove(0), Variant::DateTime), - }, - )) - } -} - -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct HeartBeatReply { - timestamp: DateTime, -} - -impl Serialize for HeartBeatReply { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { - let mut res = VariantList::new(); - - res.push(Variant::i32(MessageType::HeartBeatReply as i32)); - res.push(Variant::DateTime(self.timestamp.clone())); - - res.serialize() - } -} - -impl Deserialize for HeartBeatReply { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { - let (size, mut res) = VariantList::parse(&b)?; - - res.remove(0); - - Ok(( - size, - Self { - timestamp: match_variant!(res.remove(0), Variant::DateTime), - }, - )) - } -} diff --git a/src/message/signalproxy/heartbeat.rs b/src/message/signalproxy/heartbeat.rs new file mode 100644 index 0000000..46bfd51 --- /dev/null +++ b/src/message/signalproxy/heartbeat.rs @@ -0,0 +1,65 @@ +use crate::message::MessageType; +use crate::primitive::{DateTime, Variant, VariantList}; +use crate::{Deserialize, Serialize}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct HeartBeat { + timestamp: DateTime, +} + +impl Serialize for HeartBeat { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::HeartBeat as i32)); + res.push(Variant::DateTime(self.timestamp.clone())); + + res.serialize() + } +} + +impl Deserialize for HeartBeat { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + timestamp: match_variant!(res.remove(0), Variant::DateTime), + }, + )) + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct HeartBeatReply { + timestamp: DateTime, +} + +impl Serialize for HeartBeatReply { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::HeartBeatReply as i32)); + res.push(Variant::DateTime(self.timestamp.clone())); + + res.serialize() + } +} + +impl Deserialize for HeartBeatReply { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + timestamp: match_variant!(res.remove(0), Variant::DateTime), + }, + )) + } +} diff --git a/src/message/signalproxy/initdata.rs b/src/message/signalproxy/initdata.rs new file mode 100644 index 0000000..e4fb077 --- /dev/null +++ b/src/message/signalproxy/initdata.rs @@ -0,0 +1,41 @@ +use crate::message::MessageType; +use crate::primitive::{Variant, VariantList}; +use crate::{Deserialize, Serialize}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct InitData { + class_name: String, + object_name: String, + init_data: VariantList, +} + +impl Serialize for InitData { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::InitData as i32)); + res.push(Variant::StringUTF8(self.class_name.clone())); + res.push(Variant::StringUTF8(self.object_name.clone())); + + res.append(&mut self.init_data.clone()); + + res.serialize() + } +} + +impl Deserialize for InitData { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + class_name: match_variant!(res.remove(0), Variant::StringUTF8), + object_name: match_variant!(res.remove(0), Variant::StringUTF8), + init_data: res, + }, + )) + } +} diff --git a/src/message/signalproxy/initrequest.rs b/src/message/signalproxy/initrequest.rs new file mode 100644 index 0000000..59eee2d --- /dev/null +++ b/src/message/signalproxy/initrequest.rs @@ -0,0 +1,37 @@ +use crate::message::MessageType; +use crate::primitive::{Variant, VariantList}; +use crate::{Deserialize, Serialize}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct InitRequest { + pub class_name: String, + pub object_name: String, +} + +impl Serialize for InitRequest { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::InitRequest as i32)); + res.push(Variant::ByteArray(self.class_name.clone())); + res.push(Variant::ByteArray(self.object_name.clone())); + + res.serialize() + } +} + +impl Deserialize for InitRequest { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + class_name: match_variant!(res.remove(0), Variant::StringUTF8), + object_name: match_variant!(res.remove(0), Variant::StringUTF8), + }, + )) + } +} diff --git a/src/message/signalproxy/mod.rs b/src/message/signalproxy/mod.rs new file mode 100644 index 0000000..4e99fb0 --- /dev/null +++ b/src/message/signalproxy/mod.rs @@ -0,0 +1,124 @@ +use crate::{Deserialize, Serialize}; + +mod heartbeat; +mod initdata; +mod initrequest; +pub mod objects; +mod rpccall; +mod syncmessage; + +pub use heartbeat::*; +pub use initdata::*; +pub use initrequest::*; +pub use rpccall::*; +pub use syncmessage::*; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub enum Message { + /// Bidirectional + SyncMessage(SyncMessage), + /// Bidirectional + RpcCall(RpcCall), + InitRequest(InitRequest), + InitData(InitData), + /// Bidirectional + HeartBeat(HeartBeat), + /// Bidirectional + HeartBeatReply(HeartBeatReply), +} + +// impl Message { +// fn act(&self) { +// match &self { +// Message::SyncMessage(value) => value.serialize(), +// Message::RpcCall(value) => value.serialize(), +// Message::InitRequest(value) => value.serialize(), +// Message::InitData(value) => value.serialize(), +// Message::HeartBeat(value) => value.serialize(), +// Message::HeartBeatReply(value) => value.serialize(), +// } +// } +// } + +impl Serialize for Message { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + match &self { + Message::SyncMessage(value) => value.serialize(), + Message::RpcCall(value) => value.serialize(), + Message::InitRequest(value) => value.serialize(), + Message::InitData(value) => value.serialize(), + Message::HeartBeat(value) => value.serialize(), + Message::HeartBeatReply(value) => value.serialize(), + } + } +} + +impl Deserialize for Message { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (_, message_type) = i32::parse(&b[9..13])?; + + match MessageType::from(message_type) { + MessageType::SyncMessage => { + let (size, res) = SyncMessage::parse(&b)?; + + Ok((size, Message::SyncMessage(res))) + } + MessageType::RpcCall => { + let (size, res) = RpcCall::parse(&b)?; + + Ok((size, Message::RpcCall(res))) + } + MessageType::InitRequest => { + let (size, res) = InitRequest::parse(&b)?; + + Ok((size, Message::InitRequest(res))) + } + MessageType::InitData => { + let (size, res) = InitData::parse(&b)?; + + Ok((size, Message::InitData(res))) + } + MessageType::HeartBeat => { + let (size, res) = HeartBeat::parse(&b)?; + + Ok((size, Message::HeartBeat(res))) + } + MessageType::HeartBeatReply => { + let (size, res) = HeartBeatReply::parse(&b)?; + + Ok((size, Message::HeartBeatReply(res))) + } + } + } +} + +/// Type of an SignalProxy Message +/// The first element in the VariantList that is received +#[repr(i32)] +#[derive(Copy, Clone, Debug, std::cmp::PartialEq)] +pub enum MessageType { + /// Bidirectional + SyncMessage = 0x00000001, + /// Bidirectional + RpcCall = 0x00000002, + InitRequest = 0x00000003, + InitData = 0x00000004, + /// Bidirectional + HeartBeat = 0x00000005, + /// Bidirectional + HeartBeatReply = 0x00000006, +} + +impl From<i32> for MessageType { + fn from(val: i32) -> Self { + match val { + 0x00000001 => MessageType::SyncMessage, + 0x00000002 => MessageType::RpcCall, + 0x00000003 => MessageType::InitRequest, + 0x00000004 => MessageType::InitData, + 0x00000005 => MessageType::HeartBeat, + 0x00000006 => MessageType::HeartBeatReply, + _ => unimplemented!(), + } + } +} diff --git a/src/message/signalproxy/objects/aliasmanager.rs b/src/message/signalproxy/objects/aliasmanager.rs new file mode 100644 index 0000000..828caaa --- /dev/null +++ b/src/message/signalproxy/objects/aliasmanager.rs @@ -0,0 +1,46 @@ +use crate::primitive::{Variant, VariantMap}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct AliasManager { + pub aliases: Vec<Alias>, +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct Alias { + name: String, + expansion: String, +} + +impl AliasManager { + /// Client to Server + /// + /// Replaces all properties of the object with the content of the + /// "properties" parameter. This parameter is in network representation. + /// + fn request_update(self: &mut Self, properties: VariantMap) { + self.update(properties); + } + + /// Server to Client + fn add_alias(self: &mut Self, name: String, expansion: String) { + self.aliases.push(Alias { name, expansion }); + } + + /// Server to Client + /// + /// Replaces all properties of the object with the content of the + /// "properties" parameter. This parameter is in network representation. + /// + fn update(self: &mut Self, properties: VariantMap) { + let mut alias: Vec<Alias> = Vec::new(); + + // for (i, name) in match_variant!(properties[&"Aliases".to_string()], Variant::String) { + // alias.push(Alias { + // name, + // expansion: match_variant!(properties["Aliases"], Variant::String)["expansions"][i], + // }) + // } + + self.aliases = alias + } +} diff --git a/src/message/signalproxy/objects/backlogmanager.rs b/src/message/signalproxy/objects/backlogmanager.rs new file mode 100644 index 0000000..86a7f61 --- /dev/null +++ b/src/message/signalproxy/objects/backlogmanager.rs @@ -0,0 +1,161 @@ +// interface BacklogManager { +// +// +// // C->S calls +// +// /** +// * Loads backlog for `bufferId`, starting at message `first`, up to `last` +// * (plus `additional` more messages after `last`) but at most `limit` +// * messages total. +// */ +// requestBacklog(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int) +// /** +// * Same as `requestBacklog`, but only messages of a certain message `type` +// * with certain `flags` set. +// */ +// requestBacklogFiltered(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int) +// /** +// * Same as `requestBacklog`, but applied to all buffers. +// */ +// requestBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int) +// /** +// * Same as `requestBacklogFiltered`, but applied to all buffers. +// */ +// requestBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int) +// +// +// // S->C calls +// +// /** +// * The response to `requestBacklog`, with the messages encoded as QVariants +// * in the `messages` parameter. +// */ +// receiveBacklog(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList) +// /** +// * The response to `requestBacklogFiltered`, with the messages encoded as +// * QVariants in the `messages` parameter. +// */ +// receiveBacklogFiltered(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList) +// /** +// * The response to `requestBacklogAll`, with the messages encoded as +// * QVariants in the `messages` parameter. +// */ +// receiveBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList) +// /** +// * The response to `requestBacklogAllFiltered`, with the messages encoded as +// * QVariants in the `messages` parameter. +// */ +// receiveBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList) +// } + +use crate::primitive::VariantList; + +/// Receive and Request Backlog +/// All "request" functions are Client to Server and all "receive" functions are Server to Client +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct BacklogManager {} + +impl BacklogManager { + /// Loads backlog for `bufferId`, starting at message `first`, up to `last` + /// (plus `additional` more messages after `last`) but at most `limit` + /// messages total. + fn requestBacklog( + self: Self, + buffer_id: u32, + first: u32, + last: u32, + limit: u32, + additional: u32, + ) { + unimplemented!() + } + + /// Same as `requestBacklog`, but only messages of a certain message `type` + /// with certain `flags` set. + fn requestBacklogFiltered( + self: Self, + buffer_id: u32, + first: u32, + last: u32, + limit: u32, + additional: u32, + msgtype: u32, + flags: u32, + ) { + unimplemented!() + } + + /// Same as `requestBacklog`, but applied to all buffers. + fn requestBacklogAll(self: Self, first: u32, last: u32, limit: u32, additional: u32) { + unimplemented!() + } + + /// Same as `requestBacklogFiltered`, but applied to all buffers. + fn requestBacklogAllFiltered( + self: Self, + first: u32, + last: u32, + limit: u32, + additional: u32, + msgtype: u32, + flags: u32, + ) { + unimplemented!() + } + + /// The response to `requestBacklog`, with the messages encoded as Variants + /// in the `messages` parameter. + fn receiveBacklog( + self: Self, + buffer_id: u32, + first: u32, + last: u32, + limit: u32, + additional: u32, + messages: VariantList, + ) { + unimplemented!() + } + + /// The response to `requestBacklogFiltered`, with the messages encoded as + /// Variants in the `messages` parameter. + fn receiveBacklogFiltered( + self: Self, + buffer_id: u32, + first: u32, + last: u32, + limit: u32, + additional: u32, + msgtype: u32, + flags: u32, + messages: VariantList, + ) { + unimplemented!() + } + + /// Same as `receiveBacklog`, but applied to all buffers. + fn receiveBacklogAll( + self: Self, + first: u32, + last: u32, + limit: u32, + additional: u32, + messages: VariantList, + ) { + unimplemented!() + } + + /// Same as `receiveBacklogFiltered`, but applied to all buffers. + fn receiveBacklogAllFiltered( + self: Self, + first: u32, + last: u32, + limit: u32, + additional: u32, + msgtype: u32, + flags: u32, + messages: VariantList, + ) { + unimplemented!() + } +} diff --git a/src/message/signalproxy/objects/buffersyncer.rs b/src/message/signalproxy/objects/buffersyncer.rs new file mode 100644 index 0000000..7ee4ca5 --- /dev/null +++ b/src/message/signalproxy/objects/buffersyncer.rs @@ -0,0 +1,74 @@ +use crate::message::signalproxy::MessageType; +use std::collections::HashMap; + +// use default_macro::default; +// #[default(crate::message::signalproxy::objects::BufferSyncerClient)] +pub struct BufferSyncer { + pub activities: HashMap<u32, MessageType>, + pub highlight_counts: HashMap<u32, u32>, + pub last_seen_msg: HashMap<u32, u32>, + pub marker_line: HashMap<u32, u32>, +} + +pub trait BufferSyncerServer { + fn activities(self: &Self) -> &HashMap<u32, MessageType>; + fn activities_mut(self: &mut Self) -> &mut HashMap<u32, MessageType>; + + fn highlight_counts(self: &Self) -> &HashMap<u32, u32>; + fn highlight_counts_mut(self: &mut Self) -> &mut HashMap<u32, u32>; + + fn last_seen_msg(self: &Self) -> &HashMap<u32, u32>; + fn last_seen_msg_mut(self: &mut Self) -> &mut HashMap<u32, u32>; + + fn marker_line(self: &Self) -> &HashMap<u32, u32>; + fn marker_line_mut(self: &mut Self) -> &mut HashMap<u32, u32>; + + fn request_mark_buffer_as_read(buffer: u32); + fn request_merge_buffers_permanently(buffer1: u32, buffer2: u32); + fn request_purge_buffer_ids(); + fn request_remove_buffer(buffer: u32); + fn request_rename_buffer(buffer: u32, new_name: String); + + fn request_set_last_seen_msg(self: &mut Self, buffer: u32, msgid: u32) { + self.last_seen_msg_mut().insert(buffer, msgid); + } + + fn request_set_marker_line(self: &mut Self, buffer: u32, msgid: u32) { + self.marker_line_mut().insert(buffer, msgid); + } +} + +pub trait BufferSyncerClient { + fn activities(self: &Self) -> &HashMap<u32, MessageType>; + fn activities_mut(self: &mut Self) -> &mut HashMap<u32, MessageType>; + + fn highlight_counts(self: &Self) -> &HashMap<u32, u32>; + fn highlight_counts_mut(self: &mut Self) -> &mut HashMap<u32, u32>; + + fn last_seen_msg(self: &Self) -> &HashMap<u32, u32>; + fn last_seen_msg_mut(self: &mut Self) -> &mut HashMap<u32, u32>; + + fn marker_line(self: &Self) -> &HashMap<u32, u32>; + fn marker_line_mut(self: &mut Self) -> &mut HashMap<u32, u32>; + + fn mark_buffer_as_read(buffer: u32); + fn merge_buffers_permanently(buffer1: u32, buffer2: u32); + fn remove_buffer(buffer: u32); + fn rename_buffer(buffer: u32, new_name: String); + + fn set_buffer_activity(self: &mut Self, buffer: u32, activity: MessageType) { + self.activities_mut().insert(buffer, activity); + } + + fn set_highlight_count(self: &mut Self, buffer: u32, count: u32) { + self.highlight_counts_mut().insert(buffer, count); + } + + fn set_last_seen_msg(self: &mut Self, buffer: u32, msgid: u32) { + self.last_seen_msg_mut().insert(buffer, msgid); + } + + fn set_marker_line(self: &mut Self, buffer: u32, msgid: u32) { + self.marker_line_mut().insert(buffer, msgid); + } +} diff --git a/src/message/signalproxy/objects/identity.rs b/src/message/signalproxy/objects/identity.rs new file mode 100644 index 0000000..a710e5d --- /dev/null +++ b/src/message/signalproxy/objects/identity.rs @@ -0,0 +1,119 @@ +use crate::primitive::{Variant, VariantMap}; + +#[derive(Debug, Clone)] +pub struct Identity { + identity_id: i32, + identity_name: String, + real_name: String, + nicks: Vec<String>, + away_nick: String, + away_nick_enabled: bool, + away_reason: String, + away_reason_enabled: bool, + auto_away_enabled: bool, + auto_away_time: i32, + auto_away_reason: String, + auto_away_reason_enabled: bool, + detach_away_enabled: bool, + detach_away_reason: String, + detach_away_reason_enabled: bool, + ident: String, + kick_reason: String, + part_reason: String, + quit_reason: String, +} + +impl From<VariantMap> for Identity { + fn from(input: VariantMap) -> Self { + Identity { + identity_id: match_variant!(input.get("identityId").unwrap(), Variant::i32), + identity_name: match_variant!(input.get("identityName").unwrap(), Variant::String), + real_name: match_variant!(input.get("realName").unwrap(), Variant::String), + nicks: match_variant!(input.get("nicks").unwrap(), Variant::StringList), + away_nick: match_variant!(input.get("awayNick").unwrap(), Variant::String), + away_nick_enabled: match_variant!(input.get("awayNickEnabled").unwrap(), Variant::bool), + away_reason: match_variant!(input.get("awayReason").unwrap(), Variant::String), + away_reason_enabled: match_variant!( + input.get("awayReasonEnabled").unwrap(), + Variant::bool + ), + auto_away_enabled: match_variant!(input.get("autoAwayEnabled").unwrap(), Variant::bool), + auto_away_time: match_variant!(input.get("autoAwayTime").unwrap(), Variant::i32), + auto_away_reason: match_variant!(input.get("autoAwayReason").unwrap(), Variant::String), + auto_away_reason_enabled: match_variant!( + input.get("autoAwayReasonEnabled").unwrap(), + Variant::bool + ), + detach_away_enabled: match_variant!( + input.get("detachAwayEnabled").unwrap(), + Variant::bool + ), + detach_away_reason: match_variant!( + input.get("detachAwayReason").unwrap(), + Variant::String + ), + detach_away_reason_enabled: match_variant!( + input.get("detachAwayReasonEnabled").unwrap(), + Variant::bool + ), + ident: match_variant!(input.get("ident").unwrap(), Variant::String), + kick_reason: match_variant!(input.get("kickReason").unwrap(), Variant::String), + part_reason: match_variant!(input.get("partReason").unwrap(), Variant::String), + quit_reason: match_variant!(input.get("quitReason").unwrap(), Variant::String), + } + } +} + +impl Into<std::collections::HashMap<String, Variant>> for Identity { + fn into(self) -> VariantMap { + let mut res = VariantMap::with_capacity(19); + + res.insert("identityId".to_string(), Variant::i32(self.identity_id)); + res.insert( + "identityName".to_string(), + Variant::String(self.identity_name), + ); + res.insert("realName".to_string(), Variant::String(self.real_name)); + res.insert("nicks".to_string(), Variant::StringList(self.nicks)); + res.insert("awayNick".to_string(), Variant::String(self.away_nick)); + res.insert( + "awayNickEnabled".to_string(), + Variant::bool(self.away_nick_enabled), + ); + res.insert("awayReason".to_string(), Variant::String(self.away_reason)); + res.insert( + "awayReasonEnabled".to_string(), + Variant::bool(self.away_reason_enabled), + ); + res.insert( + "autoAwayEnabled".to_string(), + Variant::bool(self.auto_away_enabled), + ); + res.insert( + "autoAwayTime".to_string(), + Variant::i32(self.auto_away_time), + ); + res.insert( + "autoAwayReason".to_string(), + Variant::String(self.auto_away_reason), + ); + res.insert( + "detachAwayEnabled".to_string(), + Variant::bool(self.detach_away_enabled), + ); + res.insert( + "detachAwayReason".to_string(), + Variant::String(self.detach_away_reason), + ); + res.insert( + "detachAwayReasonEnabled".to_string(), + Variant::bool(self.detach_away_reason_enabled), + ); + res.insert("ident".to_string(), Variant::String(self.ident)); + res.insert("kickReason".to_string(), Variant::String(self.kick_reason)); + res.insert("partReason".to_string(), Variant::String(self.part_reason)); + res.insert("quitReason".to_string(), Variant::String(self.quit_reason)); + + res + } +} diff --git a/src/message/signalproxy/objects/mod.rs b/src/message/signalproxy/objects/mod.rs new file mode 100644 index 0000000..a84f6fa --- /dev/null +++ b/src/message/signalproxy/objects/mod.rs @@ -0,0 +1,12 @@ +// mod aliasmanager; +// mod backlogmanager; + +mod buffersyncer; +mod identity; + +pub use buffersyncer::*; +pub use identity::*; + +pub trait Act { + fn act(self: Self); +} diff --git a/src/message/signalproxy/rpccall.rs b/src/message/signalproxy/rpccall.rs new file mode 100644 index 0000000..2eac86d --- /dev/null +++ b/src/message/signalproxy/rpccall.rs @@ -0,0 +1,59 @@ +use crate::message::MessageType; +use crate::primitive::Message; +use crate::primitive::{Variant, VariantList}; +use crate::{Deserialize, Serialize}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub enum RpcCall { + DisplayMessage(DisplayMessage), +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct DisplayMessage { + pub message: Message, +} + +// #[derive(Clone, Debug, std::cmp::PartialEq)] +// pub struct RpcCall { +// pub slot_name: String, +// pub params: VariantList, +// } + +impl Serialize for RpcCall { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::RpcCall as i32)); + + match self { + RpcCall::DisplayMessage(msg) => { + res.push(Variant::StringUTF8("2displayMsg(Message)".to_string())); + res.push(Variant::Message(msg.message.clone())); + } + } + + res.serialize() + } +} + +impl Deserialize for RpcCall { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + let rpc = match_variant!(res.remove(0), Variant::StringUTF8); + + match rpc.as_str() { + "2displayMsg(Message)" => { + return Ok(( + size, + RpcCall::DisplayMessage(DisplayMessage { + message: match_variant!(res.remove(0), Variant::Message), + }), + )) + } + _ => unimplemented!(), + } + } +} diff --git a/src/message/signalproxy/syncmessage.rs b/src/message/signalproxy/syncmessage.rs new file mode 100644 index 0000000..737f3e0 --- /dev/null +++ b/src/message/signalproxy/syncmessage.rs @@ -0,0 +1,46 @@ +use crate::message::MessageType; +use crate::primitive::{Variant, VariantList}; +use crate::{Deserialize, Serialize}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct SyncMessage { + class_name: String, + object_name: String, + slot_name: String, + params: VariantList, +} + +// impl Act for SyncMessage {} + +impl Serialize for SyncMessage { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::SyncMessage as i32)); + res.push(Variant::StringUTF8(self.class_name.clone())); + res.push(Variant::StringUTF8(self.object_name.clone())); + res.push(Variant::StringUTF8(self.slot_name.clone())); + + res.append(&mut self.params.clone()); + + res.serialize() + } +} + +impl Deserialize for SyncMessage { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + class_name: match_variant!(res.remove(0), Variant::StringUTF8), + object_name: match_variant!(res.remove(0), Variant::StringUTF8), + slot_name: match_variant!(res.remove(0), Variant::StringUTF8), + params: res, + }, + )) + } +} diff --git a/src/primitive/datetime.rs b/src/primitive/datetime.rs index cbcdd51..fadd6a5 100644 --- a/src/primitive/datetime.rs +++ b/src/primitive/datetime.rs @@ -76,10 +76,18 @@ impl Deserialize for OffsetDateTime { let zone = TimeSpec::from(zone as i8); + // Default to unix epoch when one of these is set to -1 + if julian_day == -1 || millis_of_day == -1 { + return Ok((pos, OffsetDateTime::unix_epoch())); + } + let offset: UtcOffset; match zone { TimeSpec::LocalUnknown | TimeSpec::LocalStandard | TimeSpec::LocalDST => { - offset = UtcOffset::current_local_offset() + offset = UtcOffset::try_current_local_offset().unwrap_or_else(|_| { + log::warn!("could not get local offset defaulting to utc"); + UtcOffset::UTC + }) } TimeSpec::UTC => offset = UtcOffset::UTC, TimeSpec::OffsetFromUTC => { diff --git a/src/primitive/message.rs b/src/primitive/message.rs index 64b132d..56bae22 100644 --- a/src/primitive/message.rs +++ b/src/primitive/message.rs @@ -15,9 +15,20 @@ extern crate bytes; #[derive(Clone, Debug, std::cmp::PartialEq)] pub struct Message { /// The unique, sequential id for the message + /// i32 by default i64 if long-message-id features is enabled + #[cfg(feature = "long-message-id")] + #[cfg_attr(docsrs, doc(cfg(feature = "long-message-id")))] + pub msg_id: i64, + #[cfg(not(feature = "long-message-id"))] + #[cfg_attr(docsrs, doc(cfg(not(feature = "long-message-id"))))] pub msg_id: i32, - /// The timestamp of the message in UNIX time (32-bit, seconds, 64-bit if LONGMESSAGE feature enabled) + /// The timestamp of the message in UNIX time (32-bit, seconds, 64-bit if long-time feature enabled) + #[cfg(feature = "long-time")] + #[cfg_attr(docsrs, doc(cfg(feature = "long-time")))] pub timestamp: i64, + #[cfg(not(feature = "long-time"))] + #[cfg_attr(docsrs, doc(cfg(not(feature = "long-time"))))] + pub timestamp: i32, /// The message type as it's own type serialized as i32 pub msg_type: MessageType, /// The flags @@ -27,14 +38,17 @@ pub struct Message { /// The sender as nick!ident@host pub sender: String, /// The prefix modes of the sender. - /// Only Some when the SenderPrefix features is enabled - pub sender_prefixes: Option<String>, + #[cfg(feature = "sender-prefixes")] + #[cfg_attr(docsrs, doc(cfg(feature = "sender-prefixes")))] + pub sender_prefixes: String, /// The realName of the sender - /// Only Some when the RichMessage features is enabled - pub real_name: Option<String>, + #[cfg(feature = "rich-messages")] + #[cfg_attr(docsrs, doc(cfg(feature = "rich-messages")))] + pub real_name: String, /// The avatarUrl of the sender, if available - /// Only Some when the RichMessage features is enabled - pub avatar_url: Option<String>, + #[cfg(feature = "rich-messages")] + #[cfg_attr(docsrs, doc(cfg(feature = "rich-messages")))] + pub avatar_url: String, /// The message content, already stripped from CTCP formatting, but containing mIRC format codes pub content: String, } @@ -43,35 +57,28 @@ impl Serialize for Message { fn serialize(&self) -> Result<Vec<u8>, Error> { let mut values: Vec<u8> = Vec::new(); + #[cfg(feature = "long-message-id")] + values.append(&mut i64::serialize(&self.msg_id)?); + #[cfg(not(feature = "long-message-id"))] values.append(&mut i32::serialize(&self.msg_id)?); - // TODO LONGMESSAGE feature - if false { - values.append(&mut i64::serialize(&self.timestamp)?); - } else { - values.append(&mut i32::serialize(&(self.timestamp as i32))?); - } + #[cfg(feature = "long-time")] + values.append(&mut i64::serialize(&self.timestamp)?); + #[cfg(not(feature = "long-time"))] + values.append(&mut i32::serialize(&(self.timestamp as i32))?); values.append(&mut i32::serialize(&(self.msg_type as i32))?); values.append(&mut i8::serialize(&(self.flags as i8))?); values.append(&mut BufferInfo::serialize(&self.buffer)?); values.append(&mut String::serialize_utf8(&self.sender)?); - // TODO SenderPrefixes feature - if false { - if let Some(x) = &self.sender_prefixes { - values.append(&mut String::serialize_utf8(&x)?); - } - } + #[cfg(feature = "sender-prefixes")] + values.append(&mut String::serialize_utf8(&self.sender_prefixes)?); - // TODO RichMessages feature - if false { - if let Some(x) = &self.real_name { - values.append(&mut String::serialize_utf8(&x)?); - } - if let Some(x) = &self.avatar_url { - values.append(&mut String::serialize_utf8(&x)?); - } + #[cfg(feature = "rich-messages")] + { + values.append(&mut String::serialize_utf8(&self.real_name)?); + values.append(&mut String::serialize_utf8(&self.avatar_url)?); } values.append(&mut String::serialize_utf8(&self.content)?); @@ -83,19 +90,27 @@ impl Serialize for Message { impl Deserialize for Message { fn parse(b: &[u8]) -> Result<(usize, Self), Error> { let mut pos = 0; + #[cfg(feature = "long-message-id")] + let (parsed, msg_id) = i64::parse(&b[pos..])?; + #[cfg(not(feature = "long-message-id"))] let (parsed, msg_id) = i32::parse(&b[pos..])?; pos += parsed; // TODO LONGMESSAGES feature let timestamp; - if false { + + #[cfg(feature = "long-time")] + { let (parsed, temp_timestamp) = i64::parse(&b[pos..])?; pos += parsed; timestamp = temp_timestamp; - } else { + } + + #[cfg(not(feature = "long-time"))] + { let (parsed, temp_timestamp) = i32::parse(&b[pos..])?; pos += parsed; - timestamp = temp_timestamp as i64; + timestamp = temp_timestamp; } let (parsed, msg_type) = i32::parse(&b[pos..])?; @@ -107,24 +122,27 @@ impl Deserialize for Message { let (parsed, sender) = String::parse_utf8(&b[pos..])?; pos += parsed; - // TODO SenderPrefixes feature - let mut sender_prefixes = None; - if false { + #[cfg(feature = "sender-prefixes")] + let sender_prefixes: String; + #[cfg(feature = "sender-prefixes")] + { let (parsed, temp) = String::parse_utf8(&b[pos..])?; - sender_prefixes = Some(temp); + sender_prefixes = temp; pos += parsed; } - // TODO SenderPrefixes feature - let mut real_name = None; - let mut avatar_url = None; - if false { + #[cfg(feature = "rich-messages")] + let real_name: String; + #[cfg(feature = "rich-messages")] + let avatar_url: String; + #[cfg(feature = "rich-messages")] + { let (parsed, temp) = String::parse_utf8(&b[pos..])?; - real_name = Some(temp); + real_name = temp; pos += parsed; let (parsed, temp) = String::parse_utf8(&b[pos..])?; - avatar_url = Some(temp); + avatar_url = temp; pos += parsed; } @@ -140,8 +158,11 @@ impl Deserialize for Message { flags, buffer, sender, + #[cfg(feature = "sender-prefixes")] sender_prefixes, + #[cfg(feature = "rich-messages")] real_name, + #[cfg(feature = "rich-messages")] avatar_url, content, }, diff --git a/src/primitive/string.rs b/src/primitive/string.rs index 86bcdec..dcd4f7c 100644 --- a/src/primitive/string.rs +++ b/src/primitive/string.rs @@ -7,8 +7,8 @@ use failure::Error; use log::trace; -use crate::{Deserialize, DeserializeUTF8, Serialize, SerializeUTF8}; use crate::util; +use crate::{Deserialize, DeserializeUTF8, Serialize, SerializeUTF8}; /// We Shadow the String type here as we can only use impl on types in our own scope. /// @@ -33,7 +33,6 @@ impl SerializeUTF8 for String { fn serialize_utf8(&self) -> Result<Vec<u8>, Error> { let mut res: Vec<u8> = Vec::new(); res.extend(self.clone().into_bytes()); - res.extend(vec![0x00]); util::prepend_byte_len(&mut res); return Ok(res); } @@ -64,6 +63,7 @@ impl Deserialize for String { } let res: String = String::from_utf16(&chars).unwrap(); + trace!("parsed string: {}", res); return Ok((pos, res)); } } @@ -81,6 +81,7 @@ impl DeserializeUTF8 for String { let ulen = len as usize; let mut res: String = String::from_utf8(b[4..(ulen + 4)].to_vec())?; + trace!("parsed string: {}", res); // If the last byte is zero remove it // Receiving a string as bytearray will sometimes have @@ -89,6 +90,8 @@ impl DeserializeUTF8 for String { let _ = res.pop(); } + trace!("parsed string after trunc: {}", res); + return Ok((ulen + 4, res)); } } diff --git a/src/primitive/variant.rs b/src/primitive/variant.rs index 9242d90..be2bebe 100644 --- a/src/primitive/variant.rs +++ b/src/primitive/variant.rs @@ -36,6 +36,7 @@ pub enum Variant { VariantList(VariantList), String(String), StringUTF8(String), + ByteArray(String), StringList(StringList), bool(bool), u64(u64), @@ -77,6 +78,11 @@ impl Serialize for Variant { res.extend(unknown.to_be_bytes().iter()); res.extend(v.serialize_utf8()?.iter()); } + Variant::ByteArray(v) => { + res.extend(primitive::QBYTEARRAY.to_be_bytes().iter()); + res.extend(unknown.to_be_bytes().iter()); + res.extend(v.serialize_utf8()?.iter()); + } Variant::StringList(v) => { res.extend(primitive::QSTRINGLIST.to_be_bytes().iter()); res.extend(unknown.to_be_bytes().iter()); @@ -201,8 +207,7 @@ impl Deserialize for Variant { return Ok((len + vlen, Variant::StringList(value.clone()))); } primitive::QDATETIME => { - trace!(target: "primitive::Variant", "Parsing Variant: Date"); - // let (vlen, value) = DateTime::parse(&b[len..])?; + trace!(target: "primitive::Variant", "Parsing Variant: DateTime"); let (vlen, value): (usize, DateTime) = Deserialize::parse(&b[len..])?; return Ok((len + vlen, Variant::DateTime(value.clone()))); } @@ -269,12 +274,26 @@ impl Deserialize for Variant { return Ok((len + user_type_len + vlen, Variant::VariantMap(value))); } // As i32 - "BufferId" | "IdentityId" | "NetworkId" | "MsgId" => { + "BufferId" | "IdentityId" | "NetworkId" => { trace!(target: "primitive::Variant", "UserType is i32"); let (vlen, value) = i32::parse(&b[(len + user_type_len)..])?; return Ok((len + user_type_len + vlen, Variant::i32(value))); } + #[cfg(not(feature = "long-message-id"))] + "MsgId" => { + trace!(target: "primitive::Variant", "UserType is i32"); + + let (vlen, value) = i32::parse(&b[(len + user_type_len)..])?; + return Ok((len + user_type_len + vlen, Variant::i32(value))); + } + #[cfg(feature = "long-message-id")] + "MsgId" => { + trace!(target: "primitive::Variant", "UserType is i64"); + + let (vlen, value) = i64::parse(&b[(len + user_type_len)..])?; + return Ok((len + user_type_len + vlen, Variant::i64(value))); + } // As i64 "PeerPtr" => { trace!(target: "primitive::Variant", "UserType is i64"); diff --git a/src/primitive/variantlist.rs b/src/primitive/variantlist.rs index 452b927..a802864 100644 --- a/src/primitive/variantlist.rs +++ b/src/primitive/variantlist.rs @@ -40,6 +40,7 @@ impl Deserialize for VariantList { for i in 0..len { trace!(target: "primitive::VariantList", "Parsing VariantList element: {:?}", i); let (vlen, val) = Variant::parse(&b[pos..])?; + trace!("parsed variant: {:?}", val); res.push(val); pos += vlen; } diff --git a/src/session/mod.rs b/src/session/mod.rs new file mode 100644 index 0000000..67045c9 --- /dev/null +++ b/src/session/mod.rs @@ -0,0 +1,2 @@ +/// The Session Trait is the main point of entry and implements the basic logic +pub trait Session {} |
