diff --git a/Cargo.lock b/Cargo.lock index 32dd35d..bb4a1e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,16 +138,6 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" -[[package]] -name = "app_state" -version = "0.1.0" -dependencies = [ - "common", - "gpui", - "nostr-sdk", - "state", -] - [[package]] name = "arbitrary" version = "1.4.1" @@ -777,6 +767,40 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cargo-packager-updater" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b60a6cdf300a0f0ee62f3f435e23cc97ef7a0a3a489a3aee6b0ca0cd986d722b" +dependencies = [ + "base64", + "cargo-packager-utils", + "ctor", + "dirs 5.0.1", + "dunce", + "flate2", + "http", + "minisign-verify", + "reqwest 0.12.12", + "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", +] + [[package]] name = "cbc" version = "0.1.2" @@ -1111,7 +1135,7 @@ name = "coop" version = "0.1.0" dependencies = [ "anyhow", - "app_state", + "cargo-packager-updater", "chat_state", "common", "dirs 5.0.1", @@ -1331,6 +1355,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_more" version = "0.99.19" @@ -1637,6 +1670,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 = "23.5.26" @@ -2878,6 +2923,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.8.0", "libc", + "redox_syscall", ] [[package]] @@ -3100,6 +3146,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "minisign-verify" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3" + [[package]] name = "miniz_oxide" version = "0.8.3" @@ -3358,6 +3410,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" @@ -3979,6 +4037,12 @@ dependencies = [ "thiserror 1.0.69", ] +[[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.20" @@ -4400,6 +4464,7 @@ checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64", "bytes", + "futures-channel", "futures-core", "futures-util", "http", @@ -4418,6 +4483,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", + "rustls-native-certs", "rustls-pemfile", "rustls-pki-types", "serde", @@ -4427,11 +4493,13 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-socks", + "tokio-util", "tower", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots", "windows-registry", @@ -5340,6 +5408,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bdb6fa0dfa67b38c1e66b7041ba9dcf23b99d8121907cd31c807a332f7a0bbb" +[[package]] +name = "tar" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -5441,6 +5520,37 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -6647,6 +6757,17 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +[[package]] +name = "xattr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + [[package]] name = "xcursor" version = "0.3.8" diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index 22b220a..4e362d0 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -12,7 +12,6 @@ path = "src/main.rs" ui = { path = "../ui" } common = { path = "../common" } state = { path = "../state" } -app_state = { path = "../app_state" } chat_state = { path = "../chat_state" } gpui.workspace = true @@ -30,5 +29,19 @@ dirs.workspace = true rust-embed.workspace = true smol.workspace = true +cargo-packager-updater = "0.2.2" tracing-subscriber = { version = "0.3.18", features = ["fmt"] } log = "0.4" + +[package.metadata.packager] +before-packaging-command = "cargo build --release" +product-name = "Coop" +identifier = "su.reya.coop" +resources = ["src", "icons/*", "Cargo.toml", "../../README.md"] +icons = [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico", +] diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 276ff8b..e8ed254 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -1,4 +1,3 @@ -use app_state::registry::AppRegistry; use asset::Assets; use async_utility::task::spawn; use chat_state::registry::ChatRegistry; @@ -215,8 +214,6 @@ fn main() { .with_assets(Assets) .with_http_client(Arc::new(reqwest_client::ReqwestClient::new())) .run(move |cx| { - // Initialize app global state - AppRegistry::set_global(cx); // Initialize chat global state ChatRegistry::set_global(cx); diff --git a/crates/app/src/views/app.rs b/crates/app/src/views/app.rs index 19de353..22da5b4 100644 --- a/crates/app/src/views/app.rs +++ b/crates/app/src/views/app.rs @@ -1,10 +1,8 @@ -use app_state::registry::AppRegistry; use chat_state::registry::ChatRegistry; use common::profile::NostrProfile; use gpui::{ - actions, div, img, impl_internal_actions, px, App, AppContext, Axis, BorrowAppContext, Context, - Entity, InteractiveElement, IntoElement, ObjectFit, ParentElement, Render, Styled, StyledImage, - Window, + actions, div, img, impl_internal_actions, px, App, AppContext, Axis, Context, Entity, + InteractiveElement, IntoElement, ObjectFit, ParentElement, Render, Styled, StyledImage, Window, }; use nostr_sdk::prelude::*; use serde::Deserialize; @@ -200,13 +198,11 @@ impl AppView { } } PanelKind::Profile => { - if let Some(profile) = cx.global::().user() { - let panel = Arc::new(profile::init(profile, window, cx)); + let panel = Arc::new(profile::init(self.account.clone(), window, cx)); - self.dock.update(cx, |dock_area, cx| { - dock_area.add_panel(panel, action.position, window, cx); - }); - } + self.dock.update(cx, |dock_area, cx| { + dock_area.add_panel(panel, action.position, window, cx); + }); } PanelKind::Contacts => { let panel = Arc::new(contacts::init(window, cx)); @@ -229,10 +225,6 @@ impl AppView { cx.background_spawn(async move { get_client().reset().await }) .detach(); - cx.update_global::(|this, _cx| { - this.set_user(None); - }); - window.replace_root(cx, |window, cx| { Root::new(onboarding::init(window, cx).into(), window, cx) }); diff --git a/crates/app/src/views/onboarding.rs b/crates/app/src/views/onboarding.rs index 1d7ad25..be14820 100644 --- a/crates/app/src/views/onboarding.rs +++ b/crates/app/src/views/onboarding.rs @@ -1,8 +1,7 @@ -use app_state::registry::AppRegistry; -use common::{profile::NostrProfile, qr::create_qr}; +use common::{profile::NostrProfile, qr::create_qr, utils::preload}; use gpui::{ - div, img, prelude::FluentBuilder, relative, svg, App, AppContext, BorrowAppContext, - ClipboardItem, Context, Div, Entity, IntoElement, ParentElement, Render, Styled, Window, + div, img, prelude::FluentBuilder, relative, svg, App, AppContext, ClipboardItem, Context, Div, + Entity, IntoElement, ParentElement, Render, Styled, Window, }; use nostr_connect::prelude::*; use state::get_client; @@ -103,8 +102,10 @@ impl Onboarding { .ok() .unwrap_or_default(); - _ = client.set_signer(signer).await; - _ = tx.send(NostrProfile::new(*public_key, metadata)); + if tx.send(NostrProfile::new(*public_key, metadata)).is_ok() { + _ = client.set_signer(signer).await; + _ = preload(client, *public_key).await; + } } } } @@ -113,10 +114,6 @@ impl Onboarding { if let Ok(profile) = rx.await { _ = cx.update_window(window_handle, |_, window, cx| { - cx.update_global::(|this, _cx| { - this.set_user(Some(profile.clone())); - }); - window.replace_root(cx, |window, cx| { Root::new(app::init(profile, window, cx).into(), window, cx) }); @@ -173,18 +170,16 @@ impl Onboarding { .ok() .unwrap_or_default(); - _ = client.set_signer(keys).await; - _ = tx.send(NostrProfile::new(public_key, metadata)); + if tx.send(NostrProfile::new(public_key, metadata)).is_ok() { + _ = client.set_signer(keys).await; + _ = preload(client, public_key).await; + } } }) .detach(); if let Ok(profile) = rx.await { _ = cx.update_window(window_handle, |_, window, cx| { - cx.update_global::(|this, _cx| { - this.set_user(Some(profile.clone())); - }); - window.replace_root(cx, |window, cx| { Root::new(app::init(profile, window, cx).into(), window, cx) }); diff --git a/crates/app/src/views/sidebar/compose.rs b/crates/app/src/views/sidebar/compose.rs index 9655ef0..b512127 100644 --- a/crates/app/src/views/sidebar/compose.rs +++ b/crates/app/src/views/sidebar/compose.rs @@ -1,4 +1,3 @@ -use app_state::registry::AppRegistry; use chat_state::registry::ChatRegistry; use common::{ constants::FAKE_SIG, @@ -141,18 +140,9 @@ impl Compose { return; } - let current_user = if let Some(profile) = cx.global::().user() { - profile - } else { - return; - }; - // Show loading spinner self.set_submitting(true, cx); - // Get nostr client - let client = get_client(); - // Get message from user's input let content = message.to_string(); @@ -163,9 +153,7 @@ impl Compose { ); // Get all pubkeys - let current_user = current_user.public_key(); let mut pubkeys: Vec = selected.iter().copied().collect(); - pubkeys.push(current_user); // Convert selected pubkeys into Nostr tags let mut tag_list: Vec = selected.iter().map(|pk| Tag::public_key(*pk)).collect(); @@ -178,14 +166,18 @@ impl Compose { let (tx, rx) = oneshot::channel::(); cx.background_spawn(async move { + let client = get_client(); + let public_key = signer_public_key(client).await.unwrap(); let mut event: Option = None; + pubkeys.push(public_key); + for pubkey in pubkeys.iter() { if let Ok(output) = client .send_private_msg(*pubkey, &content, tags.clone()) .await { - if pubkey == ¤t_user && event.is_none() { + if pubkey == &public_key && event.is_none() { if let Ok(Some(ev)) = client.database().event_by_id(&output.val).await { if let Ok(UnwrappedGift { mut rumor, .. }) = client.unwrap_gift_wrap(&ev).await diff --git a/crates/app_state/Cargo.toml b/crates/app_state/Cargo.toml deleted file mode 100644 index 3ccd504..0000000 --- a/crates/app_state/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "app_state" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -common = { path = "../common" } -state = { path = "../state" } - -gpui.workspace = true -nostr-sdk.workspace = true diff --git a/crates/app_state/src/lib.rs b/crates/app_state/src/lib.rs deleted file mode 100644 index d108990..0000000 --- a/crates/app_state/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod registry; diff --git a/crates/app_state/src/registry.rs b/crates/app_state/src/registry.rs deleted file mode 100644 index ed973d1..0000000 --- a/crates/app_state/src/registry.rs +++ /dev/null @@ -1,75 +0,0 @@ -use common::{ - constants::{ALL_MESSAGES_SUB_ID, NEW_MESSAGE_SUB_ID}, - profile::NostrProfile, -}; -use gpui::{App, AppContext, Global}; -use nostr_sdk::prelude::*; -use state::get_client; -use std::time::Duration; - -pub struct AppRegistry { - user: Option, -} - -impl Global for AppRegistry {} - -impl AppRegistry { - pub fn set_global(cx: &mut App) { - cx.observe_global::(|cx| { - if let Some(profile) = cx.global::().user() { - let client = get_client(); - let public_key = profile.public_key(); - - cx.background_spawn(async move { - let subscription = Filter::new() - .kind(Kind::ContactList) - .author(public_key) - .limit(1); - - // Get contact list - _ = client.sync(subscription, &SyncOptions::default()).await; - - let all_messages_sub_id = SubscriptionId::new(ALL_MESSAGES_SUB_ID); - let new_message_sub_id = SubscriptionId::new(NEW_MESSAGE_SUB_ID); - - // Create a filter for getting all gift wrapped events send to current user - let all_messages = Filter::new().kind(Kind::GiftWrap).pubkey(public_key); - - // Create a filter for getting new message - let new_message = Filter::new() - .kind(Kind::GiftWrap) - .pubkey(public_key) - .limit(0); - - // Subscribe for all messages - _ = client - .subscribe_with_id( - all_messages_sub_id, - all_messages, - Some(SubscribeAutoCloseOptions::default().exit_policy( - ReqExitPolicy::WaitDurationAfterEOSE(Duration::from_secs(3)), - )), - ) - .await; - - // Subscribe for new message - _ = client - .subscribe_with_id(new_message_sub_id, new_message, None) - .await - }) - .detach(); - } - }) - .detach(); - - cx.set_global(Self { user: None }); - } - - pub fn set_user(&mut self, profile: Option) { - self.user = profile; - } - - pub fn user(&self) -> Option { - self.user.clone() - } -} diff --git a/crates/common/src/utils.rs b/crates/common/src/utils.rs index 46a11e5..81018ea 100644 --- a/crates/common/src/utils.rs +++ b/crates/common/src/utils.rs @@ -1,10 +1,11 @@ -use crate::constants::NIP96_SERVER; +use crate::constants::{ALL_MESSAGES_SUB_ID, NEW_MESSAGE_SUB_ID, NIP96_SERVER}; use itertools::Itertools; use nostr_sdk::prelude::*; use rnglib::{Language, RNG}; use std::{ collections::HashSet, hash::{DefaultHasher, Hash, Hasher}, + time::Duration, }; pub async fn signer_public_key(client: &Client) -> anyhow::Result { @@ -14,6 +15,47 @@ pub async fn signer_public_key(client: &Client) -> anyhow::Result anyhow::Result<(), anyhow::Error> { + let subscription = Filter::new() + .kind(Kind::ContactList) + .author(public_key) + .limit(1); + + // Get contact list + _ = client.sync(subscription, &SyncOptions::default()).await; + + let all_messages_sub_id = SubscriptionId::new(ALL_MESSAGES_SUB_ID); + let new_message_sub_id = SubscriptionId::new(NEW_MESSAGE_SUB_ID); + + // Create a filter for getting all gift wrapped events send to current user + let all_messages = Filter::new().kind(Kind::GiftWrap).pubkey(public_key); + + // Create a filter for getting new message + let new_message = Filter::new() + .kind(Kind::GiftWrap) + .pubkey(public_key) + .limit(0); + + // Subscribe for all messages + _ = client + .subscribe_with_id( + all_messages_sub_id, + all_messages, + Some( + SubscribeAutoCloseOptions::default() + .exit_policy(ReqExitPolicy::WaitDurationAfterEOSE(Duration::from_secs(3))), + ), + ) + .await; + + // Subscribe for new message + _ = client + .subscribe_with_id(new_message_sub_id, new_message, None) + .await; + + Ok(()) +} + pub async fn nip96_upload(client: &Client, file: Vec) -> anyhow::Result { let signer = client.signer().await?; let server_url = Url::parse(NIP96_SERVER)?;