chore: improve logout behavior (#118)

* resubscribe on logout

* .

* .
This commit is contained in:
reya
2025-08-10 10:43:28 +07:00
committed by GitHub
parent 5011becacb
commit ca622d1262
5 changed files with 95 additions and 88 deletions

View File

@@ -111,55 +111,9 @@ impl ChatSpace {
subscriptions.push(cx.observe_in( subscriptions.push(cx.observe_in(
&client_keys, &client_keys,
window, window,
|_this: &mut Self, state, window, cx| { |this: &mut Self, state, window, cx| {
if !state.read(cx).has_keys() { if !state.read(cx).has_keys() {
let title = SharedString::new(t!("startup.client_keys_warning")); this.render_client_keys_modal(window, cx);
let desc = SharedString::new(t!("startup.client_keys_desc"));
window.open_modal(cx, move |this, _window, cx| {
this.overlay_closable(false)
.show_close(false)
.keyboard(false)
.confirm()
.button_props(
ModalButtonProps::default()
.cancel_text(t!("startup.create_new_keys"))
.ok_text(t!("common.allow")),
)
.child(
div()
.w_full()
.h_40()
.flex()
.flex_col()
.gap_1()
.items_center()
.justify_center()
.text_center()
.text_sm()
.child(
div()
.font_semibold()
.text_color(cx.theme().text_muted)
.child(title.clone()),
)
.child(desc.clone()),
)
.on_cancel(|_, _window, cx| {
ClientKeys::global(cx).update(cx, |this, cx| {
this.new_keys(cx);
});
// true: Close modal
true
})
.on_ok(|_, window, cx| {
ClientKeys::global(cx).update(cx, |this, cx| {
this.load(window, cx);
});
// true: Close modal
true
})
});
} }
}, },
)); ));
@@ -301,8 +255,13 @@ impl ChatSpace {
} }
fn on_sign_out(&mut self, _ev: &Logout, window: &mut Window, cx: &mut Context<Self>) { fn on_sign_out(&mut self, _ev: &Logout, window: &mut Window, cx: &mut Context<Self>) {
let registry = Registry::global(cx);
let identity = Identity::global(cx); let identity = Identity::global(cx);
// TODO: save current session?
registry.update(cx, |this, cx| {
this.reset(cx);
});
identity.update(cx, |this, cx| { identity.update(cx, |this, cx| {
this.unload(window, cx); this.unload(window, cx);
}); });
@@ -326,6 +285,56 @@ impl ChatSpace {
}); });
} }
fn render_client_keys_modal(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let title = SharedString::new(t!("startup.client_keys_warning"));
let desc = SharedString::new(t!("startup.client_keys_desc"));
window.open_modal(cx, move |this, _window, cx| {
this.overlay_closable(false)
.show_close(false)
.keyboard(false)
.confirm()
.button_props(
ModalButtonProps::default()
.cancel_text(t!("startup.create_new_keys"))
.ok_text(t!("common.allow")),
)
.child(
div()
.w_full()
.h_40()
.flex()
.flex_col()
.gap_1()
.items_center()
.justify_center()
.text_center()
.text_sm()
.child(
div()
.font_semibold()
.text_color(cx.theme().text_muted)
.child(title.clone()),
)
.child(desc.clone()),
)
.on_cancel(|_, _window, cx| {
ClientKeys::global(cx).update(cx, |this, cx| {
this.new_keys(cx);
});
// true: Close modal
true
})
.on_ok(|_, window, cx| {
ClientKeys::global(cx).update(cx, |this, cx| {
this.load(window, cx);
});
// true: Close modal
true
})
});
}
fn render_titlebar_left_side( fn render_titlebar_left_side(
&mut self, &mut self,
_window: &mut Window, _window: &mut Window,

View File

@@ -358,8 +358,6 @@ async fn handle_nostr_notifications(
let client = nostr_client(); let client = nostr_client();
let auto_close = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); let auto_close = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
let mut notifications = client.notifications(); let mut notifications = client.notifications();
let mut processed_relay_list = false;
let mut processed_inbox_relay = false;
while let Ok(notification) = notifications.recv().await { while let Ok(notification) = notifications.recv().await {
let RelayPoolNotification::Message { message, .. } = notification else { let RelayPoolNotification::Message { message, .. } = notification else {
@@ -379,11 +377,6 @@ async fn handle_nostr_notifications(
Kind::RelayList => { Kind::RelayList => {
// Get metadata for event's pubkey that matches the current user's pubkey // Get metadata for event's pubkey that matches the current user's pubkey
if let Ok(true) = is_from_current_user(&event).await { if let Ok(true) = is_from_current_user(&event).await {
match processed_relay_list {
true => continue,
false => processed_relay_list = true,
}
let sub_id = SubscriptionId::new("metadata"); let sub_id = SubscriptionId::new("metadata");
let filter = Filter::new() let filter = Filter::new()
.kinds(vec![Kind::Metadata, Kind::ContactList, Kind::InboxRelays]) .kinds(vec![Kind::Metadata, Kind::ContactList, Kind::InboxRelays])
@@ -398,11 +391,6 @@ async fn handle_nostr_notifications(
} }
Kind::InboxRelays => { Kind::InboxRelays => {
if let Ok(true) = is_from_current_user(&event).await { if let Ok(true) = is_from_current_user(&event).await {
match processed_inbox_relay {
true => continue,
false => processed_inbox_relay = true,
}
// Get all inbox relays // Get all inbox relays
let relays = event let relays = event
.tags .tags
@@ -423,8 +411,6 @@ async fn handle_nostr_notifications(
_ = client.connect_relay(relay).await; _ = client.connect_relay(relay).await;
} }
log::info!("Connected to messaging relays");
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(event.pubkey); let filter = Filter::new().kind(Kind::GiftWrap).pubkey(event.pubkey);
let sub_id = SubscriptionId::new("gift-wrap"); let sub_id = SubscriptionId::new("gift-wrap");
@@ -436,7 +422,7 @@ async fn handle_nostr_notifications(
.await .await
.is_ok() .is_ok()
{ {
log::info!("Subscribing to gift wrap events in: {relays:?}"); log::info!("Subscribing to messages in: {relays:?}");
} }
} }
} }

View File

@@ -54,9 +54,9 @@ pub fn nostr_client() -> &'static Client {
.gossip(true) .gossip(true)
.automatic_authentication(true) .automatic_authentication(true)
.verify_subscriptions(false) .verify_subscriptions(false)
// Sleep after idle for 20 seconds // Sleep after idle for 30 seconds
.sleep_when_idle(SleepWhenIdle::Enabled { .sleep_when_idle(SleepWhenIdle::Enabled {
timeout: Duration::from_secs(20), timeout: Duration::from_secs(30),
}); });
ClientBuilder::default().database(lmdb).opts(opts).build() ClientBuilder::default().database(lmdb).opts(opts).build()

View File

@@ -127,8 +127,9 @@ impl Identity {
.kind(Kind::ApplicationSpecificData) .kind(Kind::ApplicationSpecificData)
.identifier(ACCOUNT_D); .identifier(ACCOUNT_D);
// Unset signer // Reset the nostr client
client.unset_signer().await; client.unset_signer().await;
client.unsubscribe_all().await;
// Delete account // Delete account
client.database().delete(filter).await?; client.database().delete(filter).await?;
@@ -257,7 +258,7 @@ impl Identity {
this.set_public_key(None, window, cx); this.set_public_key(None, window, cx);
}) })
.ok(); .ok();
// Close modal // true to close the modal
true true
}) })
.on_ok(move |_, window, cx| { .on_ok(move |_, window, cx| {
@@ -271,7 +272,7 @@ impl Identity {
this.verify_keys(enc, password, weak_error, window, cx); this.verify_keys(enc, password, weak_error, window, cx);
}) })
.ok(); .ok();
// false to keep the modal open
false false
}) })
.child( .child(
@@ -321,25 +322,33 @@ impl Identity {
} }
// Decrypt the password in the background to prevent blocking the main thread // Decrypt the password in the background to prevent blocking the main thread
let task: Task<Option<SecretKey>> = let task: Task<Result<SecretKey, Error>> = cx.background_spawn(async move {
cx.background_spawn(async move { enc.decrypt(&password).ok() }); let secret = enc.decrypt(&password)?;
Ok(secret)
});
cx.spawn_in(window, async move |this, cx| { cx.spawn_in(window, async move |this, cx| {
if let Some(secret) = task.await { match task.await {
cx.update(|window, cx| { Ok(secret) => {
window.close_modal(cx); cx.update(|window, cx| {
// Update user's signer with decrypted secret key this.update(cx, |this, cx| {
this.update(cx, |this, cx| { // Update user's signer with decrypted secret key
this.set_signer(Keys::new(secret), window, cx); this.set_signer(Keys::new(secret), window, cx);
// Close the current modal
window.close_modal(cx);
})
.ok();
}) })
.ok(); .ok();
}) }
.ok(); Err(e) => {
} else { error
_ = error.update(cx, |this, cx| { .update(cx, |this, cx| {
*this = Some("Invalid password".into()); *this = Some(e.to_string().into());
cx.notify(); cx.notify();
}); })
.ok();
}
} }
}) })
.detach(); .detach();
@@ -597,15 +606,12 @@ async fn get_nip65_relays(public_key: PublicKey) -> Result<(), Error> {
let client = nostr_client(); let client = nostr_client();
let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
let sub_id = SubscriptionId::new("nip65-relays"); let sub_id = SubscriptionId::new("nip65-relays");
let filter = Filter::new() let filter = Filter::new()
.kind(Kind::RelayList) .kind(Kind::RelayList)
.author(public_key) .author(public_key)
.limit(1); .limit(1);
if client.subscription(&sub_id).await.is_empty() { client.subscribe_with_id(sub_id, filter, Some(opts)).await?;
client.subscribe_with_id(sub_id, filter, Some(opts)).await?;
}
Ok(()) Ok(())
} }

View File

@@ -101,6 +101,12 @@ impl Registry {
} }
} }
pub fn reset(&mut self, cx: &mut Context<Self>) {
self.rooms = vec![];
self.loading = true;
cx.notify();
}
pub(crate) fn set_persons_from_task( pub(crate) fn set_persons_from_task(
&mut self, &mut self,
task: Task<Result<Vec<Profile>, Error>>, task: Task<Result<Vec<Profile>, Error>>,