fix: app hang when loading
This commit is contained in:
@@ -5,10 +5,10 @@ use serde::Serialize;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
use tauri::{Emitter, Manager, State};
|
||||
|
||||
use crate::Nostr;
|
||||
use crate::{Nostr, BOOTSTRAP_RELAYS};
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
struct Payload {
|
||||
struct EventPayload {
|
||||
event: String,
|
||||
sender: String,
|
||||
}
|
||||
@@ -32,7 +32,8 @@ pub async fn get_metadata(id: String, state: State<'_, Nostr>) -> Result<String,
|
||||
let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?;
|
||||
let filter = Filter::new().author(public_key).kind(Kind::Metadata).limit(1);
|
||||
|
||||
match client.get_events_of(vec![filter], Some(Duration::from_secs(2))).await {
|
||||
match client.get_events_from(BOOTSTRAP_RELAYS, vec![filter], Some(Duration::from_secs(3))).await
|
||||
{
|
||||
Ok(events) => {
|
||||
if let Some(event) = events.first() {
|
||||
Ok(Metadata::from_json(&event.content).unwrap_or(Metadata::new()).as_json())
|
||||
@@ -150,11 +151,16 @@ pub async fn connect_account(uri: &str, state: State<'_, Nostr>) -> Result<Strin
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, ()> {
|
||||
let contact_list = state.contact_list.lock().await;
|
||||
let list = contact_list.clone().into_iter().map(|c| c.public_key.to_hex()).collect::<Vec<_>>();
|
||||
pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
|
||||
let client = &state.client;
|
||||
|
||||
Ok(list)
|
||||
match client.get_contact_list(Some(Duration::from_secs(10))).await {
|
||||
Ok(contacts) => {
|
||||
let list = contacts.into_iter().map(|c| c.public_key.to_hex()).collect::<Vec<_>>();
|
||||
Ok(list)
|
||||
}
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -164,7 +170,7 @@ pub async fn get_inbox(id: String, state: State<'_, Nostr>) -> Result<Vec<String
|
||||
let public_key = PublicKey::parse(id).map_err(|e| e.to_string())?;
|
||||
let inbox = Filter::new().kind(Kind::Custom(10050)).author(public_key).limit(1);
|
||||
|
||||
match client.get_events_of(vec![inbox], None).await {
|
||||
match client.get_events_from(BOOTSTRAP_RELAYS, vec![inbox], None).await {
|
||||
Ok(events) => {
|
||||
if let Some(event) = events.into_iter().next() {
|
||||
let urls = event
|
||||
@@ -246,14 +252,9 @@ pub async fn login(
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(contacts) = client.get_contact_list(Some(Duration::from_secs(10))).await {
|
||||
let mut contact_list = state.contact_list.lock().await;
|
||||
*contact_list = contacts;
|
||||
};
|
||||
|
||||
let inbox = Filter::new().kind(Kind::Custom(10050)).author(public_key).limit(1);
|
||||
|
||||
if let Ok(events) = client.get_events_of(vec![inbox], None).await {
|
||||
if let Ok(events) = client.get_events_of(vec![inbox], Some(Duration::from_secs(5))).await {
|
||||
if let Some(event) = events.into_iter().next() {
|
||||
let urls = event
|
||||
.tags()
|
||||
@@ -279,36 +280,18 @@ pub async fn login(
|
||||
}
|
||||
}
|
||||
|
||||
let subscription_id = SubscriptionId::new("personal_inbox");
|
||||
let new_message = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
|
||||
let sub_id = SubscriptionId::new("personal_inbox");
|
||||
let new_message = Filter::new().kind(Kind::GiftWrap).pubkey(public_key).limit(0);
|
||||
|
||||
if client.subscription(&subscription_id).await.is_some() {
|
||||
if client.subscription(&sub_id).await.is_some() {
|
||||
// Remove old subscriotion
|
||||
client.unsubscribe(subscription_id.clone()).await;
|
||||
client.unsubscribe(sub_id.clone()).await;
|
||||
// Resubscribe new message for current user
|
||||
let _ = client.subscribe_with_id(subscription_id, vec![new_message], None).await;
|
||||
let _ = client.subscribe_with_id(sub_id.clone(), vec![new_message], None).await;
|
||||
} else {
|
||||
let _ = client.subscribe_with_id(subscription_id, vec![new_message], None).await;
|
||||
let _ = client.subscribe_with_id(sub_id, vec![new_message], None).await;
|
||||
}
|
||||
|
||||
let handle_clone = handle.app_handle().clone();
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let window = handle_clone.get_webview_window("main").expect("Window is terminated.");
|
||||
let state = window.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
|
||||
let sync = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
|
||||
|
||||
if client.reconcile(sync.clone(), NegentropyOptions::default()).await.is_ok() {
|
||||
handle_clone.emit("synchronized", ()).unwrap();
|
||||
};
|
||||
|
||||
if client.get_events_of(vec![sync], Some(Duration::from_secs(20))).await.is_ok() {
|
||||
handle_clone.emit("synchronized", ()).unwrap();
|
||||
};
|
||||
});
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let window = handle.get_webview_window("main").expect("Window is terminated.");
|
||||
let state = window.state::<Nostr>();
|
||||
@@ -323,7 +306,7 @@ pub async fn login(
|
||||
{
|
||||
if let Err(e) = window.emit(
|
||||
"event",
|
||||
Payload { event: rumor.as_json(), sender: sender.to_hex() },
|
||||
EventPayload { event: rumor.as_json(), sender: sender.to_hex() },
|
||||
) {
|
||||
println!("emit failed: {}", e)
|
||||
}
|
||||
|
||||
@@ -15,24 +15,27 @@ pub async fn get_chats(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
|
||||
|
||||
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
|
||||
|
||||
let events = match client.database().query(vec![filter], Order::Desc).await {
|
||||
let rumors = match client.get_events_of(vec![filter], Some(Duration::from_secs(20))).await {
|
||||
Ok(events) => {
|
||||
stream::iter(events)
|
||||
.filter_map(|ev| async move {
|
||||
if let Ok(UnwrappedGift { rumor, .. }) = client.unwrap_gift_wrap(&ev).await {
|
||||
if rumor.kind == Kind::PrivateDirectMessage {
|
||||
return Some(rumor);
|
||||
Some(rumor)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.await
|
||||
}
|
||||
Err(err) => return Err(err.to_string()),
|
||||
Err(e) => return Err(e.to_string()),
|
||||
};
|
||||
|
||||
let uniqs = events
|
||||
let uniqs = rumors
|
||||
.into_iter()
|
||||
.sorted_by_key(|ev| Reverse(ev.created_at))
|
||||
.filter(|ev| ev.pubkey != public_key)
|
||||
@@ -47,14 +50,14 @@ pub async fn get_chats(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
|
||||
#[specta::specta]
|
||||
pub async fn get_chat_messages(id: String, state: State<'_, Nostr>) -> Result<Vec<String>, String> {
|
||||
let client = &state.client;
|
||||
let signer = client.signer().await.map_err(|e| e.to_string())?;
|
||||
|
||||
let signer = client.signer().await.map_err(|e| e.to_string())?;
|
||||
let receiver_pk = signer.public_key().await.map_err(|e| e.to_string())?;
|
||||
let sender_pk = PublicKey::parse(id).map_err(|e| e.to_string())?;
|
||||
|
||||
let filter = Filter::new().kind(Kind::GiftWrap).pubkeys(vec![receiver_pk, sender_pk]);
|
||||
|
||||
let rumors = match client.database().query(vec![filter], Order::Desc).await {
|
||||
let rumors = match client.get_events_of(vec![filter], None).await {
|
||||
Ok(events) => {
|
||||
stream::iter(events)
|
||||
.filter_map(|ev| async move {
|
||||
|
||||
@@ -16,10 +16,17 @@ mod common;
|
||||
|
||||
pub struct Nostr {
|
||||
client: Client,
|
||||
contact_list: Mutex<Vec<Contact>>,
|
||||
inbox_relays: Mutex<HashMap<PublicKey, Vec<String>>>,
|
||||
}
|
||||
|
||||
// TODO: Allow user config bootstrap relays.
|
||||
pub const BOOTSTRAP_RELAYS: [&str; 4] = [
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.nostr.net/",
|
||||
"wss://relay.0xchat.com/",
|
||||
"wss://nostr.wine/",
|
||||
];
|
||||
|
||||
fn main() {
|
||||
let invoke_handler = {
|
||||
let builder = tauri_specta::ts::builder().commands(tauri_specta::collect_commands![
|
||||
@@ -67,6 +74,19 @@ fn main() {
|
||||
#[cfg(target_os = "macos")]
|
||||
main_window.set_traffic_lights_inset(12.0, 18.0).unwrap();
|
||||
|
||||
// Workaround for reset traffic light when window resized
|
||||
#[cfg(target_os = "macos")]
|
||||
let win_ = main_window.clone();
|
||||
#[cfg(target_os = "macos")]
|
||||
main_window.on_window_event(move |event| {
|
||||
if let tauri::WindowEvent::Resized(_) = event {
|
||||
win_.set_traffic_lights_inset(12.0, 18.0).unwrap();
|
||||
}
|
||||
if let tauri::WindowEvent::ThemeChanged(_) = event {
|
||||
win_.set_traffic_lights_inset(12.0, 18.0).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
// Restore native border
|
||||
#[cfg(target_os = "macos")]
|
||||
main_window.add_border(None);
|
||||
@@ -81,16 +101,14 @@ fn main() {
|
||||
|
||||
// Setup nostr client
|
||||
let opts = Options::new()
|
||||
.timeout(Duration::from_secs(30))
|
||||
.send_timeout(Some(Duration::from_secs(5)))
|
||||
.connection_timeout(Some(Duration::from_secs(5)));
|
||||
.timeout(Duration::from_secs(40))
|
||||
.send_timeout(Some(Duration::from_secs(10)))
|
||||
.connection_timeout(Some(Duration::from_secs(10)));
|
||||
|
||||
let client = ClientBuilder::default().opts(opts).database(database).build();
|
||||
|
||||
// Add bootstrap relay
|
||||
let _ = client
|
||||
.add_relays(["wss://relay.poster.place/", "wss://bostr.nokotaro.com/"])
|
||||
.await;
|
||||
let _ = client.add_relays(BOOTSTRAP_RELAYS).await;
|
||||
|
||||
// Connect
|
||||
client.connect().await;
|
||||
@@ -99,11 +117,7 @@ fn main() {
|
||||
});
|
||||
|
||||
// Create global state
|
||||
app.manage(Nostr {
|
||||
client,
|
||||
contact_list: Mutex::new(Vec::new()),
|
||||
inbox_relays: Mutex::new(HashMap::new()),
|
||||
});
|
||||
app.manage(Nostr { client, inbox_relays: Mutex::new(HashMap::new()) });
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user