diff --git a/package.json b/package.json index 7e84236..2e87c67 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@tailwindcss/vite": "^4.1.17", "@tauri-apps/api": "^2", "@tauri-apps/plugin-opener": "^2", + "@tauri-apps/plugin-updater": "~2.10.0", "tailwindcss": "^4.1.17" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f46c48..08fdd93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@tauri-apps/plugin-opener': specifier: ^2 version: 2.5.2 + '@tauri-apps/plugin-updater': + specifier: ~2.10.0 + version: 2.10.0 tailwindcss: specifier: ^4.1.17 version: 4.1.17 @@ -467,6 +470,9 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 + '@tauri-apps/api@2.10.1': + resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} + '@tauri-apps/api@2.9.0': resolution: {integrity: sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==} @@ -544,6 +550,9 @@ packages: '@tauri-apps/plugin-opener@2.5.2': resolution: {integrity: sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew==} + '@tauri-apps/plugin-updater@2.10.0': + resolution: {integrity: sha512-ljN8jPlnT0aSn8ecYhuBib84alxfMx6Hc8vJSKMJyzGbTPFZAC44T2I1QNFZssgWKrAlofvJqCC6Rr472JWfkQ==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -1137,6 +1146,8 @@ snapshots: tailwindcss: 4.1.17 vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) + '@tauri-apps/api@2.10.1': {} + '@tauri-apps/api@2.9.0': {} '@tauri-apps/cli-darwin-arm64@2.9.4': @@ -1190,6 +1201,10 @@ snapshots: dependencies: '@tauri-apps/api': 2.9.0 + '@tauri-apps/plugin-updater@2.10.0': + dependencies: + '@tauri-apps/api': 2.10.1 + '@types/cookie@0.6.0': {} '@types/estree@1.0.8': {} diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 186c8f6..5b3cd84 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -72,6 +72,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "ashpd" version = "0.11.0" @@ -801,6 +810,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -1134,6 +1154,17 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -1243,6 +1274,7 @@ dependencies = [ "tauri-plugin-opener", "tauri-plugin-positioner", "tauri-plugin-process", + "tauri-plugin-updater", "tauri-specta", "thiserror 1.0.69", "tokio", @@ -1496,8 +1528,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1507,9 +1541,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasip2", + "wasm-bindgen", ] [[package]] @@ -1841,6 +1877,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -2301,6 +2338,7 @@ checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.10.0", "libc", + "redox_syscall", ] [[package]] @@ -2330,6 +2368,12 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lua-src" version = "550.0.0" @@ -2435,6 +2479,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minisign-verify" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2839,6 +2889,18 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-osa-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" +dependencies = [ + "bitflags 2.10.0", + "objc2 0.6.3", + "objc2-app-kit", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-quartz-core" version = "0.2.2" @@ -2989,6 +3051,20 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "osakit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" +dependencies = [ + "objc2 0.6.3", + "objc2-foundation 0.3.2", + "objc2-osa-kit", + "serde", + "serde_json", + "thiserror 2.0.17", +] + [[package]] name = "pango" version = "0.18.3" @@ -3380,6 +3456,61 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.42" @@ -3618,6 +3749,8 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pki-types", "serde", "serde_json", @@ -3625,6 +3758,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -3634,6 +3768,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", ] [[package]] @@ -3754,6 +3889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3766,6 +3902,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ + "web-time", "zeroize", ] @@ -4504,6 +4641,17 @@ dependencies = [ "syn 2.0.110", ] +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4744,6 +4892,38 @@ dependencies = [ "tauri-plugin", ] +[[package]] +name = "tauri-plugin-updater" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27cbc31740f4d507712550694749572ec0e43bdd66992db7599b89fbfd6b167b" +dependencies = [ + "base64 0.22.1", + "dirs", + "flate2", + "futures-util", + "http", + "infer", + "log", + "minisign-verify", + "osakit", + "percent-encoding", + "reqwest", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.17", + "time", + "tokio", + "url", + "windows-sys 0.60.2", + "zip", +] + [[package]] name = "tauri-runtime" version = "2.9.1" @@ -4987,6 +5167,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.48.0" @@ -5717,6 +5912,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webkit2gtk" version = "2.0.1" @@ -5761,6 +5966,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.38.0" @@ -6487,6 +6701,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "xkbcommon" version = "0.9.0" @@ -6683,6 +6907,18 @@ dependencies = [ "syn 2.0.110", ] +[[package]] +name = "zip" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" +dependencies = [ + "arbitrary", + "crc32fast", + "indexmap 2.12.0", + "memchr", +] + [[package]] name = "zvariant" version = "5.8.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index af2df4b..4b24e78 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -53,6 +53,7 @@ petpet = "2.4.3" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-global-shortcut = "2" tauri-plugin-positioner = "2" +tauri-plugin-updater = "2" [target.'cfg(target_os = "macos")'.dependencies] objc2 = "0.6.3" objc2-app-kit = { version = "0.3.2", features = [ diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json new file mode 100644 index 0000000..ba6d080 --- /dev/null +++ b/src-tauri/capabilities/desktop.json @@ -0,0 +1,14 @@ +{ + "identifier": "desktop-capability", + "platforms": [ + "macOS", + "windows", + "linux" + ], + "windows": [ + "main" + ], + "permissions": [ + "updater:default" + ] +} \ No newline at end of file diff --git a/src-tauri/src/init/mod.rs b/src-tauri/src/init/mod.rs index 1169e1e..6d29ee7 100644 --- a/src-tauri/src/init/mod.rs +++ b/src-tauri/src/init/mod.rs @@ -1,6 +1,7 @@ use crate::{ init::{lifecycle::validate_server_health, tracing::init_logging}, services::{ + app_update::update_app, auth::get_session_token, cursor::init_cursor_tracking, presence_modules::init_modules, @@ -20,6 +21,7 @@ pub mod tracing; pub async fn launch_app() { init_logging(); open_splash_window(); + update_app().await; init_app_state(); init_system_tray(); init_cursor_tracking().await; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2feaddd..eca590c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -133,6 +133,7 @@ pub fn run() { .expect("Failed to export TypeScript bindings"); tauri::Builder::default() + .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_positioner::init()) .plugin(tauri_plugin_dialog::init()) diff --git a/src-tauri/src/services/app_update.rs b/src-tauri/src/services/app_update.rs new file mode 100644 index 0000000..b2a35e1 --- /dev/null +++ b/src-tauri/src/services/app_update.rs @@ -0,0 +1,48 @@ +use tauri_plugin_updater::UpdaterExt; +use tracing::{error, info}; + +use crate::get_app_handle; + +pub async fn update_app() { + let app = get_app_handle(); + if let Some(update) = match match app.updater() { + Ok(it) => it, + Err(err) => { + error!("failed to get updater: {err:?}"); + return; + } + } + .check() + .await + { + Ok(it) => it, + Err(err) => { + error!("failed to check for update: {err:?}"); + return; + } + } { + let mut downloaded = 0; + + match update + .download_and_install( + |chunk_length, content_length| { + downloaded += chunk_length; + println!("downloaded {downloaded} from {content_length:?}"); + }, + || { + info!("download finished"); + }, + ) + .await + { + Ok(it) => it, + Err(err) => { + error!("failed to install update: {err:?}"); + return; + } + }; + + info!("update installed"); + app.restart(); + } +} diff --git a/src-tauri/src/services/mod.rs b/src-tauri/src/services/mod.rs index 5693e47..8940034 100644 --- a/src-tauri/src/services/mod.rs +++ b/src-tauri/src/services/mod.rs @@ -1,6 +1,7 @@ pub mod app_data; pub mod app_events; pub mod app_menu; +pub mod app_update; pub mod auth; pub mod client_config; pub mod cursor; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index e8bfc2e..a882021 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -25,6 +25,15 @@ "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico" - ] + ], + "createUpdaterArtifacts": true + }, + "plugins": { + "updater": { + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDIyMEVBOEQxQUIzQzA4RkEKUldUNkNEeXIwYWdPSXBQbGs5bmhTalZjelF1bThDUWVhcDBIWFg3U1Jxb1E1WS9DcVVMVmR5VC8K", + "endpoints": [ + "https://github.com/wind-explorer/friendolls-desktop/releases/latest/download/latest.json" + ] + } } }