From 017a3676a41c8d457400cd95a16189889edb4ac5 Mon Sep 17 00:00:00 2001 From: reya <123083837+reyamir@users.noreply.github.com> Date: Sun, 30 Jun 2024 21:06:04 +0700 Subject: [PATCH] feat: optimize spawn thread --- apps/desktop2/src/routes/$account.tsx | 6 +- apps/desktop2/src/routes/panel.tsx | 212 +++++++++++++------------- src-tauri/src/nostr/internal.rs | 75 +++++++++ src-tauri/src/nostr/keys.rs | 188 +++++++---------------- src-tauri/src/nostr/mod.rs | 1 + 5 files changed, 243 insertions(+), 239 deletions(-) create mode 100644 src-tauri/src/nostr/internal.rs diff --git a/apps/desktop2/src/routes/$account.tsx b/apps/desktop2/src/routes/$account.tsx index cdca5643..51c108b8 100644 --- a/apps/desktop2/src/routes/$account.tsx +++ b/apps/desktop2/src/routes/$account.tsx @@ -202,10 +202,10 @@ const Search = memo(function Search() { diff --git a/apps/desktop2/src/routes/panel.tsx b/apps/desktop2/src/routes/panel.tsx index e6ab6b18..e28d54b5 100644 --- a/apps/desktop2/src/routes/panel.tsx +++ b/apps/desktop2/src/routes/panel.tsx @@ -122,6 +122,7 @@ function Screen() { NostrQuery.getNotifications() .then((data) => { const sorted = data.sort((a, b) => b.created_at - a.created_at); + console.log("sorted"); setEvents(sorted); }) .catch((e) => console.log(e)); @@ -156,7 +157,7 @@ function Screen() { } return ( -
+

Notifications

@@ -176,102 +177,112 @@ function Screen() {
- - - - Replies - - - Reactions - - - Zaps - - -
- - {texts.map((event, index) => ( - // biome-ignore lint/suspicious/noArrayIndexKey: - - ))} - - - {[...reactions.entries()].map(([root, events]) => ( -
-
-
- -
-
- {events.map((event) => ( - - - -
- {event.kind === Kind.Reaction ? ( - event.content === "+" ? ( - "👍" + + + + Replies + + + Reactions + + + Zaps + + +
+ + {texts.map((event, index) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: + + ))} + + + {[...reactions.entries()].map(([root, events]) => ( +
+
+
+ +
+
+ {events.map((event) => ( + + + +
+ {event.kind === Kind.Reaction ? ( + event.content === "+" ? ( + "👍" + ) : ( + event.content + ) ) : ( - event.content - ) - ) : ( - - )} -
-
-
- ))} + + )} +
+ + + ))} +
-
- ))} - - - {[...zaps.entries()].map(([root, events]) => ( -
-
-
- -
-
- {events.map((event) => ( - tag[0] === "P")[1]} - > - - -
- ₿ {decodeZapInvoice(event.tags).bitcoinFormatted} -
-
-
- ))} + ))} + + + {[...zaps.entries()].map(([root, events]) => ( +
+
+
+ +
+
+ {events.map((event) => ( + tag[0] === "P")[1]} + > + + +
+ ₿ {decodeZapInvoice(event.tags).bitcoinFormatted} +
+
+
+ ))} +
-
- ))} - -
- + ))} + +
+ + + + + +
); } @@ -281,22 +292,9 @@ function Tab({ value, children }: { value: string; children: ReactNode[] }) { return ( - - - {children} - - - - - - + + {children} + ); } diff --git a/src-tauri/src/nostr/internal.rs b/src-tauri/src/nostr/internal.rs new file mode 100644 index 00000000..0b4aaffc --- /dev/null +++ b/src-tauri/src/nostr/internal.rs @@ -0,0 +1,75 @@ +use crate::Settings; +use nostr_sdk::prelude::*; + +pub async fn init_nip65(client: &Client) { + let signer = client.signer().await.unwrap(); + let public_key = signer.public_key().await.unwrap(); + + if let Ok(events) = client + .get_events_of( + vec![Filter::new() + .author(public_key) + .kind(Kind::RelayList) + .limit(1)], + None, + ) + .await + { + if let Some(event) = events.first() { + let relay_list = nip65::extract_relay_list(event); + for item in relay_list.into_iter() { + let relay_url = item.0.to_string(); + let opts = match item.1 { + Some(val) => { + if val == &RelayMetadata::Read { + RelayOptions::new().read(true).write(false) + } else { + RelayOptions::new().write(true).read(false) + } + } + None => RelayOptions::default(), + }; + + // Add relay to relay pool + let _ = client + .add_relay_with_opts(&relay_url, opts) + .await + .unwrap_or_default(); + + // Connect relay + client.connect_relay(relay_url).await.unwrap_or_default(); + println!("connecting to relay: {} - {:?}", item.0, item.1); + } + } + }; +} + +pub async fn get_user_settings(client: &Client) -> Result { + let ident = "lume:settings"; + let signer = client.signer().await.unwrap(); + let public_key = signer.public_key().await.unwrap(); + + let filter = Filter::new() + .author(public_key) + .kind(Kind::ApplicationSpecificData) + .identifier(ident) + .limit(1); + + if let Ok(events) = client.get_events_of(vec![filter], None).await { + if let Some(event) = events.first() { + let content = event.content(); + if let Ok(decrypted) = signer.nip44_decrypt(public_key, content).await { + match serde_json::from_str(&decrypted) { + Ok(parsed) => parsed, + Err(_) => Err("Could not parse settings payload".into()), + } + } else { + Err("Decrypt settings failed.".into()) + } + } else { + Err("Settings not found.".into()) + } + } else { + Err("Settings not found.".into()) + } +} diff --git a/src-tauri/src/nostr/keys.rs b/src-tauri/src/nostr/keys.rs index 1ed45291..a3ce615d 100644 --- a/src-tauri/src/nostr/keys.rs +++ b/src-tauri/src/nostr/keys.rs @@ -1,16 +1,16 @@ -use std::time::Duration; - use keyring::Entry; use keyring_search::{Limit, List, Search}; use nostr_sdk::prelude::*; use serde::Serialize; use specta::Type; +use std::time::Duration; use tauri::{EventTarget, Manager, State}; use tauri_plugin_notification::NotificationExt; use crate::nostr::event::RichEvent; +use crate::nostr::internal::{get_user_settings, init_nip65}; use crate::nostr::utils::parse_event; -use crate::{Nostr, Settings, NEWSFEED_NEG_LIMIT, NOTIFICATION_NEG_LIMIT}; +use crate::{Nostr, NEWSFEED_NEG_LIMIT, NOTIFICATION_NEG_LIMIT}; #[derive(Serialize, Type)] pub struct Account { @@ -167,6 +167,7 @@ pub async fn load_account( state: State<'_, Nostr>, app: tauri::AppHandle, ) -> Result { + let handle = app.clone(); let client = &state.client; let keyring = Entry::new(npub, "nostr_secret").unwrap(); @@ -198,122 +199,64 @@ pub async fn load_account( } } - // Verify signer - let signer = client.signer().await.unwrap(); - let public_key = signer.public_key().await.unwrap(); - // Connect to user's relay (NIP-65) - if let Ok(events) = client - .get_events_of( - vec![Filter::new() - .author(public_key) - .kind(Kind::RelayList) - .limit(1)], - None, - ) - .await - { - if let Some(event) = events.first() { - let relay_list = nip65::extract_relay_list(event); - for item in relay_list.into_iter() { - let relay_url = item.0.to_string(); - let opts = match item.1 { - Some(val) => { - if val == &RelayMetadata::Read { - RelayOptions::new().read(true).write(false) - } else { - RelayOptions::new().write(true).read(false) - } - } - None => RelayOptions::default(), - }; - - // Add relay to relay pool - let _ = client - .add_relay_with_opts(&relay_url, opts) - .await - .unwrap_or_default(); - - // Connect relay - client.connect_relay(relay_url).await.unwrap_or_default(); - println!("connecting to relay: {} - {:?}", item.0, item.1); - } - } - }; + init_nip65(client).await; // Get user's contact list if let Ok(contacts) = client.get_contact_list(None).await { *state.contact_list.lock().unwrap() = contacts }; - // Create a subscription for notification - let sub_id = SubscriptionId::new("notification"); - let filter = Filter::new() - .pubkey(public_key) - .kinds(vec![ - Kind::TextNote, - Kind::Repost, - Kind::Reaction, - Kind::ZapReceipt, - ]) - .since(Timestamp::now()); - - // Subscribe - print!("Subscribing for new notification..."); - client.subscribe_with_id(sub_id, vec![filter], None).await; - // Get user's settings - let handle = app.clone(); - // Spawn a thread to handle it + if let Ok(settings) = get_user_settings(client).await { + *state.settings.lock().unwrap() = settings + }; + tauri::async_runtime::spawn(async move { let window = handle.get_window("main").unwrap(); - let state = window.state::(); - let client = &state.client; - let ident = "lume:settings"; - let filter = Filter::new() - .author(public_key) - .kind(Kind::ApplicationSpecificData) - .identifier(ident) - .limit(1); - - if let Ok(events) = client - .get_events_of(vec![filter], Some(Duration::from_secs(5))) - .await - { - if let Some(event) = events.first() { - let content = event.content(); - if let Ok(decrypted) = signer.nip44_decrypt(public_key, content).await { - let parsed: Settings = - serde_json::from_str(&decrypted).expect("Could not parse settings payload"); - - *state.settings.lock().unwrap() = parsed; - } - } - } - }); - - // Run sync service - let handle = app.clone(); - // Spawn a thread to handle it - tauri::async_runtime::spawn(async move { - let window = handle.get_window("main").unwrap(); let state = window.state::(); let client = &state.client; let contact_list = state.contact_list.lock().unwrap().clone(); - let notification = Filter::new() - .pubkey(public_key) - .kinds(vec![ - Kind::TextNote, - Kind::Repost, - Kind::Reaction, - Kind::ZapReceipt, - ]) - .limit(NOTIFICATION_NEG_LIMIT); + let signer = client.signer().await.unwrap(); + let public_key = signer.public_key().await.unwrap(); + + if !contact_list.is_empty() { + let authors: Vec = contact_list.into_iter().map(|f| f.public_key).collect(); + + match client + .reconcile( + Filter::new() + .authors(authors) + .kinds(vec![Kind::TextNote, Kind::Repost]) + .limit(NEWSFEED_NEG_LIMIT), + NegentropyOptions::default(), + ) + .await + { + Ok(_) => { + if handle.emit_to(EventTarget::Any, "synced", true).is_err() { + println!("Emit event failed.") + } + } + Err(_) => println!("Sync newsfeed failed."), + } + }; match client - .reconcile(notification, NegentropyOptions::default()) + .reconcile( + Filter::new() + .pubkey(public_key) + .kinds(vec![ + Kind::TextNote, + Kind::Repost, + Kind::Reaction, + Kind::ZapReceipt, + ]) + .limit(NOTIFICATION_NEG_LIMIT), + NegentropyOptions::default(), + ) .await { Ok(_) => { @@ -324,34 +267,21 @@ pub async fn load_account( Err(_) => println!("Sync notification failed."), }; - if !contact_list.is_empty() { - let authors: Vec = contact_list.into_iter().map(|f| f.public_key).collect(); + let subscription_id = SubscriptionId::new("notification"); + let subscription = Filter::new() + .pubkey(public_key) + .kinds(vec![ + Kind::TextNote, + Kind::Repost, + Kind::Reaction, + Kind::ZapReceipt, + ]) + .since(Timestamp::now()); - let newsfeed = Filter::new() - .authors(authors) - .kinds(vec![Kind::TextNote, Kind::Repost]) - .limit(NEWSFEED_NEG_LIMIT); - - match client - .reconcile(newsfeed, NegentropyOptions::default()) - .await - { - Ok(_) => { - if handle.emit_to(EventTarget::Any, "synced", true).is_err() { - println!("Emit event failed.") - } - } - Err(_) => println!("Sync newsfeed failed."), - } - } - }); - - // Run notification service - // Spawn a thread to handle it - tauri::async_runtime::spawn(async move { - let window = app.get_window("main").unwrap(); - let state = window.state::(); - let client = &state.client; + // Subscribing for new notification... + client + .subscribe_with_id(subscription_id, vec![subscription], None) + .await; // Handle notifications client diff --git a/src-tauri/src/nostr/mod.rs b/src-tauri/src/nostr/mod.rs index cd35415b..a019f5a3 100644 --- a/src-tauri/src/nostr/mod.rs +++ b/src-tauri/src/nostr/mod.rs @@ -1,4 +1,5 @@ pub mod event; +mod internal; pub mod keys; pub mod metadata; pub mod relay;