diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 7f1c3dc4..446f4693 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + [[package]] name = "addr2line" version = "0.24.2" @@ -85,12 +91,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aligned-vec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" - [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -133,6 +133,15 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arbitrary" version = "1.4.1" @@ -150,7 +159,7 @@ checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "core-graphics 0.23.2", - "image", + "image 0.25.5", "log", "objc2", "objc2-app-kit", @@ -166,17 +175,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" -[[package]] -name = "arg_enum_proc_macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "arrayvec" version = "0.7.6" @@ -495,29 +493,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "av1-grain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" -dependencies = [ - "anyhow", - "arrayvec", - "log", - "nom 7.1.3", - "num-rational", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" -dependencies = [ - "arrayvec", -] - [[package]] name = "axum" version = "0.6.20" @@ -617,12 +592,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitstream-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" - [[package]] name = "block" version = "0.1.6" @@ -725,7 +694,7 @@ dependencies = [ "static_assertions", "tap", "thin-vec", - "thiserror 2.0.3", + "thiserror 2.0.9", "time", ] @@ -829,12 +798,6 @@ dependencies = [ "alloc-stdlib", ] -[[package]] -name = "built" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" - [[package]] name = "bumpalo" version = "3.16.0" @@ -875,9 +838,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1058,8 +1021,10 @@ dependencies = [ "delay_timer", "dirs 5.0.1", "dunce", + "futures", "getrandom 0.2.15", - "image", + "image 0.24.9", + "imageproc", "log", "log4rs", "nanoid", @@ -1072,6 +1037,7 @@ dependencies = [ "reqwest", "reqwest_dav", "runas", + "rusttype", "serde", "serde_json", "serde_yaml", @@ -1092,6 +1058,7 @@ dependencies = [ "tauri-plugin-updater", "tauri-plugin-window-state", "tokio", + "tokio-tungstenite 0.26.1", "url", "users", "warp", @@ -1240,6 +1207,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "conv" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +dependencies = [ + "custom_derive", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -1471,6 +1447,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "custom_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" + [[package]] name = "darling" version = "0.20.10" @@ -3173,6 +3155,24 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-traits", + "png", + "qoi", + "tiff", +] + [[package]] name = "image" version = "0.25.5" @@ -3181,37 +3181,29 @@ checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", - "color_quant", - "exr", - "gif", - "image-webp", "num-traits", "png", - "qoi", - "ravif", - "rayon", - "rgb", "tiff", - "zune-core", - "zune-jpeg", ] [[package]] -name = "image-webp" -version = "0.2.0" +name = "imageproc" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +checksum = "b6aee993351d466301a29655d628bfc6f5a35a0d062b6160ca0808f425805fd7" dependencies = [ - "byteorder-lite", - "quick-error", + "approx", + "conv", + "image 0.24.9", + "itertools 0.10.5", + "nalgebra", + "num", + "rand 0.7.3", + "rand_distr", + "rayon", + "rusttype", ] -[[package]] -name = "imgref" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" - [[package]] name = "indexmap" version = "1.9.3" @@ -3277,17 +3269,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "intrusive-collections" version = "0.9.7" @@ -3344,6 +3325,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -3433,6 +3423,9 @@ name = "jpeg-decoder" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +dependencies = [ + "rayon", +] [[package]] name = "js-sys" @@ -3531,16 +3524,6 @@ version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" -[[package]] -name = "libfuzzer-sys" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" -dependencies = [ - "arbitrary", - "cc", -] - [[package]] name = "libloading" version = "0.7.4" @@ -3661,15 +3644,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "loop9" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" -dependencies = [ - "imgref", -] - [[package]] name = "lru" version = "0.7.8" @@ -3753,13 +3727,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] -name = "maybe-rayon" -version = "0.1.1" +name = "matrixmultiply" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ - "cfg-if", - "rayon", + "autocfg", + "rawpointer", ] [[package]] @@ -3890,6 +3864,21 @@ dependencies = [ "version_check", ] +[[package]] +name = "nalgebra" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb2d0de08694bed883320212c18ee3008576bfe8c306f4c3c4a58b4876998be" +dependencies = [ + "approx", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + [[package]] name = "nanoid" version = "0.4.0" @@ -4042,12 +4031,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "noop_proc_macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" - [[package]] name = "notify-rust" version = "4.11.3" @@ -4080,6 +4063,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -4091,6 +4088,15 @@ dependencies = [ "serde", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -4108,17 +4114,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -4128,6 +4123,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -4563,6 +4569,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "owned_ttf_parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb" +dependencies = [ + "ttf-parser", +] + [[package]] name = "pango" version = "0.18.3" @@ -5068,25 +5083,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "profiling" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" -dependencies = [ - "quote", - "syn 2.0.90", -] - [[package]] name = "prost" version = "0.12.6" @@ -5174,7 +5170,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2 0.5.7", - "thiserror 2.0.3", + "thiserror 2.0.9", "tokio", "tracing", ] @@ -5193,7 +5189,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.3", + "thiserror 2.0.9", "tinyvec", "tracing", "web-time", @@ -5285,6 +5281,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_distr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" +dependencies = [ + "rand 0.7.3", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -5303,56 +5308,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rav1e" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" -dependencies = [ - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av1-grain", - "bitstream-io", - "built", - "cfg-if", - "interpolate_name", - "itertools 0.12.1", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive 0.4.2", - "num-traits", - "once_cell", - "paste", - "profiling", - "rand 0.8.5", - "rand_chacha 0.3.1", - "simd_helpers", - "system-deps", - "thiserror 1.0.69", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rayon", - "rgb", -] - [[package]] name = "raw-window-handle" version = "0.5.2" @@ -5365,6 +5320,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.10.0" @@ -5552,12 +5513,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rgb" -version = "0.8.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" - [[package]] name = "ring" version = "0.17.8" @@ -5712,6 +5667,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rusttype" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff8374aa04134254b7995b63ad3dc41c7f7236f69528b28553da7d72efaa967" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + [[package]] name = "rustversion" version = "1.0.18" @@ -5730,6 +5695,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -6144,21 +6118,25 @@ dependencies = [ "libc", ] +[[package]] +name = "simba" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "simd-adler32" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -[[package]] -name = "simd_helpers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" -dependencies = [ - "quote", -] - [[package]] name = "siphasher" version = "0.3.11" @@ -6539,7 +6517,7 @@ dependencies = [ "heck 0.5.0", "http 1.1.0", "http-range", - "image", + "image 0.25.5", "jni", "libc", "log", @@ -6562,7 +6540,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.9", "tokio", "tracing", "tray-icon", @@ -6616,7 +6594,7 @@ dependencies = [ "sha2 0.10.8", "syn 2.0.90", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.9", "time", "url", "uuid", @@ -6665,7 +6643,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.3", + "thiserror 2.0.9", ] [[package]] @@ -6680,7 +6658,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.3", + "thiserror 2.0.9", ] [[package]] @@ -6696,7 +6674,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.9", "tracing", "url", "windows-registry 0.3.0", @@ -6744,7 +6722,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.3", + "thiserror 2.0.9", "url", ] @@ -6765,7 +6743,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.9", "toml 0.8.19", "url", "uuid", @@ -6783,7 +6761,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.3", + "thiserror 2.0.9", ] [[package]] @@ -6800,7 +6778,7 @@ dependencies = [ "serde_repr", "tauri", "tauri-plugin", - "thiserror 2.0.3", + "thiserror 2.0.9", "time", "url", ] @@ -6832,7 +6810,7 @@ dependencies = [ "shared_child", "tauri", "tauri-plugin", - "thiserror 2.0.3", + "thiserror 2.0.9", "tokio", ] @@ -6858,7 +6836,7 @@ dependencies = [ "tauri", "tauri-plugin", "tempfile", - "thiserror 2.0.3", + "thiserror 2.0.9", "time", "tokio", "url", @@ -6878,7 +6856,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.3", + "thiserror 2.0.9", ] [[package]] @@ -6895,7 +6873,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.9", "url", "windows 0.58.0", ] @@ -6956,7 +6934,7 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.3", + "thiserror 2.0.9", "toml 0.8.19", "url", "urlpattern", @@ -7047,7 +7025,7 @@ dependencies = [ "libc", "log", "memmem", - "num-derive 0.3.3", + "num-derive", "num-traits", "ordered-float", "regex", @@ -7086,11 +7064,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.9", ] [[package]] @@ -7106,9 +7084,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", @@ -7295,7 +7273,19 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.21.0", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4bf6fecd69fcdede0ec680aaf474cdab988f9de6bc73d3758f0160e3b7025a" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.26.1", ] [[package]] @@ -7586,6 +7576,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "ttf-parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" + [[package]] name = "tungstenite" version = "0.21.0" @@ -7605,6 +7601,24 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 2.0.9", + "utf-8", +] + [[package]] name = "typeid" version = "1.0.2" @@ -7801,17 +7815,6 @@ dependencies = [ "serde", ] -[[package]] -name = "v_frame" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" -dependencies = [ - "aligned-vec", - "num-traits", - "wasm-bindgen", -] - [[package]] name = "valuable" version = "0.1.0" @@ -7913,7 +7916,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.21.0", "tokio-util", "tower-service", "tracing", @@ -8198,6 +8201,16 @@ dependencies = [ "rustix 0.38.41", ] +[[package]] +name = "wide" +version = "0.7.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e6db2670d2be78525979e9a5f9c69d296fd7d670549fe9ebf70f8708cb5019" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" @@ -9141,12 +9154,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - [[package]] name = "zune-inflate" version = "0.2.54" @@ -9156,15 +9163,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "zune-jpeg" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768" -dependencies = [ - "zune-core", -] - [[package]] name = "zvariant" version = "4.2.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index da3ab24d..4d7441c0 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -39,7 +39,9 @@ tokio = { version = "1", features = ["full"] } serde = { version = "1.0", features = ["derive"] } reqwest = { version = "0.12", features = ["json", "rustls-tls"] } sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs", rev = "3d748b5" } -image = "0.25.5" +image = "0.24" +imageproc = "0.23" +rusttype = "0.9" tauri = { version = "2.1.1", features = [ "protocol-asset", "devtools", @@ -62,6 +64,8 @@ reqwest_dav = "0.1.14" aes-gcm = { version = "0.10.3", features = ["std"] } base64 = "0.22.1" getrandom = "0.2" +tokio-tungstenite = "0.26.1" +futures = "0.3" [target.'cfg(windows)'.dependencies] runas = "=1.2.0" diff --git a/src-tauri/assets/fonts/SFCompact.ttf b/src-tauri/assets/fonts/SFCompact.ttf new file mode 100644 index 00000000..13d4d606 Binary files /dev/null and b/src-tauri/assets/fonts/SFCompact.ttf differ diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 00b25fcf..20a12a3f 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -73,7 +73,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult { match CoreManager::global().update_config().await { Ok(_) => { handle::Handle::refresh_clash(); - let _ = handle::Handle::update_systray_tooltip(); + let _ = tray::Tray::global().update_tooltip(); Config::profiles().apply(); wrap_err!(Config::profiles().data().save_file())?; Ok(()) diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index 71ef53bd..89412b2c 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -156,17 +156,20 @@ impl IClashTemp { } pub fn guard_mixed_port(config: &Mapping) -> u16 { - let mut port = config - .get("mixed-port") + let raw_value = config.get("mixed-port"); + + let mut port = raw_value .and_then(|value| match value { Value::String(val_str) => val_str.parse().ok(), Value::Number(val_num) => val_num.as_u64().map(|u| u as u16), _ => None, }) .unwrap_or(7897); + if port == 0 { port = 7897; } + port } diff --git a/src-tauri/src/core/clash_api.rs b/src-tauri/src/core/clash_api.rs index 8d114676..55e6a633 100644 --- a/src-tauri/src/core/clash_api.rs +++ b/src-tauri/src/core/clash_api.rs @@ -123,6 +123,12 @@ pub fn parse_check_output(log: String) -> String { log } +pub fn get_traffic_ws_url() -> Result { + let (url, _) = clash_client_info()?; + let ws_url = url.replace("http://", "ws://") + "/traffic"; + Ok(ws_url) +} + #[test] fn test_parse_check_output() { let str1 = r#"xxxx\n time="2022-11-18T20:42:58+08:00" level=error msg="proxy 0: 'alpn' expected type 'string', got unconvertible type '[]interface {}'""#; diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index ae3d71d3..d9bfe3fe 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -76,7 +76,6 @@ impl CoreManager { service::stop_core_by_service().await?; } *running = false; - Ok(()) } @@ -96,6 +95,7 @@ impl CoreManager { service::run_core_by_service(&config_path).await?; *running = true; } + Ok(()) } diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index abb735a6..eef12f0c 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -1,6 +1,4 @@ -use super::tray::Tray; use crate::log_err; -use anyhow::Result; use once_cell::sync::OnceCell; use parking_lot::RwLock; use std::sync::Arc; @@ -65,27 +63,6 @@ impl Handle { } } - /// update the system tray state - pub fn update_systray_part() -> Result<()> { - Tray::update_part()?; - Ok(()) - } - - pub fn update_systray_menu() -> Result<()> { - Tray::update_menu()?; - Ok(()) - } - - pub fn update_systray_icon() -> Result<()> { - Tray::update_icon()?; - Ok(()) - } - - pub fn update_systray_tooltip() -> Result<()> { - Tray::update_tooltip()?; - Ok(()) - } - pub fn set_is_exiting(&self) { let mut is_exiting = self.is_exiting.write(); *is_exiting = true; diff --git a/src-tauri/src/core/tray.rs b/src-tauri/src/core/tray/mod.rs similarity index 77% rename from src-tauri/src/core/tray.rs rename to src-tauri/src/core/tray/mod.rs index 3d551823..70168be5 100644 --- a/src-tauri/src/core/tray.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -1,3 +1,7 @@ +pub mod speed_rate; +use speed_rate::Rate; +pub use speed_rate::{SpeedRate, Traffic}; + use crate::utils::dirs; use crate::{ cmds, @@ -6,6 +10,10 @@ use crate::{ utils::resolve::{self, VERSION}, }; use anyhow::Result; +use futures::StreamExt; +use once_cell::sync::OnceCell; +use parking_lot::{Mutex, RwLock}; +use std::sync::Arc; use tauri::AppHandle; use tauri::{ menu::CheckMenuItem, @@ -15,12 +23,33 @@ use tauri::{ menu::{MenuEvent, MenuItem, PredefinedMenuItem, Submenu}, Wry, }; +use tokio::sync::broadcast; use super::handle; -pub struct Tray {} +pub struct Tray { + pub speed_rate: Arc>>, + #[cfg(target_os = "macos")] + shutdown_tx: Arc>>>, +} impl Tray { - pub fn create_systray() -> Result<()> { + pub fn global() -> &'static Tray { + static TRAY: OnceCell = OnceCell::new(); + + TRAY.get_or_init(|| Tray { + speed_rate: Arc::new(Mutex::new(None)), + #[cfg(target_os = "macos")] + shutdown_tx: Arc::new(RwLock::new(None)), + }) + } + + pub fn init(&self) -> Result<()> { + let mut speed_rate = self.speed_rate.lock(); + *speed_rate = Some(SpeedRate::new()); + Ok(()) + } + + pub fn create_systray(&self) -> Result<()> { let app_handle = handle::Handle::global().app_handle().unwrap(); let tray_incon_id = TrayIconId::new("main"); let tray = app_handle.tray_by_id(&tray_incon_id).unwrap(); @@ -64,7 +93,7 @@ impl Tray { } /// 更新托盘菜单 - pub fn update_menu() -> Result<()> { + pub fn update_menu(&self) -> Result<()> { let app_handle = handle::Handle::global().app_handle().unwrap(); let verge = Config::verge().latest().clone(); let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false); @@ -91,7 +120,7 @@ impl Tray { } /// 更新托盘图标 - pub fn update_icon() -> Result<()> { + pub fn update_icon(&self, rate: Option) -> Result<()> { let app_handle = handle::Handle::global().app_handle().unwrap(); let verge = Config::verge().latest().clone(); let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false); @@ -109,12 +138,12 @@ impl Tray { let icon_bytes = if *system_proxy && !*tun_mode { #[cfg(target_os = "macos")] let mut icon = match tray_icon.as_str() { - "colorful" => include_bytes!("../../icons/tray-icon-sys.ico").to_vec(), - _ => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(), + "colorful" => include_bytes!("../../../icons/tray-icon-sys.ico").to_vec(), + _ => include_bytes!("../../../icons/tray-icon-sys-mono.ico").to_vec(), }; #[cfg(not(target_os = "macos"))] - let mut icon = include_bytes!("../../icons/tray-icon-sys.ico").to_vec(); + let mut icon = include_bytes!("../../../icons/tray-icon-sys.ico").to_vec(); if *sysproxy_tray_icon { let icon_dir_path = dirs::app_home_dir()?.join("icons"); let png_path = icon_dir_path.join("sysproxy.png"); @@ -129,8 +158,8 @@ impl Tray { } else if *tun_mode { #[cfg(target_os = "macos")] let mut icon = match tray_icon.as_str() { - "colorful" => include_bytes!("../../icons/tray-icon-tun.ico").to_vec(), - _ => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(), + "colorful" => include_bytes!("../../../icons/tray-icon-tun.ico").to_vec(), + _ => include_bytes!("../../../icons/tray-icon-tun-mono.ico").to_vec(), }; #[cfg(not(target_os = "macos"))] @@ -149,8 +178,8 @@ impl Tray { } else { #[cfg(target_os = "macos")] let mut icon = match tray_icon.as_str() { - "colorful" => include_bytes!("../../icons/tray-icon.ico").to_vec(), - _ => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(), + "colorful" => include_bytes!("../../../icons/tray-icon.ico").to_vec(), + _ => include_bytes!("../../../icons/tray-icon-mono.ico").to_vec(), }; #[cfg(not(target_os = "macos"))] @@ -172,6 +201,14 @@ impl Tray { { let is_template = crate::utils::help::is_monochrome_image_from_bytes(&icon_bytes).unwrap_or(false); + // 如果rate为None,获取当前速率 + let rate = rate.or_else(|| { + self.speed_rate + .lock() + .as_ref() + .and_then(|speed_rate| speed_rate.get_curent_rate()) + }); + let icon_bytes = SpeedRate::add_speed_text(icon_bytes, rate)?; let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)); let _ = tray.set_icon_as_template(is_template); } @@ -183,7 +220,7 @@ impl Tray { } /// 更新托盘提示 - pub fn update_tooltip() -> Result<()> { + pub fn update_tooltip(&self) -> Result<()> { let app_handle = handle::Handle::global().app_handle().unwrap(); let use_zh = { Config::verge().latest().language == Some("zh".into()) }; let version = VERSION.get().unwrap(); @@ -223,12 +260,55 @@ impl Tray { Ok(()) } - pub fn update_part() -> Result<()> { - Self::update_menu()?; - Self::update_icon()?; - Self::update_tooltip()?; + pub fn update_part(&self) -> Result<()> { + self.update_menu()?; + self.update_icon(None)?; + self.update_tooltip()?; Ok(()) } + + /// 订阅流量数据 + #[cfg(target_os = "macos")] + pub async fn subscribe_traffic(&self) -> Result<()> { + log::info!(target: "app", "subscribe traffic"); + let (shutdown_tx, shutdown_rx) = broadcast::channel(1); + *self.shutdown_tx.write() = Some(shutdown_tx); + + let speed_rate = Arc::clone(&self.speed_rate); + + tauri::async_runtime::spawn(async move { + let mut shutdown = shutdown_rx; + if let Ok(mut stream) = Traffic::get_traffic_stream().await { + loop { + tokio::select! { + Some(traffic) = stream.next() => { + if let Ok(traffic) = traffic { + let guard = speed_rate.lock(); + if let Some(sr) = guard.as_ref() { + if let Some(rate) = sr.update_and_check_changed(traffic.up, traffic.down) { + let _ = Tray::global().update_icon(Some(rate)); + } + } + } + } + _ = shutdown.recv() => break, + } + } + } + }); + + Ok(()) + } + + /// 取消订阅 traffic 数据 + #[cfg(target_os = "macos")] + #[allow(unused)] + pub fn unsubscribe_traffic(&self) { + log::info!(target: "app", "unsubscribe traffic"); + if let Some(tx) = self.shutdown_tx.write().take() { + drop(tx); // 发送端被丢弃时会自动发送关闭信号 + } + } } fn create_tray_menu( diff --git a/src-tauri/src/core/tray/speed_rate.rs b/src-tauri/src/core/tray/speed_rate.rs new file mode 100644 index 00000000..447440f4 --- /dev/null +++ b/src-tauri/src/core/tray/speed_rate.rs @@ -0,0 +1,189 @@ +use crate::core::clash_api::get_traffic_ws_url; +use crate::utils::help::format_bytes_speed; +use anyhow::Result; +use futures::Stream; +use image::{ImageBuffer, Rgba}; +use imageproc::drawing::draw_text_mut; +use parking_lot::Mutex; +use rusttype::{Font, Scale}; +use std::io::Cursor; +use std::sync::Arc; +use tokio_tungstenite::tungstenite::Message; + +#[derive(Debug, Clone, Default, PartialEq)] +pub struct Rate { + pub up: u64, + pub down: u64, +} + +#[derive(Debug, Clone)] +pub struct SpeedRate { + rate: Arc>, +} + +impl SpeedRate { + pub fn new() -> Self { + Self { + rate: Arc::new(Mutex::new((Rate::default(), Rate::default()))), + } + } + + /// 更新流量数据并返回变化后的速率(如果有变化) + pub fn update_and_check_changed(&self, up: u64, down: u64) -> Option { + let mut rates = self.rate.lock(); + let (current, previous) = &mut *rates; + + *previous = current.clone(); + current.up = up; + current.down = down; + + if previous != current { + Some(current.clone()) + } else { + None + } + } + + // 获取当前的速率 + pub fn get_curent_rate(&self) -> Option { + let rates = self.rate.lock(); + let (current, _) = &*rates; + Some(current.clone()) + } + + /// 在图标上添加速率显示 + pub fn add_speed_text(icon: Vec, rate: Option) -> Result> { + let rate = rate.unwrap_or(Rate { up: 0, down: 0 }); + let img = image::load_from_memory(&icon)?; + let (width, height) = (img.width(), img.height()); + + let mut image = ImageBuffer::new((width as f32 * 4.0) as u32, height); + image::imageops::replace(&mut image, &img, 0, 0); + + let font = + Font::try_from_bytes(include_bytes!("../../../assets/fonts/SFCompact.ttf")).unwrap(); + + // 修改颜色和阴影参数 + let text_color = Rgba([255u8, 255u8, 255u8, 255u8]); // 纯白色 + let shadow_color = Rgba([0u8, 0u8, 0u8, 180u8]); // 半透明黑色阴影 + let base_size = (height as f32 * 0.5) as f32; + let scale = Scale::uniform(base_size); + + let up_text = format_bytes_speed(rate.up); + let down_text = format_bytes_speed(rate.down); + + // 计算文本位置(保持不变) + let up_width = font + .layout(&up_text, scale, rusttype::Point { x: 0.0, y: 0.0 }) + .map(|g| g.position().x + g.unpositioned().h_metrics().advance_width) + .last() + .unwrap_or(0.0); + + let down_width = font + .layout(&down_text, scale, rusttype::Point { x: 0.0, y: 0.0 }) + .map(|g| g.position().x + g.unpositioned().h_metrics().advance_width) + .last() + .unwrap_or(0.0); + + let right_margin = 8; + let canvas_width = width * 4; + let up_x = canvas_width as f32 - up_width - right_margin as f32; + let down_x = canvas_width as f32 - down_width - right_margin as f32; + + // 添加阴影效果 + let shadow_offset = 1; // 阴影偏移量 + + // 绘制上行速率(先画阴影,再画文字) + draw_text_mut( + &mut image, + shadow_color, + up_x as i32 + shadow_offset, + 1 + shadow_offset, + scale, + &font, + &up_text, + ); + draw_text_mut( + &mut image, + text_color, + up_x as i32, + 1, + scale, + &font, + &up_text, + ); + + // 绘制下行速率(先画阴影,再画文字) + draw_text_mut( + &mut image, + shadow_color, + down_x as i32 + shadow_offset, + height as i32 - (base_size as i32) - 1 + shadow_offset, + scale, + &font, + &down_text, + ); + draw_text_mut( + &mut image, + text_color, + down_x as i32, + height as i32 - (base_size as i32) - 1, + scale, + &font, + &down_text, + ); + + let mut bytes: Vec = Vec::new(); + let mut cursor = Cursor::new(&mut bytes); + image.write_to(&mut cursor, image::ImageFormat::Png)?; + Ok(bytes) + } +} + +#[derive(Debug, Clone)] +pub struct Traffic { + pub up: u64, + pub down: u64, +} +impl Traffic { + pub async fn get_traffic_stream() -> Result>> + { + use futures::stream::{self, StreamExt}; + use std::time::Duration; + + let stream = Box::pin( + stream::unfold((), |_| async { + loop { + let ws_url = get_traffic_ws_url().unwrap(); + + match tokio_tungstenite::connect_async(&ws_url).await { + Ok((ws_stream, _)) => { + log::info!(target: "app", "traffic ws connection established"); + return Some(( + ws_stream.map(|msg| { + msg.map_err(anyhow::Error::from).and_then(|msg: Message| { + let data = msg.into_text()?; + let json: serde_json::Value = serde_json::from_str(&data)?; + Ok(Traffic { + up: json["up"].as_u64().unwrap_or(0), + down: json["down"].as_u64().unwrap_or(0), + }) + }) + }), + (), + )); + } + Err(e) => { + log::error!(target: "app", "traffic ws connection failed: {e}"); + tokio::time::sleep(Duration::from_secs(5)).await; + continue; + } + } + } + }) + .flatten(), + ); + + Ok(stream) + } +} diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs index bc022dbb..d2eb325f 100644 --- a/src-tauri/src/feat.rs +++ b/src-tauri/src/feat.rs @@ -76,9 +76,9 @@ pub fn change_clash_mode(mode: String) { if Config::clash().data().save_config().is_ok() { handle::Handle::refresh_clash(); - log_err!(handle::Handle::update_systray_menu()); + log_err!(tray::Tray::global().update_menu()); #[cfg(target_os = "macos")] - log_err!(handle::Handle::update_systray_icon()); + log_err!(tray::Tray::global().update_icon(None)); } } Err(err) => log::error!(target: "app", "{err}"), @@ -141,9 +141,9 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> { CoreManager::global().restart_core().await?; } else { if patch.get("mode").is_some() { - log_err!(handle::Handle::update_systray_menu()); + log_err!(tray::Tray::global().update_menu()); #[cfg(target_os = "macos")] - log_err!(handle::Handle::update_systray_icon()); + log_err!(tray::Tray::global().update_icon(None)); } Config::runtime().latest().patch_config(patch); CoreManager::global().update_config().await?; @@ -267,7 +267,7 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> { } if should_update_systray_icon { - handle::Handle::update_systray_icon()?; + tray::Tray::global().update_icon(None)?; } >::Ok(()) diff --git a/src-tauri/src/utils/help.rs b/src-tauri/src/utils/help.rs index 5d68ee6d..0138631a 100644 --- a/src-tauri/src/utils/help.rs +++ b/src-tauri/src/utils/help.rs @@ -201,22 +201,34 @@ macro_rules! t { }; } -#[test] -fn test_parse_value() { - let test_1 = "upload=111; download=2222; total=3333; expire=444"; - let test_2 = "attachment; filename=Clash.yaml"; - - assert_eq!(parse_str::(test_1, "upload").unwrap(), 111); - assert_eq!(parse_str::(test_1, "download").unwrap(), 2222); - assert_eq!(parse_str::(test_1, "total").unwrap(), 3333); - assert_eq!(parse_str::(test_1, "expire").unwrap(), 444); - assert_eq!( - parse_str::(test_2, "filename").unwrap(), - format!("Clash.yaml") - ); - - assert_eq!(parse_str::(test_1, "aaa"), None); - assert_eq!(parse_str::(test_1, "upload1"), None); - assert_eq!(parse_str::(test_1, "expire1"), None); - assert_eq!(parse_str::(test_2, "attachment"), None); +/// 将字节数转换为可读的流量字符串 +/// 支持 B/s、KB/s、MB/s、GB/s 的自动转换 +/// +/// # Examples +/// ``` +/// assert_eq!(format_bytes_speed(1000), "1000B/s"); +/// assert_eq!(format_bytes_speed(1024), "1.0KB/s"); +/// assert_eq!(format_bytes_speed(1024 * 1024), "1.0MB/s"); +/// ``` +pub fn format_bytes_speed(speed: u64) -> String { + if speed < 1024 { + format!("{}B/s", speed) + } else if speed < 1024 * 1024 { + format!("{:.1}KB/s", speed as f64 / 1024.0) + } else if speed < 1024 * 1024 * 1024 { + format!("{:.1}MB/s", speed as f64 / 1024.0 / 1024.0) + } else { + format!("{:.1}GB/s", speed as f64 / 1024.0 / 1024.0 / 1024.0) + } +} + +#[test] +fn test_format_bytes_speed() { + assert_eq!(format_bytes_speed(0), "0B/s"); + assert_eq!(format_bytes_speed(1023), "1023B/s"); + assert_eq!(format_bytes_speed(1024), "1.0KB/s"); + assert_eq!(format_bytes_speed(1024 * 1024), "1.0MB/s"); + assert_eq!(format_bytes_speed(1024 * 1024 * 1024), "1.0GB/s"); + assert_eq!(format_bytes_speed(1024 * 500), "500.0KB/s"); + assert_eq!(format_bytes_speed(1024 * 1024 * 2), "2.0MB/s"); } diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index 1be687b8..a2110ae4 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -92,7 +92,8 @@ pub async fn resolve_setup(app: &mut App) { server::embed_server(); log::trace!(target: "app", "init system tray"); - log_err!(tray::Tray::create_systray()); + log_err!(tray::Tray::global().init()); + log_err!(tray::Tray::global().create_systray()); let silent_start = { Config::verge().data().enable_silent_start }; if !silent_start.unwrap_or(false) { @@ -102,14 +103,21 @@ pub async fn resolve_setup(app: &mut App) { log_err!(sysopt::Sysopt::global().update_sysproxy().await); log_err!(sysopt::Sysopt::global().init_guard_sysproxy()); - log_err!(handle::Handle::update_systray_part()); + log_err!(tray::Tray::global().update_part()); log_err!(hotkey::Hotkey::global().init()); log_err!(timer::Timer::global().init()); + + // 流量订阅 + #[cfg(target_os = "macos")] + log_err!(tray::Tray::global().subscribe_traffic().await); } /// reset system proxy pub fn resolve_reset() { tauri::async_runtime::block_on(async move { + #[cfg(target_os = "macos")] + tray::Tray::global().unsubscribe_traffic(); + log_err!(sysopt::Sysopt::global().reset_sysproxy().await); log_err!(CoreManager::global().stop_core().await); #[cfg(target_os = "macos")]