diff --git a/.github/workflows/msrv-check.yml b/.github/workflows/msrv-check.yml new file mode 100644 index 00000000..894ecffa --- /dev/null +++ b/.github/workflows/msrv-check.yml @@ -0,0 +1,53 @@ +name: Check MSRV + +on: + push: + branches: + - dev + paths: + - '.github/workflows/msrv-check.yml' + - 'plugins/*/src/**' + - '**/Cargo.toml' + - '**/Cargo.lock' + pull_request: + branches: + - dev + paths: + - '.github/workflows/msrv-check.yml' + - 'plugins/*/src/**' + - '**/Cargo.toml' + - '**/Cargo.lock' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + msrv: + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v3 + + - name: install webkit2gtk and libudev for [authenticator] + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.0 libudev-dev + + - uses: dtolnay/rust-toolchain@1.64.0 + + - uses: Swatinem/rust-cache@v2 + + - name: build + run: cargo build --workspace --exclude 'tauri-plugin-sql' --all-targets --all-features + + - name: build sql:sqlite + run: cargo build --package 'tauri-plugin-sql' --all-targets --features sqlite + + - name: build sql:mysql + run: cargo build --package 'tauri-plugin-sql' --all-targets --features mysql + + - name: build sql:postgres + run: cargo build --package 'tauri-plugin-sql' --all-targets --features postgres diff --git a/Cargo.lock b/Cargo.lock index ebd4ec1a..2e909ee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,7 +153,7 @@ dependencies = [ "slab", "socket2", "waker-fn", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1156,7 +1156,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1986,6 +1986,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "iota-crypto" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1d447f89ea13f2cd26d50195378bb2f76a0f9320ae4db3c0811b25fe6ed6c1" +dependencies = [ + "autocfg", +] + [[package]] name = "iota_stronghold" version = "1.0.5" @@ -1994,7 +2003,7 @@ checksum = "6c5baaa2460627283f54b968db7a38c9c754dc6059157cae64550ed1b79c91aa" dependencies = [ "bincode", "hkdf", - "iota-crypto", + "iota-crypto 0.15.3", "rust-argon2", "serde", "stronghold-derive", @@ -2384,7 +2393,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2506,7 +2515,7 @@ dependencies = [ "mio", "serde", "walkdir", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2631,6 +2640,15 @@ dependencies = [ "syn", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -2808,7 +2826,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -3020,7 +3038,7 @@ dependencies = [ "line-wrap", "quick-xml", "serde", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -3046,7 +3064,7 @@ dependencies = [ "libc", "log", "wepoll-ffi", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -3489,7 +3507,7 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -3901,6 +3919,7 @@ dependencies = [ "sqlx-rt", "stringprep", "thiserror", + "time 0.3.20", "tokio-stream", "url", "webpki-roots", @@ -4013,7 +4032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d93abb10fbd11335d31c33a70b2523c0caab348215caa2ce6da04a268c30afcb" dependencies = [ "dirs", - "iota-crypto", + "iota-crypto 0.15.3", "libc", "libsodium-sys", "log", @@ -4044,7 +4063,7 @@ dependencies = [ "anyhow", "dirs-next", "hex", - "iota-crypto", + "iota-crypto 0.15.3", "once_cell", "paste", "serde", @@ -4238,7 +4257,7 @@ dependencies = [ "sha2 0.10.6", "tauri-utils", "thiserror", - "time 0.3.17", + "time 0.3.20", "uuid 1.3.0", "walkdir", ] @@ -4336,7 +4355,7 @@ dependencies = [ "serde_json", "serde_repr", "tauri", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -4372,7 +4391,7 @@ dependencies = [ "serde_json", "tauri", "thiserror", - "windows-sys", + "windows-sys 0.45.0", "zbus", ] @@ -4380,13 +4399,14 @@ dependencies = [ name = "tauri-plugin-sql" version = "0.1.0" dependencies = [ - "futures", + "futures-core", "log", "serde", "serde_json", "sqlx", "tauri", "thiserror", + "time 0.3.20", "tokio", ] @@ -4406,7 +4426,7 @@ name = "tauri-plugin-stronghold" version = "0.1.0" dependencies = [ "hex", - "iota-crypto", + "iota-crypto 0.16.0", "iota_stronghold", "log", "rand 0.8.5", @@ -4612,11 +4632,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa 1.0.5", + "libc", + "num_threads", "serde", "time-core", "time-macros", @@ -4630,9 +4652,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] @@ -4678,7 +4700,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -5414,6 +5436,30 @@ dependencies = [ "windows_x86_64_msvc 0.42.1", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", +] + [[package]] name = "windows-tokens" version = "0.39.0" diff --git a/plugins/log/Cargo.toml b/plugins/log/Cargo.toml index 41a1457a..94ad25f0 100644 --- a/plugins/log/Cargo.toml +++ b/plugins/log/Cargo.toml @@ -17,7 +17,7 @@ serde_repr = "0.1" byte-unit = "4.0" fern = "0.6" log = { workspace = true, features = ["kv_unstable"] } -time = { version = "0.3", features = ["formatting"] } +time = { version = "0.3", features = ["formatting", "local-offset"] } [features] colored = ["fern/colored"] \ No newline at end of file diff --git a/plugins/log/src/lib.rs b/plugins/log/src/lib.rs index 2ab8ced9..5f40cab0 100644 --- a/plugins/log/src/lib.rs +++ b/plugins/log/src/lib.rs @@ -21,9 +21,11 @@ use tauri::{ }; pub use fern; +use time::OffsetDateTime; const DEFAULT_MAX_FILE_SIZE: u128 = 40000; const DEFAULT_ROTATION_STRATEGY: RotationStrategy = RotationStrategy::KeepOne; +const DEFAULT_TIMEZONE_STRATEGY: TimezoneStrategy = TimezoneStrategy::UseUtc; const DEFAULT_LOG_TARGETS: [LogTarget; 2] = [LogTarget::Stdout, LogTarget::LogDir]; /// An enum representing the available verbosity levels of the logger. @@ -83,6 +85,23 @@ pub enum RotationStrategy { KeepOne, } +#[derive(Debug, Clone)] +pub enum TimezoneStrategy { + UseUtc, + UseLocal, +} + +impl TimezoneStrategy { + pub fn get_now(&self) -> OffsetDateTime { + match self { + TimezoneStrategy::UseUtc => OffsetDateTime::now_utc(), + TimezoneStrategy::UseLocal => { + OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc()) + } // Fallback to UTC since Rust cannot determine local timezone + } + } +} + #[derive(Debug, Serialize, Clone)] struct RecordPayload { message: String, @@ -145,6 +164,7 @@ fn log( pub struct Builder { dispatch: fern::Dispatch, rotation_strategy: RotationStrategy, + timezone_strategy: TimezoneStrategy, max_file_size: u128, targets: Vec, } @@ -157,7 +177,7 @@ impl Default for Builder { let dispatch = fern::Dispatch::new().format(move |out, message, record| { out.finish(format_args!( "{}[{}][{}] {}", - time::OffsetDateTime::now_utc().format(&format).unwrap(), + DEFAULT_TIMEZONE_STRATEGY.get_now().format(&format).unwrap(), record.target(), record.level(), message @@ -166,6 +186,7 @@ impl Default for Builder { Self { dispatch, rotation_strategy: DEFAULT_ROTATION_STRATEGY, + timezone_strategy: DEFAULT_TIMEZONE_STRATEGY, max_file_size: DEFAULT_MAX_FILE_SIZE, targets: DEFAULT_LOG_TARGETS.into(), } @@ -182,6 +203,24 @@ impl Builder { self } + pub fn timezone_strategy(mut self, timezone_strategy: TimezoneStrategy) -> Self { + self.timezone_strategy = timezone_strategy.clone(); + + let format = + time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]") + .unwrap(); + self.dispatch = fern::Dispatch::new().format(move |out, message, record| { + out.finish(format_args!( + "{}[{}][{}] {}", + timezone_strategy.get_now().format(&format).unwrap(), + record.target(), + record.level(), + message + )) + }); + self + } + pub fn max_file_size(mut self, max_file_size: u128) -> Self { self.max_file_size = max_file_size; self @@ -228,10 +267,12 @@ impl Builder { let format = time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]") .unwrap(); + + let timezone_strategy = self.timezone_strategy.clone(); self.format(move |out, message, record| { out.finish(format_args!( "{}[{}][{}] {}", - time::OffsetDateTime::now_utc().format(&format).unwrap(), + timezone_strategy.get_now().format(&format).unwrap(), record.target(), colors.color(record.level()), message @@ -259,6 +300,7 @@ impl Builder { &path, app_name, &self.rotation_strategy, + &self.timezone_strategy, self.max_file_size, )?)? .into() @@ -273,6 +315,7 @@ impl Builder { &path, app_name, &self.rotation_strategy, + &self.timezone_strategy, self.max_file_size, )?)? .into() @@ -306,6 +349,7 @@ fn get_log_file_path( dir: &impl AsRef, app_name: &str, rotation_strategy: &RotationStrategy, + timezone_strategy: &TimezoneStrategy, max_file_size: u128, ) -> plugin::Result { let path = dir.as_ref().join(format!("{app_name}.log")); @@ -318,7 +362,8 @@ fn get_log_file_path( let to = dir.as_ref().join(format!( "{}_{}.log", app_name, - time::OffsetDateTime::now_utc() + timezone_strategy + .get_now() .format( &time::format_description::parse( "[year]-[month]-[day]_[hour]-[minute]-[second]" diff --git a/plugins/single-instance/Cargo.toml b/plugins/single-instance/Cargo.toml index 4762e033..d57ff092 100644 --- a/plugins/single-instance/Cargo.toml +++ b/plugins/single-instance/Cargo.toml @@ -18,7 +18,7 @@ log.workspace = true thiserror.workspace = true [target.'cfg(target_os = "windows")'.dependencies.windows-sys] -version = "0.42" +version = "0.45" features = [ "Win32_System_Threading", "Win32_System_DataExchange", diff --git a/plugins/single-instance/README.md b/plugins/single-instance/README.md index 1efbba90..595d6b17 100644 --- a/plugins/single-instance/README.md +++ b/plugins/single-instance/README.md @@ -1,4 +1,4 @@ -![tauri-plugin-single-instance](banner.jpg) +![tauri-plugin-single-instance](banner.png) Ensure a single instance of your tauri app is running. @@ -38,7 +38,7 @@ struct Payload { fn main() { tauri::Builder::default() - .plugin(auri_plugin_single_instance::init(|app, argv, cwd| { + .plugin(tauri_plugin_single_instance::init(|app, argv, cwd| { println!("{}, {argv:?}, {cwd}", app.package_info().name); app.emit_all("single-instance", Payload { args: argv, cwd }).unwrap(); diff --git a/plugins/sql/Cargo.toml b/plugins/sql/Cargo.toml index c72e237c..502cd12c 100644 --- a/plugins/sql/Cargo.toml +++ b/plugins/sql/Cargo.toml @@ -15,9 +15,10 @@ serde_json.workspace = true tauri.workspace = true log.workspace = true thiserror.workspace = true -sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "json"] } +futures-core = "0.3" +sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "json", "time"] } +time = "0.3" tokio = { version = "1", features = ["sync"] } -futures = "0.3" [features] sqlite = ["sqlx/sqlite"] diff --git a/plugins/sql/src/decode/mod.rs b/plugins/sql/src/decode/mod.rs new file mode 100644 index 00000000..415c99b8 --- /dev/null +++ b/plugins/sql/src/decode/mod.rs @@ -0,0 +1,15 @@ +#[cfg(feature = "mysql")] +mod mysql; +#[cfg(feature = "postgres")] +mod postgres; +#[cfg(feature = "sqlite")] +mod sqlite; + +#[cfg(feature = "mysql")] +pub(crate) use mysql::to_json; + +#[cfg(feature = "postgres")] +pub(crate) use postgres::to_json; + +#[cfg(feature = "sqlite")] +pub(crate) use sqlite::to_json; diff --git a/plugins/sql/src/decode/mysql.rs b/plugins/sql/src/decode/mysql.rs new file mode 100644 index 00000000..e68bd1ac --- /dev/null +++ b/plugins/sql/src/decode/mysql.rs @@ -0,0 +1,90 @@ +use serde_json::Value as JsonValue; +use sqlx::{mysql::MySqlValueRef, TypeInfo, Value, ValueRef}; +use time::{Date, OffsetDateTime, PrimitiveDateTime, Time}; + +use crate::Error; + +pub(crate) fn to_json(v: MySqlValueRef) -> Result { + if v.is_null() { + return Ok(JsonValue::Null); + } + + let res = match v.type_info().name() { + "CHAR" | "VARCHAR" | "TINYTEXT" | "TEXT" | "MEDIUMTEXT" | "LONGTEXT" | "ENUM" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode() { + JsonValue::String(v) + } else { + JsonValue::Null + } + } + "FLOAT" | "DOUBLE" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode::() { + JsonValue::from(v) + } else { + JsonValue::Null + } + } + "TINYINT" | "SMALLINT" | "INT" | "MEDIUMINT" | "BIGINT" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode::() { + JsonValue::Number(v.into()) + } else { + JsonValue::Null + } + } + "TINYINT UNSIGNED" | "SMALLINT UNSIGNED" | "INT UNSIGNED" | "MEDIUMINT UNSIGNED" + | "BIGINT UNSIGNED" | "YEAR" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode::() { + JsonValue::Number(v.into()) + } else { + JsonValue::Null + } + } + "BOOLEAN" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode() { + JsonValue::Bool(v) + } else { + JsonValue::Null + } + } + "DATE" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode::() { + JsonValue::String(v.to_string()) + } else { + JsonValue::Null + } + } + "TIME" => { + if let Ok(v) = ValueRef::to_owned(&v).try_decode::