refactor
This commit is contained in:
@@ -7,6 +7,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use anyhow::{Context as AnyhowContext, Error, anyhow};
|
use anyhow::{Context as AnyhowContext, Error, anyhow};
|
||||||
use common::EventUtils;
|
use common::EventUtils;
|
||||||
|
use device::{DeviceEvent, DeviceRegistry};
|
||||||
use fuzzy_matcher::FuzzyMatcher;
|
use fuzzy_matcher::FuzzyMatcher;
|
||||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@@ -104,7 +105,7 @@ pub struct ChatRegistry {
|
|||||||
tasks: SmallVec<[Task<Result<(), Error>>; 2]>,
|
tasks: SmallVec<[Task<Result<(), Error>>; 2]>,
|
||||||
|
|
||||||
/// Subscriptions
|
/// Subscriptions
|
||||||
_subscriptions: SmallVec<[Subscription; 1]>,
|
_subscriptions: SmallVec<[Subscription; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<ChatEvent> for ChatRegistry {}
|
impl EventEmitter<ChatEvent> for ChatRegistry {}
|
||||||
@@ -123,17 +124,48 @@ impl ChatRegistry {
|
|||||||
/// Create a new chat registry instance
|
/// Create a new chat registry instance
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
let device = DeviceRegistry::global(cx);
|
||||||
|
|
||||||
let (tx, rx) = flume::unbounded::<Signal>();
|
let (tx, rx) = flume::unbounded::<Signal>();
|
||||||
let mut subscriptions = smallvec![];
|
let mut subscriptions = smallvec![];
|
||||||
|
|
||||||
subscriptions.push(
|
subscriptions.push(
|
||||||
// Subscribe to the signer event
|
// Subscribe to the signer event
|
||||||
cx.subscribe(&nostr, |this, _state, event, cx| {
|
cx.subscribe_in(&nostr, window, |this, state, event, window, cx| {
|
||||||
if event == &StateEvent::SignerSet {
|
if event == &StateEvent::SignerSet {
|
||||||
this.reset(cx);
|
this.reset(cx);
|
||||||
this.get_contact_list(cx);
|
this.get_contact_list(cx);
|
||||||
this.get_messages(cx);
|
|
||||||
this.get_rooms(cx);
|
this.get_rooms(cx);
|
||||||
|
|
||||||
|
let signer = state.read(cx).signer();
|
||||||
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
|
let user_signer = signer.get().await;
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.get_messages(user_signer, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
subscriptions.push(
|
||||||
|
// Subscribe to the device event
|
||||||
|
cx.subscribe_in(&device, window, |_this, _s, event, window, cx| {
|
||||||
|
if event == &DeviceEvent::Set {
|
||||||
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
let signer = nostr.read(cx).signer();
|
||||||
|
|
||||||
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
|
if let Some(device_signer) = signer.get_encryption_signer().await {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.get_messages(device_signer, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -297,7 +329,7 @@ impl ChatRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get contact list from relays
|
/// Get contact list from relays
|
||||||
pub fn get_contact_list(&mut self, cx: &mut Context<Self>) {
|
fn get_contact_list(&mut self, cx: &mut Context<Self>) {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let client = nostr.read(cx).client();
|
let client = nostr.read(cx).client();
|
||||||
let signer = nostr.read(cx).signer();
|
let signer = nostr.read(cx).signer();
|
||||||
@@ -327,9 +359,12 @@ impl ChatRegistry {
|
|||||||
self.tasks.push(task);
|
self.tasks.push(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all messages for current user
|
/// Get all messages for the provided signer
|
||||||
pub fn get_messages(&mut self, cx: &mut Context<Self>) {
|
fn get_messages<T>(&mut self, signer: T, cx: &mut Context<Self>)
|
||||||
let task = self.subscribe_gift_wrap_events(cx);
|
where
|
||||||
|
T: NostrSigner + 'static,
|
||||||
|
{
|
||||||
|
let task = self.subscribe_gift_wrap_events(signer, cx);
|
||||||
|
|
||||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||||
match task.await {
|
match task.await {
|
||||||
@@ -382,18 +417,20 @@ impl ChatRegistry {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Continuously get gift wrap events for the current user in their messaging relays
|
/// Continuously get gift wrap events for the signer
|
||||||
fn subscribe_gift_wrap_events(&self, cx: &App) -> Task<Result<(), Error>> {
|
fn subscribe_gift_wrap_events<T>(&self, signer: T, cx: &App) -> Task<Result<(), Error>>
|
||||||
|
where
|
||||||
|
T: NostrSigner + 'static,
|
||||||
|
{
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let client = nostr.read(cx).client();
|
let client = nostr.read(cx).client();
|
||||||
let signer = nostr.read(cx).signer();
|
|
||||||
let urls = self.get_messaging_relays(cx);
|
let urls = self.get_messaging_relays(cx);
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
let urls = urls.await?;
|
let urls = urls.await?;
|
||||||
let public_key = signer.get_public_key().await?;
|
let public_key = signer.get_public_key().await?;
|
||||||
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
|
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
|
||||||
let id = SubscriptionId::new(USER_GIFTWRAP);
|
let id = SubscriptionId::new(format!("{}-msg", public_key.to_hex()));
|
||||||
|
|
||||||
// Ensure relay connections
|
// Ensure relay connections
|
||||||
for url in urls.iter() {
|
for url in urls.iter() {
|
||||||
@@ -417,6 +454,31 @@ impl ChatRegistry {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refresh the chat registry, fetching messages and contact list from relays.
|
||||||
|
pub fn refresh(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
self.reset(cx);
|
||||||
|
self.get_contact_list(cx);
|
||||||
|
self.get_rooms(cx);
|
||||||
|
|
||||||
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
let signer = nostr.read(cx).signer();
|
||||||
|
|
||||||
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
|
let user_signer = signer.get().await;
|
||||||
|
let device_signer = signer.get_encryption_signer().await;
|
||||||
|
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.get_messages(user_signer, cx);
|
||||||
|
|
||||||
|
if let Some(device_signer) = device_signer {
|
||||||
|
this.get_messages(device_signer, cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the initializing status of the chat registry
|
/// Set the initializing status of the chat registry
|
||||||
fn set_initializing(&mut self, initializing: bool, cx: &mut Context<Self>) {
|
fn set_initializing(&mut self, initializing: bool, cx: &mut Context<Self>) {
|
||||||
self.initializing = initializing;
|
self.initializing = initializing;
|
||||||
|
|||||||
@@ -92,14 +92,14 @@ fn main() {
|
|||||||
// Initialize relay auth registry
|
// Initialize relay auth registry
|
||||||
relay_auth::init(window, cx);
|
relay_auth::init(window, cx);
|
||||||
|
|
||||||
// Initialize app registry
|
|
||||||
chat::init(window, cx);
|
|
||||||
|
|
||||||
// Initialize device signer
|
// Initialize device signer
|
||||||
//
|
//
|
||||||
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
||||||
device::init(window, cx);
|
device::init(window, cx);
|
||||||
|
|
||||||
|
// Initialize app registry
|
||||||
|
chat::init(window, cx);
|
||||||
|
|
||||||
// Initialize auto update
|
// Initialize auto update
|
||||||
auto_update::init(window, cx);
|
auto_update::init(window, cx);
|
||||||
|
|
||||||
|
|||||||
@@ -354,8 +354,9 @@ impl Workspace {
|
|||||||
}
|
}
|
||||||
Command::RefreshMessagingRelays => {
|
Command::RefreshMessagingRelays => {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
|
// Trigger a refresh of the chat registry
|
||||||
chat.update(cx, |this, cx| {
|
chat.update(cx, |this, cx| {
|
||||||
this.get_messages(cx);
|
this.refresh(window, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Command::ShowRelayList => {
|
Command::ShowRelayList => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -11,7 +11,7 @@ use gpui::{
|
|||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use person::PersonRegistry;
|
use person::PersonRegistry;
|
||||||
use state::{Announcement, DEVICE_GIFTWRAP, NostrRegistry, StateEvent, TIMEOUT, app_name};
|
use state::{Announcement, NostrRegistry, StateEvent, TIMEOUT, app_name};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::avatar::Avatar;
|
use ui::avatar::Avatar;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
@@ -213,76 +213,14 @@ impl DeviceRegistry {
|
|||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
|
this.set_initializing(false, cx);
|
||||||
cx.emit(DeviceEvent::Set);
|
cx.emit(DeviceEvent::Set);
|
||||||
this.get_messages(cx);
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all messages for encryption keys
|
|
||||||
fn get_messages(&mut self, cx: &mut Context<Self>) {
|
|
||||||
let task = self.subscribe_gift_wrap_events(cx);
|
|
||||||
|
|
||||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
|
||||||
if let Err(e) = task.await {
|
|
||||||
this.update(cx, |_this, cx| {
|
|
||||||
cx.emit(DeviceEvent::error(e.to_string()));
|
|
||||||
})?;
|
|
||||||
} else {
|
|
||||||
this.update(cx, |this, cx| {
|
|
||||||
this.set_initializing(false, cx);
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Continuously get gift wrap events for the current user in their messaging relays
|
|
||||||
fn subscribe_gift_wrap_events(&self, cx: &App) -> Task<Result<(), Error>> {
|
|
||||||
let persons = PersonRegistry::global(cx);
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
|
||||||
let client = nostr.read(cx).client();
|
|
||||||
let signer = nostr.read(cx).signer();
|
|
||||||
|
|
||||||
let Some(user) = signer.public_key() else {
|
|
||||||
return Task::ready(Err(anyhow!("User not found")));
|
|
||||||
};
|
|
||||||
|
|
||||||
let profile = persons.read(cx).get(&user, cx);
|
|
||||||
let relays = profile.messaging_relays().clone();
|
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
|
||||||
let encryption = signer.get_encryption_signer().await.context("not found")?;
|
|
||||||
let public_key = encryption.get_public_key().await?;
|
|
||||||
|
|
||||||
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
|
|
||||||
let id = SubscriptionId::new(DEVICE_GIFTWRAP);
|
|
||||||
|
|
||||||
// Ensure user has relays configured
|
|
||||||
if relays.is_empty() {
|
|
||||||
return Err(anyhow!("No messaging relays found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure relays are connected
|
|
||||||
for url in relays.iter() {
|
|
||||||
client.add_relay(url).and_connect().await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct target for subscription
|
|
||||||
let target: HashMap<RelayUrl, Filter> = relays
|
|
||||||
.into_iter()
|
|
||||||
.map(|relay| (relay, filter.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Subscribe
|
|
||||||
client.subscribe(target).with_id(id).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Backup the encryption's secret key to a file
|
/// Backup the encryption's secret key to a file
|
||||||
pub fn backup(&self, path: PathBuf, cx: &App) -> Task<Result<(), Error>> {
|
pub fn backup(&self, path: PathBuf, cx: &App) -> Task<Result<(), Error>> {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
|||||||
Reference in New Issue
Block a user