From 44298f660f7765d288a9f272fdd27766898d4e29 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 3 Sep 2023 17:33:30 -0400 Subject: [PATCH] Remove old APIs, improve/fix front logging --- Cargo.lock | 12 -- usdpl-back/Cargo.toml | 6 +- usdpl-back/src/api_common/files.rs | 44 ----- usdpl-back/src/api_common/mod.rs | 1 - usdpl-build/Cargo.toml | 5 + usdpl-build/src/front/service_generator.rs | 3 + usdpl-core/Cargo.toml | 5 +- usdpl-core/src/lib.rs | 7 - usdpl-core/src/remote_call.rs | 114 ------------- usdpl-core/src/serdes/dump_impl.rs | 157 ----------------- usdpl-core/src/serdes/load_impl.rs | 185 --------------------- usdpl-core/src/serdes/mod.rs | 10 -- usdpl-core/src/serdes/primitive.rs | 163 ------------------ usdpl-core/src/serdes/traits.rs | 150 ----------------- usdpl-core/src/socket.rs | 174 ------------------- usdpl-front/Cargo.toml | 9 +- usdpl-front/src/client_handler.rs | 63 ++----- usdpl-front/src/connection.rs | 126 -------------- usdpl-front/src/console_logs.rs | 52 ++++++ usdpl-front/src/lib.rs | 182 ++++---------------- 20 files changed, 115 insertions(+), 1353 deletions(-) delete mode 100644 usdpl-back/src/api_common/files.rs delete mode 100644 usdpl-core/src/remote_call.rs delete mode 100644 usdpl-core/src/serdes/dump_impl.rs delete mode 100644 usdpl-core/src/serdes/load_impl.rs delete mode 100644 usdpl-core/src/serdes/mod.rs delete mode 100644 usdpl-core/src/serdes/primitive.rs delete mode 100644 usdpl-core/src/serdes/traits.rs delete mode 100644 usdpl-core/src/socket.rs delete mode 100644 usdpl-front/src/connection.rs create mode 100644 usdpl-front/src/console_logs.rs diff --git a/Cargo.lock b/Cargo.lock index b70aa29..74c7017 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,17 +196,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "console_log" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" -dependencies = [ - "log", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "convert_case" version = "0.4.0" @@ -1565,7 +1554,6 @@ name = "usdpl-front" version = "0.11.0" dependencies = [ "console_error_panic_hook", - "console_log", "futures", "futures-channel", "gloo-net", diff --git a/usdpl-back/Cargo.toml b/usdpl-back/Cargo.toml index 872c61d..67e03cd 100644 --- a/usdpl-back/Cargo.toml +++ b/usdpl-back/Cargo.toml @@ -2,8 +2,9 @@ name = "usdpl-back" version = "0.11.0" edition = "2021" +authors = ["NGnius "] license = "GPL-3.0-only" -repository = "https://github.com/NGnius/usdpl-rs" +repository = "https://git.ngni.us/NG-SD-Plugins/usdpl-rs" readme = "../README.md" description = "Universal Steam Deck Plugin Library back-end" @@ -11,7 +12,7 @@ description = "Universal Steam Deck Plugin Library back-end" default = ["blocking"] decky = ["usdpl-core/decky"] blocking = [] # synchronous API for async functionality, using tokio -encrypt = ["usdpl-core/encrypt", "obfstr", "hex"] +#encrypt = ["usdpl-core", "obfstr", "hex"] [dependencies] usdpl-core = { version = "0.11", path = "../usdpl-core"} @@ -27,7 +28,6 @@ prost = "0.11" ratchet_rs = { version = "0.4", features = [ "deflate" ] } # HTTP web framework -#warp = { version = "0.3" } bytes = { version = "1.1" } tokio = { version = "1", features = [ "full" ]} diff --git a/usdpl-back/src/api_common/files.rs b/usdpl-back/src/api_common/files.rs deleted file mode 100644 index f3085a3..0000000 --- a/usdpl-back/src/api_common/files.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Common low-level file operations -use std::fmt::Display; -use std::fs::File; -use std::io::{self, Read, Write}; -use std::path::Path; -use std::str::FromStr; - -/// Write something to a file. -/// Useful for kernel configuration files. -#[inline] -pub fn write_single, D: Display>(path: P, display: D) -> Result<(), io::Error> { - let mut file = File::create(path)?; - write!(file, "{}", display) -} - -/// read_single error -#[derive(Debug)] -pub enum ReadError { - /// IO Error - Io(io::Error), - /// String parsing error - Parse(E), -} - -impl std::fmt::Display for ReadError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Io(io) => write!(f, "io: {}", io), - Self::Parse(e) => write!(f, "parse: {}", e), - } - } -} - -impl std::error::Error for ReadError {} - -/// Read something from a file. -/// Useful for kernel configuration files. -#[inline] -pub fn read_single, D: FromStr, E>(path: P) -> Result> { - let mut file = File::open(path).map_err(ReadError::Io)?; - let mut string = String::new(); - file.read_to_string(&mut string).map_err(ReadError::Io)?; - string.trim().parse().map_err(ReadError::Parse) -} diff --git a/usdpl-back/src/api_common/mod.rs b/usdpl-back/src/api_common/mod.rs index 63763e5..16ec367 100644 --- a/usdpl-back/src/api_common/mod.rs +++ b/usdpl-back/src/api_common/mod.rs @@ -1,2 +1 @@ pub mod dirs; -pub mod files; diff --git a/usdpl-build/Cargo.toml b/usdpl-build/Cargo.toml index 796f836..9e0a40a 100644 --- a/usdpl-build/Cargo.toml +++ b/usdpl-build/Cargo.toml @@ -2,6 +2,11 @@ name = "usdpl-build" version = "0.11.0" edition = "2021" +authors = ["NGnius "] +license = "GPL-3.0-only" +repository = "https://git.ngni.us/NG-SD-Plugins/usdpl-rs" +readme = "../README.md" +description = "Universal Steam Deck Plugin Library core" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/usdpl-build/src/front/service_generator.rs b/usdpl-build/src/front/service_generator.rs index 5391926..d3dd5f9 100644 --- a/usdpl-build/src/front/service_generator.rs +++ b/usdpl-build/src/front/service_generator.rs @@ -1026,6 +1026,7 @@ impl IServiceGenerator for WasmServiceGenerator { .expect("FileDescriptorSet required for WASM service generator"); let service_struct_name = quote::format_ident!("{}Client", service.name); let service_js_name = quote::format_ident!("{}", service.name); + let service_str_name = service.name.clone(); let service_methods = generate_service_methods(&service, fds); let service_types = generate_service_io_types(&service, fds); let mod_name = quote::format_ident!("js_{}", service.name.to_lowercase()); @@ -1059,9 +1060,11 @@ impl IServiceGenerator for WasmServiceGenerator { impl #service_js_name { #[wasm_bindgen(constructor)] pub fn new(port: u16) -> Self { + usdpl_front::init_usdpl(); let implementation = super::#service_struct_name::new( WebSocketHandler::new(port) ); + log::info!("Initialized ws service {} on port {}", #service_str_name, port); Self { service: implementation, } diff --git a/usdpl-core/Cargo.toml b/usdpl-core/Cargo.toml index b196650..e9c1e5e 100644 --- a/usdpl-core/Cargo.toml +++ b/usdpl-core/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "usdpl-core" version = "0.11.0" +authors = ["NGnius "] edition = "2021" license = "GPL-3.0-only" -repository = "https://github.com/NGnius/usdpl-rs" +repository = "https://git.ngni.us/NG-SD-Plugins/usdpl-rs" readme = "../README.md" -description = "Universal Steam Deck Plugin Library core" +description = "Universal Steam Deck Plugin Library core designed for all architectures" [features] default = [] diff --git a/usdpl-core/src/lib.rs b/usdpl-core/src/lib.rs index f5453bc..18ddfb9 100644 --- a/usdpl-core/src/lib.rs +++ b/usdpl-core/src/lib.rs @@ -2,19 +2,12 @@ //! This contains serialization functionality and networking datatypes. #![warn(missing_docs)] -mod remote_call; - #[cfg(not(any(feature = "decky")))] mod api_any; mod api_common; #[cfg(all(feature = "decky", not(any(feature = "any"))))] mod api_decky; -pub mod serdes; -pub mod socket; - -pub use remote_call::{RemoteCall, RemoteCallResponse}; - /// USDPL core API. /// This contains functionality used in both the back-end and front-end. pub mod api { diff --git a/usdpl-core/src/remote_call.rs b/usdpl-core/src/remote_call.rs deleted file mode 100644 index 973f0db..0000000 --- a/usdpl-core/src/remote_call.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::io::{Read, Write}; - -use crate::serdes::{DumpError, Dumpable, LoadError, Loadable, Primitive}; - -/// Remote call packet representing a function to call on the back-end, sent from the front-end -pub struct RemoteCall { - /// The call id assigned by the front-end - pub id: u64, - /// The function's name - pub function: String, - /// The function's input parameters - pub parameters: Vec, -} - -impl Loadable for RemoteCall { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let (id_num, len0) = u64::load(buffer)?; - let (function_name, len1) = String::load(buffer)?; - let (params, len2) = Vec::::load(buffer)?; - Ok(( - Self { - id: id_num, - function: function_name, - parameters: params, - }, - len0 + len1 + len2, - )) - } -} - -impl Dumpable for RemoteCall { - fn dump(&self, buffer: &mut dyn Write) -> Result { - let len0 = self.id.dump(buffer)?; - let len1 = self.function.dump(buffer)?; - let len2 = self.parameters.dump(buffer)?; - Ok(len0 + len1 + len2) - } -} - -/// Remote call response packet representing the response from a remote call after the back-end has executed it. -pub struct RemoteCallResponse { - /// The call id from the RemoteCall - pub id: u64, - /// The function's result - pub response: Vec, -} - -impl Loadable for RemoteCallResponse { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let (id_num, len0) = u64::load(buffer)?; - let (response_var, len1) = Vec::::load(buffer)?; - Ok(( - Self { - id: id_num, - response: response_var, - }, - len0 + len1, - )) - } -} - -impl Dumpable for RemoteCallResponse { - fn dump(&self, buffer: &mut dyn Write) -> Result { - let len0 = self.id.dump(buffer)?; - let len1 = self.response.dump(buffer)?; - Ok(len0 + len1) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn remote_call_idempotence_test() { - let call = RemoteCall { - id: 42, - function: "something very long just in case this causes unexpected issues".into(), - parameters: vec!["param1".into(), 42f64.into()], - }; - - let mut buffer = String::with_capacity(crate::socket::PACKET_BUFFER_SIZE); - let len = call.dump_base64(&mut buffer).unwrap(); - - println!("base64 dumped: `{}` (len: {})", buffer, len); - - let (loaded_call, loaded_len) = RemoteCall::load_base64(buffer.as_bytes()).unwrap(); - assert_eq!(len, loaded_len, "Expected load and dump lengths to match"); - - assert_eq!(loaded_call.id, call.id, "RemoteCall.id does not match"); - assert_eq!( - loaded_call.function, call.function, - "RemoteCall.function does not match" - ); - if let Primitive::String(loaded) = &loaded_call.parameters[0] { - if let Primitive::String(original) = &call.parameters[0] { - assert_eq!(loaded, original, "RemoteCall.parameters[0] does not match"); - } else { - panic!("Original call parameter 0 is not String") - } - } else { - panic!("Loaded call parameter 0 is not String") - } - if let Primitive::F64(loaded) = &loaded_call.parameters[1] { - if let Primitive::F64(original) = &call.parameters[1] { - assert_eq!(loaded, original, "RemoteCall.parameters[1] does not match"); - } else { - panic!("Original call parameter 1 is not f64") - } - } else { - panic!("Loaded call parameter 1 is not f64") - } - } -} diff --git a/usdpl-core/src/serdes/dump_impl.rs b/usdpl-core/src/serdes/dump_impl.rs deleted file mode 100644 index 61551fe..0000000 --- a/usdpl-core/src/serdes/dump_impl.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::io::Write; - -use super::{DumpError, Dumpable}; - -impl Dumpable for String { - fn dump(&self, buffer: &mut dyn Write) -> Result { - let str_bytes = self.as_bytes(); - let len_bytes = (str_bytes.len() as u32).to_le_bytes(); - let size1 = buffer.write(&len_bytes).map_err(DumpError::Io)?; - let size2 = buffer.write(&str_bytes).map_err(DumpError::Io)?; - Ok(size1 + size2) - } -} - -impl Dumpable for Vec { - fn dump(&self, buffer: &mut dyn Write) -> Result { - let len_bytes = (self.len() as u32).to_le_bytes(); - let mut total = buffer.write(&len_bytes).map_err(DumpError::Io)?; - for obj in self.iter() { - let len = obj.dump(buffer)?; - total += len; - } - Ok(total) - } -} - -impl Dumpable for (T0, T1) { - fn dump(&self, buffer: &mut dyn Write) -> Result { - Ok(self.0.dump(buffer)? + self.1.dump(buffer)?) - } -} - -impl Dumpable for (T0, T1, T2) { - fn dump(&self, buffer: &mut dyn Write) -> Result { - Ok(self.0.dump(buffer)? + self.1.dump(buffer)? + self.2.dump(buffer)?) - } -} - -impl Dumpable for (T0, T1, T2, T3) { - fn dump(&self, buffer: &mut dyn Write) -> Result { - Ok(self.0.dump(buffer)? - + self.1.dump(buffer)? - + self.2.dump(buffer)? - + self.3.dump(buffer)?) - } -} - -impl Dumpable - for (T0, T1, T2, T3, T4) -{ - fn dump(&self, buffer: &mut dyn Write) -> Result { - Ok(self.0.dump(buffer)? - + self.1.dump(buffer)? - + self.2.dump(buffer)? - + self.3.dump(buffer)? - + self.4.dump(buffer)?) - } -} - -impl Dumpable for bool { - fn dump(&self, buffer: &mut dyn Write) -> Result { - buffer.write(&[*self as u8]).map_err(DumpError::Io) - } -} - -impl Dumpable for u8 { - fn dump(&self, buffer: &mut dyn Write) -> Result { - buffer.write(&[*self]).map_err(DumpError::Io) - } -} - -/*impl Dumpable for i8 { - fn dump(&self, buffer: &mut dyn Write) -> Result { - buffer.write(&self.to_le_bytes()).map_err(DumpError::Io) - } -}*/ - -macro_rules! int_impl { - ($type:ty) => { - impl Dumpable for $type { - fn dump(&self, buffer: &mut dyn Write) -> Result { - buffer.write(&self.to_le_bytes()).map_err(DumpError::Io) - } - } - }; -} - -int_impl! {u16} -int_impl! {u32} -int_impl! {u64} -int_impl! {u128} - -int_impl! {i8} -int_impl! {i16} -int_impl! {i32} -int_impl! {i64} -int_impl! {i128} - -int_impl! {f32} -int_impl! {f64} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! test_impl { - ($fn_name:ident, $data:expr, $expected_len:literal, $expected_dump:expr) => { - #[test] - fn $fn_name() { - let data = $data; - let mut buffer = Vec::with_capacity(128); - let write_len = data.dump(&mut buffer).expect("Dump not ok"); - assert_eq!(write_len, $expected_len, "Wrong amount written"); - assert_eq!(&buffer[..write_len], $expected_dump); - println!("Dumped {:?}", buffer.as_slice()); - } - }; - } - - test_impl! {string_dump_test, "test".to_string(), 8, &[4, 0, 0, 0, 116, 101, 115, 116]} - - test_impl! { - vec_dump_test, - vec![ - "".to_string(), - "test1".to_string(), - "test2".to_string() - ], - 26, - &[3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 5, 0, 0, 0, 116, 101, 115, 116, 50] - } - - test_impl! {tuple2_dump_test, (0u8, 1u8), 2, &[0, 1]} - test_impl! {tuple3_dump_test, (0u8, 1u8, 2u8), 3, &[0, 1, 2]} - test_impl! {tuple4_dump_test, (0u8, 1u8, 2u8, 3u8), 4, &[0, 1, 2, 3]} - test_impl! {tuple5_dump_test, (0u8, 1u8, 2u8, 3u8, 4u8), 5, &[0, 1, 2, 3, 4]} - - test_impl! {bool_true_dump_test, true, 1, &[1]} - test_impl! {bool_false_dump_test, false, 1, &[0]} - - // testing macro-generated code isn't particularly useful, but do it anyway - - test_impl! {u8_dump_test, 42u8, 1, &[42]} - test_impl! {u16_dump_test, 42u16, 2, &[42, 0]} - test_impl! {u32_dump_test, 42u32, 4, &[42, 0, 0, 0]} - test_impl! {u64_dump_test, 42u64, 8, &[42, 0, 0, 0, 0, 0, 0, 0]} - test_impl! {u128_dump_test, 42u128, 16, &[42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - - test_impl! {i8_dump_test, 42i8, 1, &[42]} - test_impl! {i16_dump_test, 42i16, 2, &[42, 0]} - test_impl! {i32_dump_test, 42i32, 4, &[42, 0, 0, 0]} - test_impl! {i64_dump_test, 42i64, 8, &[42, 0, 0, 0, 0, 0, 0, 0]} - test_impl! {i128_dump_test, 42i128, 16, &[42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - - test_impl! {f32_dump_test, 42f32, 4, &[0, 0, 40, 66]} - test_impl! {f64_dump_test, 42f64, 8, &[0, 0, 0, 0, 0, 0, 69, 64]} -} diff --git a/usdpl-core/src/serdes/load_impl.rs b/usdpl-core/src/serdes/load_impl.rs deleted file mode 100644 index f2aa9bf..0000000 --- a/usdpl-core/src/serdes/load_impl.rs +++ /dev/null @@ -1,185 +0,0 @@ -use std::io::Read; - -use super::{LoadError, Loadable}; - -impl Loadable for String { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut u32_bytes: [u8; 4] = [u8::MAX; 4]; - buffer.read_exact(&mut u32_bytes).map_err(LoadError::Io)?; - let str_size = u32::from_le_bytes(u32_bytes) as usize; - //let mut str_buf = String::with_capacity(str_size); - let mut str_buf = Vec::with_capacity(str_size); - let mut byte_buf = [u8::MAX; 1]; - for _ in 0..str_size { - buffer.read_exact(&mut byte_buf).map_err(LoadError::Io)?; - str_buf.push(byte_buf[0]); - } - //let size2 = buffer.read_to_string(&mut str_buf).map_err(LoadError::Io)?; - Ok(( - String::from_utf8(str_buf).map_err(|_| LoadError::InvalidData)?, - str_size + 4, - )) - } -} - -impl Loadable for Vec { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut u32_bytes: [u8; 4] = [u8::MAX; 4]; - buffer.read_exact(&mut u32_bytes).map_err(LoadError::Io)?; - let count = u32::from_le_bytes(u32_bytes) as usize; - let mut cursor = 4; - let mut items = Vec::with_capacity(count); - for _ in 0..count { - let (obj, len) = T::load(buffer)?; - cursor += len; - items.push(obj); - } - Ok((items, cursor)) - } -} - -impl Loadable for (T0, T1) { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let (t0, len0) = T0::load(buffer)?; - let (t1, len1) = T1::load(buffer)?; - Ok(((t0, t1), len0 + len1)) - } -} - -impl Loadable for (T0, T1, T2) { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let (t0, len0) = T0::load(buffer)?; - let (t1, len1) = T1::load(buffer)?; - let (t2, len2) = T2::load(buffer)?; - Ok(((t0, t1, t2), len0 + len1 + len2)) - } -} - -impl Loadable for (T0, T1, T2, T3) { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let (t0, len0) = T0::load(buffer)?; - let (t1, len1) = T1::load(buffer)?; - let (t2, len2) = T2::load(buffer)?; - let (t3, len3) = T3::load(buffer)?; - Ok(((t0, t1, t2, t3), len0 + len1 + len2 + len3)) - } -} - -impl Loadable - for (T0, T1, T2, T3, T4) -{ - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let (t0, len0) = T0::load(buffer)?; - let (t1, len1) = T1::load(buffer)?; - let (t2, len2) = T2::load(buffer)?; - let (t3, len3) = T3::load(buffer)?; - let (t4, len4) = T4::load(buffer)?; - Ok(((t0, t1, t2, t3, t4), len0 + len1 + len2 + len3 + len4)) - } -} - -impl Loadable for bool { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut byte = [u8::MAX; 1]; - buffer.read_exact(&mut byte).map_err(LoadError::Io)?; - Ok((byte[0] != 0, 1)) - } -} - -impl Loadable for u8 { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut byte = [u8::MAX; 1]; - buffer.read_exact(&mut byte).map_err(LoadError::Io)?; - Ok((byte[0], 1)) - } -} - -impl Loadable for i8 { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut byte = [u8::MAX; 1]; - buffer.read_exact(&mut byte).map_err(LoadError::Io)?; - Ok((i8::from_le_bytes(byte), 1)) - } -} - -macro_rules! int_impl { - ($type:ty, $size:literal) => { - impl Loadable for $type { - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut bytes: [u8; $size] = [u8::MAX; $size]; - buffer.read_exact(&mut bytes).map_err(LoadError::Io)?; - let i = <$type>::from_le_bytes(bytes); - Ok((i, $size)) - } - } - }; -} - -int_impl! {u16, 2} -int_impl! {u32, 4} -int_impl! {u64, 8} -int_impl! {u128, 16} - -int_impl! {i16, 2} -int_impl! {i32, 4} -int_impl! {i64, 8} -int_impl! {i128, 16} - -int_impl! {f32, 4} -int_impl! {f64, 8} - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Cursor; - - macro_rules! test_impl { - ($fn_name:ident, $data:expr, $type:ty, $expected_len:literal, $expected_load:expr) => { - #[test] - fn $fn_name() { - let buffer_data = $data; - let mut buffer = Vec::with_capacity(buffer_data.len()); - buffer.extend_from_slice(&buffer_data); - let (obj, read_len) = <$type>::load(&mut Cursor::new(buffer)).expect("Load not ok"); - assert_eq!(read_len, $expected_len, "Wrong amount read"); - assert_eq!(obj, $expected_load, "Loaded value not as expected"); - println!("Loaded {:?}", obj); - } - }; - } - - test_impl! {string_load_test, [4u8, 0, 0, 0, 116, 101, 115, 116, 0, 128], String, 8, "test"} - test_impl! { - vec_load_test, - [3u8, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 5, 0, 0, 0, 116, 101, 115, 116, 50], - Vec, - 26, - vec![ - "".to_string(), - "test1".to_string(), - "test2".to_string() - ] - } - - test_impl! {tuple2_load_test, [0, 1], (u8, u8), 2, (0, 1)} - - test_impl! {bool_true_load_test, [1], bool, 1, true} - test_impl! {bool_false_load_test, [0], bool, 1, false} - - // testing macro-generated code isn't particularly useful, but do it anyway - - test_impl! {u8_load_test, [42], u8, 1, 42u8} - test_impl! {u16_load_test, [42, 0], u16, 2, 42u16} - test_impl! {u32_load_test, [42, 0, 0, 0], u32, 4, 42u32} - test_impl! {u64_load_test, [42, 0, 0, 0, 0, 0, 0, 0], u64, 8, 42u64} - test_impl! {u128_load_test, [42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], u128, 16, 42u128} - - test_impl! {i8_load_test, [42], i8, 1, 42i8} - test_impl! {i16_load_test, [42, 0], i16, 2, 42i16} - test_impl! {i32_load_test, [42, 0, 0, 0], i32, 4, 42i32} - test_impl! {i64_load_test, [42, 0, 0, 0, 0, 0, 0, 0], i64, 8, 42i64} - test_impl! {i128_load_test, [42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], i128, 16, 42i128} - - test_impl! {f32_load_test, [0, 0, 40, 66], f32, 4, 42f32} - test_impl! {f64_load_test, [0, 0, 0, 0, 0, 0, 69, 64], f64, 8, 42f64} -} diff --git a/usdpl-core/src/serdes/mod.rs b/usdpl-core/src/serdes/mod.rs deleted file mode 100644 index f911e6d..0000000 --- a/usdpl-core/src/serdes/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Serialization and deserialization functionality. -//! Little endian is preferred. - -mod dump_impl; -mod load_impl; -mod primitive; -mod traits; - -pub use primitive::Primitive; -pub use traits::{DumpError, Dumpable, LoadError, Loadable}; diff --git a/usdpl-core/src/serdes/primitive.rs b/usdpl-core/src/serdes/primitive.rs deleted file mode 100644 index 9793bff..0000000 --- a/usdpl-core/src/serdes/primitive.rs +++ /dev/null @@ -1,163 +0,0 @@ -use super::{DumpError, Dumpable, LoadError, Loadable}; -use std::io::{Read, Write}; - -/// Primitive types supported for communication between the USDPL back- and front-end. -/// These are used for sending over the TCP connection. -pub enum Primitive { - /// Null or unsupported object - Empty, - /// String-like - String(String), - /// f32 - F32(f32), - /// f64 - F64(f64), - /// u32 - U32(u32), - /// u64 - U64(u64), - /// i32 - I32(i32), - /// i64 - I64(i64), - /// boolean - Bool(bool), - /// Non-primitive in Json format - Json(String), -} - -impl Primitive { - /// Discriminant -- first byte of a dumped primitive - const fn discriminant(&self) -> u8 { - match self { - Self::Empty => 1, - Self::String(_) => 2, - Self::F32(_) => 3, - Self::F64(_) => 4, - Self::U32(_) => 5, - Self::U64(_) => 6, - Self::I32(_) => 7, - Self::I64(_) => 8, - Self::Bool(_) => 9, - Self::Json(_) => 10, - } - } -} - -impl Loadable for Primitive { - fn load(buf: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut discriminant_buf = [u8::MAX; 1]; - buf.read_exact(&mut discriminant_buf) - .map_err(LoadError::Io)?; - let mut result: (Self, usize) = match discriminant_buf[0] { - //0 => (None, 0), - 1 => (Self::Empty, 0), - 2 => String::load(buf).map(|(obj, len)| (Self::String(obj), len))?, - 3 => f32::load(buf).map(|(obj, len)| (Self::F32(obj), len))?, - 4 => f64::load(buf).map(|(obj, len)| (Self::F64(obj), len))?, - 5 => u32::load(buf).map(|(obj, len)| (Self::U32(obj), len))?, - 6 => u64::load(buf).map(|(obj, len)| (Self::U64(obj), len))?, - 7 => i32::load(buf).map(|(obj, len)| (Self::I32(obj), len))?, - 8 => i64::load(buf).map(|(obj, len)| (Self::I64(obj), len))?, - 9 => bool::load(buf).map(|(obj, len)| (Self::Bool(obj), len))?, - 10 => String::load(buf).map(|(obj, len)| (Self::Json(obj), len))?, - _ => return Err(LoadError::InvalidData), - }; - result.1 += 1; - Ok(result) - } -} - -impl Dumpable for Primitive { - fn dump(&self, buf: &mut dyn Write) -> Result { - let size1 = buf.write(&[self.discriminant()]).map_err(DumpError::Io)?; - let result = match self { - Self::Empty => Ok(0), - Self::String(s) => s.dump(buf), - Self::F32(x) => x.dump(buf), - Self::F64(x) => x.dump(buf), - Self::U32(x) => x.dump(buf), - Self::U64(x) => x.dump(buf), - Self::I32(x) => x.dump(buf), - Self::I64(x) => x.dump(buf), - Self::Bool(x) => x.dump(buf), - Self::Json(x) => x.dump(buf), - }?; - Ok(size1 + result) - } -} - -impl std::convert::Into for &str { - fn into(self) -> Primitive { - Primitive::String(self.to_string()) - } -} - -impl std::convert::Into for () { - fn into(self) -> Primitive { - Primitive::Empty - } -} - -macro_rules! into_impl { - ($type:ty, $variant:ident) => { - impl std::convert::Into for $type { - fn into(self) -> Primitive { - Primitive::$variant(self) - } - } - }; -} - -into_impl! {String, String} -into_impl! {bool, Bool} - -into_impl! {u32, U32} -into_impl! {u64, U64} - -into_impl! {i32, I32} -into_impl! {i64, I64} - -into_impl! {f32, F32} -into_impl! {f64, F64} - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Cursor; - - #[test] - fn string_idempotence_test() { - let data = "Test"; - let primitive = Primitive::String(data.to_string()); - let mut buffer = Vec::with_capacity(128); - let write_len = primitive.dump(&mut buffer).expect("Dump not ok"); - let (obj, read_len) = Primitive::load(&mut Cursor::new(buffer)).expect("Load not ok"); - assert_eq!( - write_len, read_len, - "Amount written and amount read do not match" - ); - if let Primitive::String(result) = obj { - assert_eq!(data, result, "Data written and read does not match"); - } else { - panic!("Read non-string primitive"); - } - } - - #[test] - fn empty_idempotence_test() { - let primitive = Primitive::Empty; - let mut buffer = Vec::with_capacity(128); - let write_len = primitive.dump(&mut buffer).expect("Dump not ok"); - let (obj, read_len) = Primitive::load(&mut Cursor::new(buffer)).expect("Load not ok"); - assert_eq!( - write_len, read_len, - "Amount written and amount read do not match" - ); - if let Primitive::Empty = obj { - //assert_eq!(data, result, "Data written and read does not match"); - } else { - panic!("Read non-string primitive"); - } - } -} diff --git a/usdpl-core/src/serdes/traits.rs b/usdpl-core/src/serdes/traits.rs deleted file mode 100644 index b11b5db..0000000 --- a/usdpl-core/src/serdes/traits.rs +++ /dev/null @@ -1,150 +0,0 @@ -use base64::{decode_config_buf, encode_config_buf, Config}; -use std::io::{Cursor, Read, Write}; - -const B64_CONF: Config = Config::new(base64::CharacterSet::Standard, true); - -#[cfg(feature = "encrypt")] -const ASSOCIATED_DATA: &[u8] = b"usdpl-core-data"; - -#[cfg(feature = "encrypt")] -use aes_gcm_siv::aead::{AeadInPlace, NewAead}; - -/// Errors from Loadable::load -#[derive(Debug)] -pub enum LoadError { - /// Buffer smaller than expected - TooSmallBuffer, - /// Unexpected/corrupted data encountered - InvalidData, - /// Encrypted data cannot be decrypted - #[cfg(feature = "encrypt")] - DecryptionError, - /// Read error - Io(std::io::Error), - /// Unimplemented - #[cfg(debug_assertions)] - Todo, -} - -impl std::fmt::Display for LoadError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::TooSmallBuffer => write!(f, "LoadError: TooSmallBuffer"), - Self::InvalidData => write!(f, "LoadError: InvalidData"), - #[cfg(feature = "encrypt")] - Self::DecryptionError => write!(f, "LoadError: DecryptionError"), - Self::Io(err) => write!(f, "LoadError: Io({})", err), - #[cfg(debug_assertions)] - Self::Todo => write!(f, "LoadError: TODO!"), - } - } -} - -/// Load an object from the buffer -pub trait Loadable: Sized { - /// Read the buffer, building the object and returning the amount of bytes read. - /// If anything is wrong with the buffer, Err should be returned. - fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError>; - - /// Load data from a base64-encoded buffer - fn load_base64(buffer: &[u8]) -> Result<(Self, usize), LoadError> { - let mut buffer2 = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE); - decode_config_buf(buffer, B64_CONF, &mut buffer2).map_err(|_| LoadError::InvalidData)?; - let mut cursor = Cursor::new(buffer2); - Self::load(&mut cursor) - } - - /// Load data from an encrypted base64-encoded buffer - #[cfg(feature = "encrypt")] - fn load_encrypted(buffer: &[u8], key: &[u8], nonce: &[u8]) -> Result<(Self, usize), LoadError> { - //println!("encrypted buffer: {}", String::from_utf8(buffer.to_vec()).unwrap()); - let key = aes_gcm_siv::Key::from_slice(key); - let cipher = aes_gcm_siv::Aes256GcmSiv::new(key); - let nonce = aes_gcm_siv::Nonce::from_slice(nonce); - let mut decoded_buf = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE); - base64::decode_config_buf(buffer, B64_CONF, &mut decoded_buf) - .map_err(|_| LoadError::InvalidData)?; - //println!("Decoded buf: {:?}", decoded_buf); - cipher - .decrypt_in_place(nonce, ASSOCIATED_DATA, &mut decoded_buf) - .map_err(|_| LoadError::DecryptionError)?; - //println!("Decrypted buf: {:?}", decoded_buf); - let mut cursor = Cursor::new(decoded_buf); - Self::load(&mut cursor) - } -} - -/// Errors from Dumpable::dump -#[derive(Debug)] -pub enum DumpError { - /// Buffer not big enough to dump data into - TooSmallBuffer, - /// Data cannot be dumped - Unsupported, - /// Data cannot be encrypted - #[cfg(feature = "encrypt")] - EncryptionError, - /// Write error - Io(std::io::Error), - /// Unimplemented - #[cfg(debug_assertions)] - Todo, -} - -impl std::fmt::Display for DumpError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::TooSmallBuffer => write!(f, "DumpError: TooSmallBuffer"), - Self::Unsupported => write!(f, "DumpError: Unsupported"), - #[cfg(feature = "encrypt")] - Self::EncryptionError => write!(f, "DumpError: EncryptionError"), - Self::Io(err) => write!(f, "DumpError: Io({})", err), - #[cfg(debug_assertions)] - Self::Todo => write!(f, "DumpError: TODO!"), - } - } -} - -/// Dump an object into the buffer -pub trait Dumpable { - /// Write the object to the buffer, returning the amount of bytes written. - /// If anything is wrong, false should be returned. - fn dump(&self, buffer: &mut dyn Write) -> Result; - - /// Dump data as base64-encoded. - /// Useful for transmitting data as text. - fn dump_base64(&self, buffer: &mut String) -> Result { - let mut buffer2 = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE); - let len = self.dump(&mut buffer2)?; - encode_config_buf(&buffer2[..len], B64_CONF, buffer); - Ok(len) - } - - /// Dump data as an encrypted base64-encoded buffer - #[cfg(feature = "encrypt")] - fn dump_encrypted( - &self, - buffer: &mut Vec, - key: &[u8], - nonce: &[u8], - ) -> Result { - let mut buffer2 = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE); - let size = self.dump(&mut buffer2)?; - buffer2.truncate(size); - //println!("Buf: {:?}", buffer2); - let key = aes_gcm_siv::Key::from_slice(key); - let cipher = aes_gcm_siv::Aes256GcmSiv::new(key); - let nonce = aes_gcm_siv::Nonce::from_slice(nonce); - cipher - .encrypt_in_place(nonce, ASSOCIATED_DATA, &mut buffer2) - .map_err(|_| DumpError::EncryptionError)?; - //println!("Encrypted slice: {:?}", &buffer2); - let mut base64_buf = String::with_capacity(crate::socket::PACKET_BUFFER_SIZE); - encode_config_buf(buffer2.as_slice(), B64_CONF, &mut base64_buf); - //println!("base64 len: {}", base64_buf.as_bytes().len()); - buffer.extend_from_slice(base64_buf.as_bytes()); - //let string = String::from_utf8(buffer.as_slice().to_vec()).unwrap(); - //println!("Encoded slice: {}", string); - Ok(base64_buf.len()) - } -} diff --git a/usdpl-core/src/socket.rs b/usdpl-core/src/socket.rs deleted file mode 100644 index 6b8940e..0000000 --- a/usdpl-core/src/socket.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! Web messaging -use std::io::{Read, Write}; -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; - -use crate::serdes::{DumpError, Dumpable, LoadError, Loadable}; -use crate::{RemoteCall, RemoteCallResponse}; - -/// Host IP address for web browsers -pub const HOST_STR: &str = "localhost"; -/// Host IP address -pub const HOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); - -/// Standard max packet size -pub const PACKET_BUFFER_SIZE: usize = 1024; -/// Encryption nonce size -pub const NONCE_SIZE: usize = 12; - -/// Address and port -#[inline] -pub fn socket_addr(port: u16) -> SocketAddr { - SocketAddr::V4(SocketAddrV4::new(HOST, port)) -} - -/// Accepted Packet types and the data they contain -pub enum Packet { - /// A remote call - Call(RemoteCall), - /// A reponse to a remote call - CallResponse(RemoteCallResponse), - /// Unused - KeepAlive, - /// Invalid - Invalid, - /// General message - Message(String), - /// Response to an unsupported packet - Unsupported, - /// Broken packet type, useful for testing - Bad, - /// Many packets merged into one - Many(Vec), - /// Translation data dump - Translations(Vec<(String, Vec)>), - /// Request translations for language - Language(String), -} - -impl Packet { - /// Byte representing the packet type -- the first byte of any packet in USDPL - const fn discriminant(&self) -> u8 { - match self { - Self::Call(_) => 1, - Self::CallResponse(_) => 2, - Self::KeepAlive => 3, - Self::Invalid => 4, - Self::Message(_) => 5, - Self::Unsupported => 6, - Self::Bad => 7, - Self::Many(_) => 8, - Self::Translations(_) => 9, - Self::Language(_) => 10, - } - } -} - -impl Loadable for Packet { - fn load(buf: &mut dyn Read) -> Result<(Self, usize), LoadError> { - let mut discriminant_buf = [u8::MAX; 1]; - buf.read_exact(&mut discriminant_buf) - .map_err(LoadError::Io)?; - let mut result: (Self, usize) = match discriminant_buf[0] { - //0 => (None, 0), - 1 => { - let (obj, len) = RemoteCall::load(buf)?; - (Self::Call(obj), len) - } - 2 => { - let (obj, len) = RemoteCallResponse::load(buf)?; - (Self::CallResponse(obj), len) - } - 3 => (Self::KeepAlive, 0), - 4 => (Self::Invalid, 0), - 5 => { - let (obj, len) = String::load(buf)?; - (Self::Message(obj), len) - } - 6 => (Self::Unsupported, 0), - 7 => return Err(LoadError::InvalidData), - 8 => { - let (obj, len) = <_>::load(buf)?; - (Self::Many(obj), len) - } - 9 => { - let (obj, len) = <_>::load(buf)?; - (Self::Translations(obj), len) - } - 10 => { - let (obj, len) = <_>::load(buf)?; - (Self::Language(obj), len) - } - _ => return Err(LoadError::InvalidData), - }; - result.1 += 1; - Ok(result) - } -} - -impl Dumpable for Packet { - fn dump(&self, buf: &mut dyn Write) -> Result { - let size1 = buf.write(&[self.discriminant()]).map_err(DumpError::Io)?; - let result = match self { - Self::Call(c) => c.dump(buf), - Self::CallResponse(c) => c.dump(buf), - Self::KeepAlive => Ok(0), - Self::Invalid => Ok(0), - Self::Message(s) => s.dump(buf), - Self::Unsupported => Ok(0), - Self::Bad => return Err(DumpError::Unsupported), - Self::Many(v) => v.dump(buf), - Self::Translations(tr) => tr.dump(buf), - Self::Language(l) => l.dump(buf), - }?; - Ok(size1 + result) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(feature = "encrypt")] - #[test] - fn encryption_integration_test() { - let key = - hex_literal::hex!("59C4E408F27250B3147E7724511824F1D28ED7BEF43CF7103ACE747F77A2B265"); - let nonce = [0u8; NONCE_SIZE]; - let packet = Packet::Call(RemoteCall { - id: 42, - function: "test".into(), - parameters: Vec::new(), - }); - let mut buffer = Vec::with_capacity(PACKET_BUFFER_SIZE); - let len = packet.dump_encrypted(&mut buffer, &key, &nonce).unwrap(); - println!( - "buffer: {}", - String::from_utf8(buffer.as_slice()[..len].to_vec()).unwrap() - ); - - let (packet_out, _len) = - Packet::load_encrypted(&buffer.as_slice()[..len], &key, &nonce).unwrap(); - - if let Packet::Call(call_out) = packet_out { - if let Packet::Call(call_in) = packet { - assert_eq!( - call_in.id, call_out.id, - "Input and output packets do not match" - ); - assert_eq!( - call_in.function, call_out.function, - "Input and output packets do not match" - ); - assert_eq!( - call_in.parameters.len(), - call_out.parameters.len(), - "Input and output packets do not match" - ); - } else { - panic!("Packet in not a Call"); - } - } else { - panic!("Packet out not a Call!"); - } - } -} diff --git a/usdpl-front/Cargo.toml b/usdpl-front/Cargo.toml index 942c526..9dfc78c 100644 --- a/usdpl-front/Cargo.toml +++ b/usdpl-front/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "usdpl-front" version = "0.11.0" -authors = ["NGnius (Graham) "] +authors = ["NGnius "] edition = "2021" license = "GPL-3.0-only" -repository = "https://github.com/NGnius/usdpl-rs" +repository = "https://git.ngni.us/NG-SD-Plugins/usdpl-rs" readme = "../README.md" description = "Universal Steam Deck Plugin Library front-end designed for WASM" @@ -14,8 +14,8 @@ crate-type = ["cdylib", "rlib"] [features] default = [] decky = ["usdpl-core/decky"] -debug = ["console_error_panic_hook", "console_log"] -encrypt = ["usdpl-core/encrypt", "obfstr", "hex"] +debug = ["console_error_panic_hook"] +#encrypt = ["usdpl-core/encrypt", "obfstr", "hex"] [dependencies] wasm-bindgen = "0.2" @@ -23,7 +23,6 @@ wasm-bindgen-futures = "0.4" gloo-net = { version = "0.4", features = ["websocket"] } futures = "0.3" futures-channel = "0.3" -console_log = { version = "1.0", optional = true, features = ["color"] } # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires diff --git a/usdpl-front/src/client_handler.rs b/usdpl-front/src/client_handler.rs index 4f3c799..eff4991 100644 --- a/usdpl-front/src/client_handler.rs +++ b/usdpl-front/src/client_handler.rs @@ -32,23 +32,19 @@ async fn send_recv_ws<'a>(mut tx: futures_channel::mpsc::Sender { - #[cfg(feature = "debug")] - web_sys::console::debug_1(&format!("Got message to send over websocket").into()); + log::debug!("Got message to send over websocket"); if let Some(next) = next { match next { Ok(next) => { @@ -65,8 +61,7 @@ async fn send_recv_ws<'a>(mut tx: futures_channel::mpsc::Sender { - #[cfg(feature = "debug")] - web_sys::console::debug_1(&format!("Received message from websocket").into()); + log::debug!("Received message from websocket"); if let Some(next) = response { match next { Ok(Message::Bytes(b)) => tx.send(Ok(b.into())).await.unwrap_or(()), @@ -84,11 +79,9 @@ async fn send_recv_ws<'a>(mut tx: futures_channel::mpsc::Sender tx.send(Ok(b.into())).await.unwrap_or(()), Ok(_) => tx.send(Err("Message::Text not allowed".into())).await.unwrap_or(()), @@ -104,11 +97,9 @@ async fn send_recv_ws<'a>(mut tx: futures_channel::mpsc::Sender { if let Err(e) = ws_sink.send(Message::Bytes(next.into())).await { @@ -129,38 +120,7 @@ async fn send_recv_ws<'a>(mut tx: futures_channel::mpsc::Sender { - if let Err(e) = ws.send(Message::Bytes(next.into())).await { - tx2.send(Err(e.to_string())).await.unwrap_or(()); - } - }, - Err(e) => tx2.send(Err(e.to_string())).await.unwrap_or(()) - } - } else { - break; - } - } - }); - - spawn_local(async move { - while let State::Open = ws.state() { - if let Some(next) = ws.next().await { - match next { - Ok(Message::Bytes(b)) => tx.send(Ok(b.into())).await.unwrap_or(()), - Ok(_) => tx.send(Err("Message::Text not allowed".into())).await.unwrap_or(()), - Err(e) => tx.send(Err(e.to_string())).await.unwrap_or(()), - } - } else { - break; - } - } - });*/ + log::debug!("ws with url `{}` has closed", url); } #[derive(Debug)] @@ -197,8 +157,7 @@ impl ClientHandler<'static> for WebSocketHandler { "ws://usdpl-ws-{}.localhost:{}/{}.{}/{}", id, self.port, package, service, method, ); - #[cfg(feature = "debug")] - web_sys::console::log_1(&format!("doing send/receive on ws url `{}`", url).into()); + log::debug!("doing send/receive on ws url `{}`", url); let (tx, rx) = futures_channel::mpsc::channel(CHANNEL_BOUND); spawn_local(send_recv_ws(tx, url, input)); diff --git a/usdpl-front/src/connection.rs b/usdpl-front/src/connection.rs deleted file mode 100644 index 442e312..0000000 --- a/usdpl-front/src/connection.rs +++ /dev/null @@ -1,126 +0,0 @@ -//use std::net::TcpStream; -//use std::io::{Read, Write}; - -use wasm_bindgen::prelude::*; -use wasm_bindgen::JsCast; -use wasm_bindgen_futures::JsFuture; - -//use web_sys::{WebSocket, MessageEvent, ErrorEvent}; -use js_sys::JsString; -use web_sys::{Request, RequestInit, RequestMode, Response}; -//use wasm_rs_shared_channel::{Expects, spsc::{Receiver, Sender}}; - -use usdpl_core::serdes::{Dumpable, Loadable, Primitive}; -use usdpl_core::socket; - -#[cfg(feature = "encrypt")] -const NONCE: [u8; socket::NONCE_SIZE] = [0u8; socket::NONCE_SIZE]; - -pub async fn send_recv_packet( - id: u64, - packet: socket::Packet, - port: u16, - #[cfg(feature = "encrypt")] key: Vec, -) -> Result { - let mut opts = RequestInit::new(); - opts.method("POST"); - opts.mode(RequestMode::Cors); - - let url = format!( - "http://usdpl{}.{}:{}/usdpl/call", - id, - socket::HOST_STR, - port - ); - - #[allow(unused_variables)] - let (buffer, len) = dump_to_buffer( - packet, - #[cfg(feature = "encrypt")] - key.as_slice(), - )?; - let string: String = String::from_utf8_lossy(buffer.as_slice()).into(); - #[cfg(feature = "debug")] - crate::imports::console_log(&format!("Dumped base64 `{}` len:{}", string, len)); - opts.body(Some(&string.into())); - - let request = Request::new_with_str_and_init(&url, &opts)?; - - //request.headers().set("Accept", "text/base64")?; - //.set("Authorization", "wasm TODO_KEY")?; - - let window = web_sys::window().unwrap(); - let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?; - - let resp: Response = resp_value.dyn_into()?; - let text = JsFuture::from(resp.text()?).await?; - let string: JsString = text.dyn_into()?; - - let rust_str = string.as_string().unwrap(); - #[cfg(feature = "debug")] - crate::imports::console_log(&format!( - "Received base64 `{}` len:{}", - rust_str, - rust_str.len() - )); - - #[cfg(not(feature = "encrypt"))] - { - Ok(socket::Packet::load_base64(rust_str.as_bytes()) - .map_err(super::convert::str_to_js)? - .0) - } - - #[cfg(feature = "encrypt")] - { - Ok( - socket::Packet::load_encrypted(rust_str.as_bytes(), key.as_slice(), &NONCE) - .map_err(super::convert::str_to_js)? - .0, - ) - } -} - -pub async fn send_call( - id: u64, - packet: socket::Packet, - port: u16, - #[cfg(feature = "encrypt")] key: Vec, -) -> Result, JsValue> { - let packet = send_recv_packet( - id, - packet, - port, - #[cfg(feature = "encrypt")] - key, - ) - .await?; - - match packet { - socket::Packet::CallResponse(resp) => Ok(resp.response), - _ => { - //imports::console_warn(&format!("USDPL warning: Got non-call-response message from {}", resp.url())); - Err("Expected call response message, got something else".into()) - } - } -} - -#[cfg(feature = "encrypt")] -fn dump_to_buffer(packet: socket::Packet, key: &[u8]) -> Result<(Vec, usize), JsValue> { - let mut buffer = Vec::with_capacity(socket::PACKET_BUFFER_SIZE); - //buffer.extend_from_slice(&[0u8; socket::PACKET_BUFFER_SIZE]); - let len = packet - .dump_encrypted(&mut buffer, key, &NONCE) - .map_err(super::convert::str_to_js)?; - Ok((buffer, len)) -} - -#[cfg(not(feature = "encrypt"))] -fn dump_to_buffer(packet: socket::Packet) -> Result<(Vec, usize), JsValue> { - let mut buffer = String::with_capacity(socket::PACKET_BUFFER_SIZE); - //buffer.extend_from_slice(&[0u8; socket::PACKET_BUFFER_SIZE]); - let len = packet - .dump_base64(&mut buffer) - .map_err(super::convert::str_to_js)?; - Ok((buffer.as_bytes().to_vec(), len)) -} diff --git a/usdpl-front/src/console_logs.rs b/usdpl-front/src/console_logs.rs new file mode 100644 index 0000000..2b14974 --- /dev/null +++ b/usdpl-front/src/console_logs.rs @@ -0,0 +1,52 @@ +pub(crate) struct BuiltInLogger { + min_level: log::Level, +} + +impl BuiltInLogger { + pub const fn new(min: log::Level) -> Self { + Self { + min_level: min, + } + } +} + +impl log::Log for BuiltInLogger { + fn enabled(&self, metadata: &log::Metadata) -> bool { + metadata.level() <= self.min_level + } + + fn log(&self, record: &log::Record) { + if self.enabled(record.metadata()) { + match record.level() { + log::Level::Error => web_sys::console::error_1(&fmt_msg(record).into()), + log::Level::Warn => web_sys::console::warn_1(&fmt_msg(record).into()), + log::Level::Info => web_sys::console::log_1(&fmt_msg(record).into()), + log::Level::Debug => web_sys::console::debug_1(&fmt_msg(record).into()), + log::Level::Trace => web_sys::console::debug_1(&fmt_msg(record).into()), + } + } + } + + fn flush(&self) {} +} + +fn fmt_msg(record: &log::Record) -> String { + #[cfg(feature = "debug")] + { format!("[{}]({}) {}", record.level(), file_line_info(record), record.args()) } + #[cfg(not(feature = "debug"))] + { format!("[{}]({}) {}", record.level(), module_line_info(record), record.args()) } +} + +#[cfg(feature = "debug")] +fn file_line_info(record: &log::Record) -> String { + let filepath = record.file().unwrap_or(""); + let line = record.line().map(|l| l.to_string()).unwrap_or_else(|| "line?".to_string()); + format!("{}:{}", filepath, line) +} + +#[cfg(not(feature = "debug"))] +fn module_line_info(record: &log::Record) -> String { + let target = record.target(); + let line = record.line().map(|l| l.to_string()).unwrap_or_else(|| "line?".to_string()); + format!("{}:{}", target, line) +} diff --git a/usdpl-front/src/lib.rs b/usdpl-front/src/lib.rs index aa2fd5d..ebaf687 100644 --- a/usdpl-front/src/lib.rs +++ b/usdpl-front/src/lib.rs @@ -7,15 +7,10 @@ mod client_handler; pub use client_handler::WebSocketHandler; -//mod connection; +mod console_logs; mod convert; pub mod wasm; -/*#[allow(missing_docs)] // existence is pain otherwise -pub mod _nrpc_js_interop { - include!(concat!(env!("OUT_DIR"), "/mod.rs")); -}*/ - #[allow(missing_docs)] pub mod _helpers { pub use js_sys; @@ -26,21 +21,14 @@ pub mod _helpers { pub use nrpc; } -//use std::sync::atomic::{AtomicU64, Ordering}; - -//use js_sys::Array; use wasm_bindgen::prelude::*; -//use usdpl_core::{socket::Packet, RemoteCall}; -//const REMOTE_CALL_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); -//const REMOTE_PORT: std::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(31337); +#[cfg(feature = "debug")] +const DEFAULT_MIN_LEVEL: log::Level = log::Level::Trace; +#[cfg(not(feature = "debug"))] +const DEFAULT_MIN_LEVEL: log::Level = log::Level::Info; -/*static mut CTX: UsdplContext = UsdplContext { - port: 0, - //id: AtomicU64::new(0), - #[cfg(feature = "encrypt")] - key: Vec::new(), -};*/ +const DEFAULT_LOGGER: console_logs::BuiltInLogger = console_logs::BuiltInLogger::new(DEFAULT_MIN_LEVEL); static mut CACHE: Option> = None; @@ -51,56 +39,40 @@ fn encryption_key() -> Vec { hex::decode(obfstr::obfstr!(env!("USDPL_ENCRYPTION_KEY"))).unwrap() } -/* -//#[wasm_bindgen] -#[derive(Debug)] -struct UsdplContext { - port: u16, - id: AtomicU64, - #[cfg(feature = "encrypt")] - key: Vec, -} - -fn get_port() -> u16 { - unsafe { CTX.port } -} - -#[cfg(feature = "encrypt")] -fn get_key() -> Vec { - unsafe { CTX.key.clone() } -}*/ - -/*fn increment_id() -> u64 { - let atomic = unsafe { &CTX.id }; - atomic.fetch_add(1, Ordering::SeqCst) -}*/ +static INIT_DONE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); /// Initialize the front-end library -#[wasm_bindgen] -pub fn init_usdpl(port: u16) { - #[cfg(feature = "debug")] - web_sys::console::log_1(&format!("init_usdpl(port={})", port).into()); - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); - #[cfg(feature = "console_log")] - console_log::init_with_level(log::Level::Debug).expect("USDPL: error initializing console log"); +//#[wasm_bindgen] +pub fn init_usdpl() { + if !INIT_DONE.swap(true, std::sync::atomic::Ordering::SeqCst) { + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); - /*unsafe { - CTX = UsdplContext { - port: port, - //id: AtomicU64::new(0), - #[cfg(feature = "encrypt")] - key: encryption_key(), - }; - }*/ + log::set_logger(&DEFAULT_LOGGER) + .map_err(|e| web_sys::console::error_1(&format!("Failed to setup USDPL logger: {}", e).into())) + .unwrap_or(()); + log::set_max_level(log::LevelFilter::Trace); + log::debug!("init_usdpl() log configured"); - unsafe { - CACHE = Some(std::collections::HashMap::new()); + unsafe { + CACHE = Some(std::collections::HashMap::new()); + } + + log::info!("USDPL init succeeded: {}", build_info()); + } else { + log::info!("USDPL init was re-attempted"); } +} - #[cfg(feature = "debug")] - web_sys::console::log_1(&format!("USDPL:{} init succeeded", port).into()); - log::info!("USDPL:{} init succeeded", port); +fn build_info() -> String { + format!("{} v{} ({}) for {} by {}, more: {}", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION"), + env!("CARGO_PKG_LICENSE"), + target_usdpl(), + env!("CARGO_PKG_AUTHORS"), + env!("CARGO_PKG_REPOSITORY"), + ) } /// Get the targeted plugin framework, or "any" if unknown @@ -140,92 +112,6 @@ pub fn get_value(key: String) -> JsValue { } } -/* -/// Call a function on the back-end. -/// Returns null (None) if this fails for any reason. -#[wasm_bindgen] -pub async fn call_backend(name: String, parameters: Vec) -> JsValue { - #[cfg(feature = "debug")] - web_sys::console::log_1(&format!( - "call_backend({}, [params; {}])", - name, - parameters.len() - ).into()); - let next_id = increment_id(); - let mut params = Vec::with_capacity(parameters.len()); - for val in parameters { - params.push(convert::js_to_primitive(val)); - } - let port = get_port(); - #[cfg(feature = "debug")] - web_sys::console::log_1(&format!("USDPL: Got port {}", port).into()); - let results = connection::send_call( - next_id, - Packet::Call(RemoteCall { - id: next_id, - function: name.clone(), - parameters: params, - }), - port, - #[cfg(feature = "encrypt")] - get_key(), - ) - .await; - let results = match results { - Ok(x) => x, - #[allow(unused_variables)] - Err(e) => { - #[cfg(feature = "debug")] - web_sys::console::error_1(&format!("USDPL: Got error while calling {}: {:?}", name, e).into()); - return JsValue::NULL; - } - }; - let results_js = Array::new_with_length(results.len() as _); - let mut i = 0; - for item in results { - results_js.set(i as _, convert::primitive_to_js(item)); - i += 1; - } - results_js.into() -} - -/// Initialize translation strings for the front-end -#[wasm_bindgen] -pub async fn init_tr(locale: String) { - let next_id = increment_id(); - match connection::send_recv_packet( - next_id, - Packet::Language(locale.clone()), - get_port(), - #[cfg(feature = "encrypt")] - get_key(), - ) - .await - { - Ok(Packet::Translations(translations)) => { - #[cfg(feature = "debug")] - web_sys::console::log_1(&format!("USDPL: Got translations for {}", locale).into()); - // convert translations into map - let mut tr_map = std::collections::HashMap::with_capacity(translations.len()); - for (key, val) in translations { - tr_map.insert(key, val); - } - unsafe { TRANSLATIONS = Some(tr_map) } - } - Ok(_) => { - #[cfg(feature = "debug")] - web_sys::console::error_1(&format!("USDPL: Got wrong packet response for init_tr").into()); - unsafe { TRANSLATIONS = None } - } - #[allow(unused_variables)] - Err(e) => { - #[cfg(feature = "debug")] - web_sys::console::error_1(&format!("USDPL: Got wrong error for init_tr: {:#?}", e).into()); - unsafe { TRANSLATIONS = None } - } - } -}*/ - /// Translate a phrase, equivalent to tr_n(msg_id, 0) #[wasm_bindgen] pub fn tr(msg_id: String) -> String {