diff --git a/Cargo.lock b/Cargo.lock index 74603a8..6efc66a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,16 +420,14 @@ name = "auto_update" version = "1.0.0-beta" dependencies = [ "anyhow", + "cargo-packager-updater", "common", "global", "gpui", - "i18n", "log", "nostr-sdk", - "reqwest 0.12.22", - "rust-i18n", + "smallvec", "smol", - "tempfile", ] [[package]] @@ -841,6 +839,42 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cargo-packager-updater" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec09acab5c2227aba2e592d431708305bdeb6d507703f6cd8983fb57b6c5ef7" +dependencies = [ + "base64", + "cargo-packager-utils", + "ctor 0.2.9", + "dirs 5.0.1", + "dunce", + "flate2", + "http", + "log", + "minisign-verify", + "percent-encoding", + "reqwest 0.12.22", + "semver", + "serde", + "serde_json", + "tar", + "tempfile", + "thiserror 1.0.69", + "time", + "url", +] + +[[package]] +name = "cargo-packager-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b43458dd2ee3cdab3f5b105acd80791383b730380c929018701313d7d299d4e8" +dependencies = [ + "ctor 0.2.9", +] + [[package]] name = "cbc" version = "0.1.2" @@ -1441,6 +1475,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.104", +] + [[package]] name = "ctor" version = "0.4.3" @@ -1475,6 +1519,15 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -1860,6 +1913,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "flatbuffers" version = "25.2.10" @@ -2394,7 +2459,7 @@ dependencies = [ "core-text", "core-video", "cosmic-text", - "ctor", + "ctor 0.4.3", "derive_more", "embed-resource", "etagere", @@ -3333,6 +3398,7 @@ checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ "bitflags 2.9.1", "libc", + "redox_syscall", ] [[package]] @@ -3533,7 +3599,7 @@ dependencies = [ "bindgen 0.71.1", "core-foundation 0.10.1", "core-video", - "ctor", + "ctor 0.4.3", "foreign-types 0.5.0", "metal", "objc", @@ -3610,6 +3676,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "minisign-verify" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -3915,6 +3987,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -4517,6 +4595,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -5013,6 +5097,7 @@ dependencies = [ "base64", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2", @@ -5030,6 +5115,9 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -5037,6 +5125,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -6233,6 +6322,17 @@ dependencies = [ "objc", ] +[[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" @@ -6341,6 +6441,37 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -8041,6 +8172,16 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +[[package]] +name = "xattr" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" +dependencies = [ + "libc", + "rustix 1.0.8", +] + [[package]] name = "xcb" version = "1.5.0" diff --git a/crates/auto_update/Cargo.toml b/crates/auto_update/Cargo.toml index 8b567e7..8bfad2d 100644 --- a/crates/auto_update/Cargo.toml +++ b/crates/auto_update/Cargo.toml @@ -8,13 +8,11 @@ publish.workspace = true common = { path = "../common" } global = { path = "../global" } -rust-i18n.workspace = true -i18n.workspace = true gpui.workspace = true nostr-sdk.workspace = true anyhow.workspace = true smol.workspace = true -reqwest.workspace = true log.workspace = true +smallvec.workspace = true -tempfile = "3.19.1" +cargo-packager-updater = "0.2.3" diff --git a/crates/auto_update/src/lib.rs b/crates/auto_update/src/lib.rs index 3b98138..dd562c4 100644 --- a/crates/auto_update/src/lib.rs +++ b/crates/auto_update/src/lib.rs @@ -1,348 +1,160 @@ -use std::env::consts::OS; -use std::env::{self}; -use std::ffi::OsString; -use std::path::PathBuf; - -use anyhow::{anyhow, Context as _, Error}; -use global::nostr_client; -use gpui::{App, AppContext, Context, Entity, Global, SemanticVersion, Task}; -use nostr_sdk::prelude::*; -use smol::fs::{self, File}; -use smol::io::AsyncWriteExt; -use smol::process::Command; -use tempfile::TempDir; - -i18n::init!(); - -struct GlobalAutoUpdate(Entity); - -impl Global for GlobalAutoUpdate {} +use anyhow::Error; +use cargo_packager_updater::semver::Version; +use cargo_packager_updater::{check_update, Config, Update}; +use global::constants::{APP_PUBKEY, APP_UPDATER_ENDPOINT}; +use gpui::http_client::Url; +use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task, Window}; +use smallvec::{smallvec, SmallVec}; pub fn init(cx: &mut App) { - let env = env!("CARGO_PKG_VERSION"); - let current_version: SemanticVersion = env.parse().expect("Invalid version in Cargo.toml"); - - AutoUpdater::set_global( - cx.new(|_| AutoUpdater { - current_version, - status: AutoUpdateStatus::Idle, - }), - cx, - ); + AutoUpdater::set_global(cx.new(AutoUpdater::new), cx); } -struct MacOsUnmounter { - mount_path: PathBuf, -} +struct GlobalAutoUpdater(Entity); -impl Drop for MacOsUnmounter { - fn drop(&mut self) { - let unmount_output = std::process::Command::new("hdiutil") - .args(["detach", "-force"]) - .arg(&self.mount_path) - .output(); +impl Global for GlobalAutoUpdater {} - match unmount_output { - Ok(output) if output.status.success() => { - log::info!("Successfully unmounted the disk image"); - } - Ok(output) => { - log::error!( - "Failed to unmount disk image: {:?}", - String::from_utf8_lossy(&output.stderr) - ); - } - Err(error) => { - log::error!("Error while trying to unmount disk image: {error:?}"); - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum AutoUpdateStatus { Idle, Checking, - Downloading, + Checked { update: Box }, Installing, - Updated { binary_path: PathBuf }, - Errored, + Updated, + Errored { msg: Box }, } impl AutoUpdateStatus { + pub fn is_updating(&self) -> bool { + matches!(self, Self::Checked { .. } | Self::Installing) + } + pub fn is_updated(&self) -> bool { - matches!(self, Self::Updated { .. }) + matches!(self, Self::Updated) + } + + pub fn checked(update: Update) -> Self { + Self::Checked { + update: Box::new(update), + } + } + + pub fn error(e: String) -> Self { + Self::Errored { msg: Box::new(e) } } } -#[derive(Debug)] pub struct AutoUpdater { - status: AutoUpdateStatus, - current_version: SemanticVersion, + pub status: AutoUpdateStatus, + config: Config, + version: Version, + #[allow(dead_code)] + subscriptions: SmallVec<[Subscription; 1]>, } impl AutoUpdater { + /// Retrieve the Global Auto Updater instance pub fn global(cx: &App) -> Entity { - cx.global::().0.clone() + cx.global::().0.clone() } - pub fn set_global(auto_updater: Entity, cx: &mut App) { - cx.set_global(GlobalAutoUpdate(auto_updater)); + /// Retrieve the Auto Updater instance + pub fn read_global(cx: &App) -> &Self { + cx.global::().0.read(cx) } - pub fn current_version(&self) -> SemanticVersion { - self.current_version + /// Set the Global Auto Updater instance + pub(crate) fn set_global(state: Entity, cx: &mut App) { + cx.set_global(GlobalAutoUpdater(state)); } - pub fn status(&self) -> AutoUpdateStatus { - self.status.clone() + pub(crate) fn new(cx: &mut Context) -> Self { + let config = cargo_packager_updater::Config { + endpoints: vec![Url::parse(APP_UPDATER_ENDPOINT).expect("Endpoint is not valid")], + pubkey: String::from(APP_PUBKEY), + ..Default::default() + }; + let version = Version::parse(env!("CARGO_PKG_VERSION")).expect("Failed to parse version"); + let mut subscriptions = smallvec![]; + + subscriptions.push(cx.observe_new::(|this, window, cx| { + if let Some(window) = window { + this.check_for_updates(window, cx); + } + })); + + Self { + status: AutoUpdateStatus::Idle, + version, + config, + subscriptions, + } } - pub fn set_status(&mut self, status: AutoUpdateStatus, cx: &mut Context) { + pub fn check_for_updates(&mut self, window: &mut Window, cx: &mut Context) { + let config = self.config.clone(); + let current_version = self.version.clone(); + + log::info!("Checking for updates..."); + self.set_status(AutoUpdateStatus::Checking, cx); + + let checking: Task, Error>> = cx.background_spawn(async move { + if let Some(update) = check_update(current_version, config)? { + Ok(Some(update)) + } else { + Ok(None) + } + }); + + cx.spawn_in(window, async move |this, cx| { + if let Ok(Some(update)) = checking.await { + cx.update(|window, cx| { + this.update(cx, |this, cx| { + this.set_status(AutoUpdateStatus::checked(update), cx); + this.install_update(window, cx); + }) + .ok(); + }) + .ok(); + } else { + this.update(cx, |this, cx| { + this.set_status(AutoUpdateStatus::Idle, cx); + }) + .ok(); + } + }) + .detach(); + } + + pub(crate) fn install_update(&mut self, window: &mut Window, cx: &mut Context) { + self.set_status(AutoUpdateStatus::Installing, cx); + + if let AutoUpdateStatus::Checked { update } = self.status.clone() { + let install: Task> = + cx.background_spawn(async move { Ok(update.download_and_install()?) }); + + cx.spawn_in(window, async move |this, cx| { + match install.await { + Ok(_) => { + this.update(cx, |this, cx| { + this.set_status(AutoUpdateStatus::Updated, cx); + }) + .ok(); + } + Err(e) => { + this.update(cx, |this, cx| { + this.set_status(AutoUpdateStatus::error(e.to_string()), cx); + }) + .ok(); + } + }; + }) + .detach(); + } + } + + fn set_status(&mut self, status: AutoUpdateStatus, cx: &mut Context) { self.status = status; cx.notify(); } - - pub fn update(&mut self, event: Event, cx: &mut Context) { - self.set_status(AutoUpdateStatus::Checking, cx); - - // Extract the version from the identifier tag - let ident = match event.tags.identifier() { - Some(i) => match i.split('@').next_back() { - Some(i) => i, - None => return, - }, - None => return, - }; - - // Convert the version string to a SemanticVersion - let new_version: SemanticVersion = ident.parse().expect("Invalid version"); - - // Check if the new version is the same as the current version - if self.current_version == new_version { - self.set_status(AutoUpdateStatus::Idle, cx); - return; - }; - - // Download the new version - self.set_status(AutoUpdateStatus::Downloading, cx); - - let task: Task> = cx.background_spawn(async move { - let ids = event.tags.event_ids().copied(); - let filter = Filter::new().ids(ids).kind(Kind::FileMetadata); - let events = nostr_client().database().query(filter).await?; - - if let Some(event) = events.into_iter().find(|event| event.content == OS) { - let tag = event.tags.find(TagKind::Url).context("url not found")?; - let url = Url::parse(tag.content().context("invalid")?)?; - - let temp_dir = tempfile::Builder::new().prefix("coop-update").tempdir()?; - let filename = match OS { - "macos" => Ok("Coop.dmg"), - "linux" => Ok("Coop.tar.gz"), - "windows" => Ok("CoopUpdateInstaller.exe"), - _ => Err(anyhow!("not supported: {:?}", OS)), - }?; - - let downloaded_asset = temp_dir.path().join(filename); - let mut target_file = File::create(&downloaded_asset).await?; - - let response = reqwest::get(url).await?; - let mut stream = response.bytes_stream(); - - while let Some(item) = stream.next().await { - let chunk = item?; - target_file.write_all(&chunk).await?; - } - - log::info!("downloaded update. path: {downloaded_asset:?}"); - - Ok((temp_dir, downloaded_asset)) - } else { - Err(anyhow!("Not found")) - } - }); - - cx.spawn(async move |this, cx| { - if let Ok((temp_dir, downloaded_asset)) = task.await { - cx.update(|cx| { - this.update(cx, |this, cx| { - this.set_status(AutoUpdateStatus::Installing, cx); - - match OS { - "macos" => this.install_release_macos(temp_dir, downloaded_asset, cx), - "linux" => this.install_release_linux(temp_dir, downloaded_asset, cx), - "windows" => this.install_release_windows(downloaded_asset, cx), - _ => {} - } - }) - .ok(); - }) - .ok(); - } - }) - .detach(); - } - - fn install_release_macos(&mut self, temp_dir: TempDir, asset: PathBuf, cx: &mut Context) { - let running_app_path = cx.app_path().unwrap(); - let running_app_filename = running_app_path.file_name().unwrap(); - - let mount_path = temp_dir.path().join("Coop"); - - let mut mounted_app_path: OsString = mount_path.join(running_app_filename).into(); - mounted_app_path.push("/"); - - let task: Task> = cx.background_spawn(async move { - let output = Command::new("hdiutil") - .args(["attach", "-nobrowse"]) - .arg(&asset) - .arg("-mountroot") - .arg(temp_dir.path()) - .output() - .await?; - - anyhow::ensure!( - output.status.success(), - "failed to mount: {:?}", - String::from_utf8_lossy(&output.stderr) - ); - - // Create an MacOsUnmounter that will be dropped (and thus unmount the disk) when this function exits - let _unmounter = MacOsUnmounter { - mount_path: mount_path.clone(), - }; - - let output = Command::new("rsync") - .args(["-av", "--delete"]) - .arg(&mounted_app_path) - .arg(&running_app_path) - .output() - .await?; - - anyhow::ensure!( - output.status.success(), - "failed to copy app: {:?}", - String::from_utf8_lossy(&output.stderr) - ); - - Ok(running_app_path) - }); - - cx.spawn(async move |this, cx| { - if let Ok(binary_path) = task.await { - cx.update(|cx| { - this.update(cx, |this, cx| { - this.status = AutoUpdateStatus::Updated { binary_path }; - cx.notify(); - }) - .ok(); - }) - .ok(); - } - }) - .detach(); - } - - fn install_release_linux(&mut self, temp_dir: TempDir, asset: PathBuf, cx: &mut Context) { - let home_dir = PathBuf::from(env::var("HOME").unwrap()); - let running_app_path = cx.app_path().unwrap(); - let extracted = temp_dir.path().join("coop"); - - let task: Task> = cx.background_spawn(async move { - fs::create_dir_all(&extracted).await?; - - let output = Command::new("tar") - .arg("-xzf") - .arg(&asset) - .arg("-C") - .arg(&extracted) - .output() - .await?; - - anyhow::ensure!( - output.status.success(), - "failed to extract {:?} to {:?}: {:?}", - asset, - extracted, - String::from_utf8_lossy(&output.stderr) - ); - - let app_folder_name: String = "coop.app".into(); - let from = extracted.join(&app_folder_name); - let mut to = home_dir.join(".local"); - - let expected_suffix = format!("{app_folder_name}/libexec/coop"); - - if let Some(prefix) = running_app_path - .to_str() - .and_then(|str| str.strip_suffix(&expected_suffix)) - { - to = PathBuf::from(prefix); - } - - let output = Command::new("rsync") - .args(["-av", "--delete"]) - .arg(&from) - .arg(&to) - .output() - .await?; - - anyhow::ensure!( - output.status.success(), - "failed to copy Coop update from {:?} to {:?}: {:?}", - from, - to, - String::from_utf8_lossy(&output.stderr) - ); - - Ok(to.join(expected_suffix)) - }); - - cx.spawn(async move |this, cx| { - if let Ok(binary_path) = task.await { - cx.update(|cx| { - this.update(cx, |this, cx| { - this.status = AutoUpdateStatus::Updated { binary_path }; - cx.notify(); - }) - .ok(); - }) - .ok(); - } - }) - .detach(); - } - - fn install_release_windows(&mut self, asset: PathBuf, cx: &mut Context) { - let task: Task> = cx.background_spawn(async move { - let output = Command::new(asset) - .arg("/verysilent") - .arg("/update=true") - .arg("!desktopicon") - .arg("!quicklaunchicon") - .output() - .await?; - anyhow::ensure!( - output.status.success(), - "failed to start installer: {:?}", - String::from_utf8_lossy(&output.stderr) - ); - Ok(std::env::current_exe()?) - }); - - cx.spawn(async move |this, cx| { - if let Ok(binary_path) = task.await { - cx.update(|cx| { - this.update(cx, |this, cx| { - this.status = AutoUpdateStatus::Updated { binary_path }; - cx.notify(); - }) - .ok(); - }) - .ok(); - } - }) - .detach(); - } } diff --git a/crates/coop/src/chatspace.rs b/crates/coop/src/chatspace.rs index 9eec6be..c953bf7 100644 --- a/crates/coop/src/chatspace.rs +++ b/crates/coop/src/chatspace.rs @@ -1,14 +1,16 @@ use std::sync::Arc; +use auto_update::AutoUpdater; use client_keys::ClientKeys; use common::display::DisplayProfile; use global::constants::DEFAULT_SIDEBAR_WIDTH; use gpui::prelude::FluentBuilder; use gpui::{ actions, div, px, rems, Action, App, AppContext, Axis, Context, Entity, InteractiveElement, - IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Window, + IntoElement, ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, + Subscription, Window, }; -use i18n::t; +use i18n::{shared_t, t}; use identity::Identity; use nostr_connect::prelude::*; use nostr_sdk::prelude::*; @@ -275,7 +277,7 @@ impl ChatSpace { }); } - pub fn on_settings(&mut self, _ev: &Settings, window: &mut Window, cx: &mut Context) { + fn on_settings(&mut self, _ev: &Settings, window: &mut Window, cx: &mut Context) { let view = preferences::init(window, cx); let title = SharedString::new(t!("common.preferences")); @@ -341,8 +343,39 @@ impl ChatSpace { let need_backup = Identity::read_global(cx).need_backup(); let relay_ready = Identity::read_global(cx).relay_ready(); + let updating = AutoUpdater::read_global(cx).status.is_updating(); + let updated = AutoUpdater::read_global(cx).status.is_updated(); + h_flex() .gap_1() + .when(updating, |this| { + this.child( + h_flex() + .h_6() + .items_center() + .justify_center() + .text_xs() + .bg(cx.theme().ghost_element_background_alt) + .child(shared_t!("auto_update.updating")), + ) + }) + .when(updated, |this| { + this.child( + h_flex() + .id("updated") + .h_6() + .items_center() + .justify_center() + .text_xs() + .bg(cx.theme().ghost_element_background_alt) + .hover(|this| this.bg(cx.theme().ghost_element_hover)) + .active(|this| this.bg(cx.theme().ghost_element_active)) + .child(shared_t!("auto_update.updated")) + .on_click(|_, _window, cx| { + cx.restart(None); + }), + ) + }) .when_some(relay_ready, |this, status| { this.when(!status, |this| this.child(messaging_relays::relay_button())) }) diff --git a/crates/coop/src/main.rs b/crates/coop/src/main.rs index 2c75285..e0807ed 100644 --- a/crates/coop/src/main.rs +++ b/crates/coop/src/main.rs @@ -4,9 +4,8 @@ use std::time::Duration; use anyhow::{anyhow, Error}; use assets::Assets; -use auto_update::AutoUpdater; use global::constants::{ - ALL_MESSAGES_SUB_ID, APP_ID, APP_NAME, APP_PUBKEY, BOOTSTRAP_RELAYS, METADATA_BATCH_LIMIT, + ALL_MESSAGES_SUB_ID, APP_ID, APP_NAME, BOOTSTRAP_RELAYS, METADATA_BATCH_LIMIT, METADATA_BATCH_TIMEOUT, NEW_MESSAGE_SUB_ID, SEARCH_RELAYS, }; use global::{nostr_client, NostrSignal}; @@ -55,11 +54,6 @@ fn main() { log::error!("Failed to connect to bootstrap relays: {e}"); } - // Connect to bootstrap relays. - if let Err(e) = subscribe_for_app_updates(client).await { - log::error!("Failed to subscribe for app updates: {e}"); - } - // Handle Nostr notifications. // // Send the redefined signal back to GPUI via channel. @@ -250,7 +244,6 @@ fn main() { while let Ok(signal) = signal_rx.recv().await { cx.update(|window, cx| { let registry = Registry::global(cx); - let auto_updater = AutoUpdater::global(cx); let identity = Identity::read_global(cx); match signal { @@ -293,11 +286,6 @@ fn main() { NostrSignal::Notice(_msg) => { // window.push_notification(msg, cx); } - NostrSignal::AppUpdate(event) => { - auto_updater.update(cx, |this, cx| { - this.update(event, cx); - }); - } }; }) .ok(); @@ -431,20 +419,6 @@ async fn handle_nostr_notifications( ) } } - Kind::ReleaseArtifactSet => { - let ids = event.tags.event_ids().copied(); - let filter = Filter::new().ids(ids).kind(Kind::FileMetadata); - - client - .subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts)) - .await - .ok(); - - signal_tx - .send(NostrSignal::AppUpdate(event.into_owned())) - .await - .ok(); - } _ => {} } } @@ -460,27 +434,6 @@ async fn handle_nostr_notifications( Ok(()) } -async fn subscribe_for_app_updates(client: &Client) -> Result<(), Error> { - let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); - - let coordinate = Coordinate { - kind: Kind::Custom(32267), - public_key: PublicKey::from_hex(APP_PUBKEY).expect("App Pubkey is invalid"), - identifier: APP_ID.into(), - }; - - let filter = Filter::new() - .kind(Kind::ReleaseArtifactSet) - .coordinate(&coordinate) - .limit(1); - - client - .subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts)) - .await?; - - Ok(()) -} - async fn check_author(client: &Client, event: &Event) -> Result { let signer = client.signer().await?; let public_key = signer.get_public_key().await?; diff --git a/crates/global/src/constants.rs b/crates/global/src/constants.rs index abaa22e..04d39c8 100644 --- a/crates/global/src/constants.rs +++ b/crates/global/src/constants.rs @@ -1,6 +1,7 @@ pub const APP_NAME: &str = "Coop"; pub const APP_ID: &str = "su.reya.coop"; -pub const APP_PUBKEY: &str = "b1813fb01274b32cc5db6d1198e7c79dda0fb430899f63c7064f651a41d44f2b"; +pub const APP_PUBKEY: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDc4MkNFRkQ2RkVGQURGNzUKUldSMTMvcisxdThzZUZraHc4Vno3NVNJek81VkJFUEV3MkJweGFxQXhpekdSU1JIekpqMG4yemMK"; +pub const APP_UPDATER_ENDPOINT: &str = "https://coop-updater.reya.su/"; pub const KEYRING_URL: &str = "Coop Safe Storage"; pub const ACCOUNT_D: &str = "coop:account"; diff --git a/crates/global/src/lib.rs b/crates/global/src/lib.rs index 7f3a1e6..974f882 100644 --- a/crates/global/src/lib.rs +++ b/crates/global/src/lib.rs @@ -31,9 +31,6 @@ pub enum NostrSignal { /// Notice from Relay Pool Notice(String), - - /// Application update event received - AppUpdate(Event), } static NOSTR_CLIENT: OnceLock = OnceLock::new(); diff --git a/crates/identity/src/lib.rs b/crates/identity/src/lib.rs index 969ed96..2d8db36 100644 --- a/crates/identity/src/lib.rs +++ b/crates/identity/src/lib.rs @@ -581,7 +581,6 @@ impl Identity { cx.spawn_in(window, async move |this, cx| { let result = task.await; - log::info!("result: {result}"); this.update(cx, |this, cx| { this.relay_ready = Some(result); diff --git a/locales/app.yml b/locales/app.yml index e50fc75..8d77a6b 100644 --- a/locales/app.yml +++ b/locales/app.yml @@ -32,6 +32,12 @@ common: clear: en: "Clear" +auto_update: + updating: + en: "Installing the new update..." + updated: + en: "Restart to apply the new update" + user: dark_mode: en: "Dark Mode"