chore: fix some gossip and nip4e bugs (#23)
Reviewed-on: #23 Co-authored-by: Ren Amamiya <reya@lume.nu> Co-committed-by: Ren Amamiya <reya@lume.nu>
This commit was merged in pull request #23.
This commit is contained in:
@@ -16,7 +16,7 @@ use gpui::{
|
||||
use nostr_sdk::prelude::*;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use smol::lock::RwLock;
|
||||
use state::{DEVICE_GIFTWRAP, NostrRegistry, StateEvent, TIMEOUT, USER_GIFTWRAP};
|
||||
use state::{CoopSigner, DEVICE_GIFTWRAP, NostrRegistry, StateEvent, TIMEOUT, USER_GIFTWRAP};
|
||||
|
||||
mod message;
|
||||
mod room;
|
||||
@@ -154,7 +154,6 @@ impl ChatRegistry {
|
||||
let rx = self.signal_rx.clone();
|
||||
|
||||
self.tasks.push(cx.background_spawn(async move {
|
||||
let device_signer = signer.get_encryption_signer().await;
|
||||
let mut notifications = client.notifications();
|
||||
let mut processed_events = HashSet::new();
|
||||
|
||||
@@ -183,7 +182,7 @@ impl ChatRegistry {
|
||||
}
|
||||
|
||||
// Extract the rumor from the gift wrap event
|
||||
match extract_rumor(&client, &device_signer, event.as_ref()).await {
|
||||
match extract_rumor(&client, &signer, event.as_ref()).await {
|
||||
Ok(rumor) => {
|
||||
if rumor.tags.is_empty() {
|
||||
let error: SharedString = "No room for message".into();
|
||||
@@ -682,7 +681,7 @@ impl ChatRegistry {
|
||||
/// Unwraps a gift-wrapped event and processes its contents.
|
||||
async fn extract_rumor(
|
||||
client: &Client,
|
||||
device_signer: &Option<Arc<dyn NostrSigner>>,
|
||||
signer: &Arc<CoopSigner>,
|
||||
gift_wrap: &Event,
|
||||
) -> Result<UnsignedEvent, Error> {
|
||||
// Try to get cached rumor first
|
||||
@@ -691,7 +690,7 @@ async fn extract_rumor(
|
||||
}
|
||||
|
||||
// Try to unwrap with the available signer
|
||||
let unwrapped = try_unwrap(client, device_signer, gift_wrap).await?;
|
||||
let unwrapped = try_unwrap(signer, gift_wrap).await?;
|
||||
let mut rumor = unwrapped.rumor;
|
||||
|
||||
// Generate event id for the rumor if it doesn't have one
|
||||
@@ -706,30 +705,27 @@ async fn extract_rumor(
|
||||
}
|
||||
|
||||
/// Helper method to try unwrapping with different signers
|
||||
async fn try_unwrap(
|
||||
client: &Client,
|
||||
device_signer: &Option<Arc<dyn NostrSigner>>,
|
||||
gift_wrap: &Event,
|
||||
) -> Result<UnwrappedGift, Error> {
|
||||
async fn try_unwrap(signer: &Arc<CoopSigner>, gift_wrap: &Event) -> Result<UnwrappedGift, Error> {
|
||||
// Try with the device signer first
|
||||
if let Some(signer) = device_signer
|
||||
&& let Ok(unwrapped) = try_unwrap_with(gift_wrap, signer).await
|
||||
{
|
||||
return Ok(unwrapped);
|
||||
};
|
||||
if let Some(signer) = signer.get_encryption_signer().await {
|
||||
log::info!("trying with encryption key");
|
||||
if let Ok(unwrapped) = try_unwrap_with(gift_wrap, &signer).await {
|
||||
return Ok(unwrapped);
|
||||
}
|
||||
}
|
||||
|
||||
// Try with the user's signer
|
||||
let user_signer = client.signer().context("Signer not found")?;
|
||||
let unwrapped = try_unwrap_with(gift_wrap, user_signer).await?;
|
||||
// Fallback to the user's signer
|
||||
let user_signer = signer.get().await;
|
||||
let unwrapped = try_unwrap_with(gift_wrap, &user_signer).await?;
|
||||
|
||||
Ok(unwrapped)
|
||||
}
|
||||
|
||||
/// Attempts to unwrap a gift wrap event with a given signer.
|
||||
async fn try_unwrap_with(
|
||||
gift_wrap: &Event,
|
||||
signer: &Arc<dyn NostrSigner>,
|
||||
) -> Result<UnwrappedGift, Error> {
|
||||
async fn try_unwrap_with<T>(gift_wrap: &Event, signer: &T) -> Result<UnwrappedGift, Error>
|
||||
where
|
||||
T: NostrSigner + 'static,
|
||||
{
|
||||
// Get the sealed event
|
||||
let seal = signer
|
||||
.nip44_decrypt(&gift_wrap.pubkey, &gift_wrap.content)
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Error;
|
||||
use anyhow::{Error, anyhow};
|
||||
use common::EventUtils;
|
||||
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task};
|
||||
use itertools::Itertools;
|
||||
@@ -354,17 +354,7 @@ impl Room {
|
||||
pub fn connect(&self, cx: &App) -> Task<Result<(), Error>> {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let client = nostr.read(cx).client();
|
||||
|
||||
let signer = nostr.read(cx).signer();
|
||||
let sender = signer.public_key();
|
||||
|
||||
// Get all members, excluding the sender
|
||||
let members: Vec<PublicKey> = self
|
||||
.members
|
||||
.iter()
|
||||
.filter(|public_key| Some(**public_key) != sender)
|
||||
.copied()
|
||||
.collect();
|
||||
let members = self.members();
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let opts = SubscribeAutoCloseOptions::default()
|
||||
@@ -515,45 +505,46 @@ impl Room {
|
||||
|
||||
// Handle encryption signer requirements
|
||||
if signer_kind.encryption() {
|
||||
// Receiver didn't set up a decoupled encryption key
|
||||
if announcement.is_none() {
|
||||
reports.push(SendReport::new(public_key).error(NO_DEKEY));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sender didn't set up a decoupled encryption key
|
||||
if encryption_signer.is_none() {
|
||||
reports.push(SendReport::new(sender.public_key()).error(USER_NO_DEKEY));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine receiver and signer
|
||||
let (receiver, signer) = match signer_kind {
|
||||
// Determine the signer to use
|
||||
let signer = match signer_kind {
|
||||
SignerKind::Auto => {
|
||||
if let Some(announcement) = announcement {
|
||||
if let Some(enc_signer) = encryption_signer.as_ref() {
|
||||
(announcement.public_key(), enc_signer.clone())
|
||||
} else {
|
||||
(member.public_key(), user_signer.clone())
|
||||
}
|
||||
if announcement.is_some()
|
||||
&& let Some(encryption_signer) = encryption_signer.clone()
|
||||
{
|
||||
// Safe to unwrap due to earlier checks
|
||||
encryption_signer
|
||||
} else {
|
||||
(member.public_key(), user_signer.clone())
|
||||
user_signer.clone()
|
||||
}
|
||||
}
|
||||
SignerKind::Encryption => {
|
||||
// Safe to unwrap due to earlier checks
|
||||
(
|
||||
announcement.unwrap().public_key(),
|
||||
encryption_signer.as_ref().unwrap().clone(),
|
||||
)
|
||||
encryption_signer.as_ref().unwrap().clone()
|
||||
}
|
||||
SignerKind::User => (member.public_key(), user_signer.clone()),
|
||||
SignerKind::User => user_signer.clone(),
|
||||
};
|
||||
|
||||
match send_gift_wrap(&client, &signer, &receiver, &rumor, public_key).await {
|
||||
Ok((report, _)) => {
|
||||
// Send the gift wrap event and collect the report
|
||||
match send_gift_wrap(&client, &signer, &member, &rumor, signer_kind).await {
|
||||
Ok(report) => {
|
||||
reports.push(report);
|
||||
sents += 1;
|
||||
}
|
||||
Err(report) => {
|
||||
Err(error) => {
|
||||
let report = SendReport::new(public_key).error(error.to_string());
|
||||
reports.push(report);
|
||||
}
|
||||
}
|
||||
@@ -562,11 +553,32 @@ impl Room {
|
||||
// Send backup to current user if needed
|
||||
if backup && sents >= 1 {
|
||||
let public_key = sender.public_key();
|
||||
let signer = encryption_signer.as_ref().unwrap_or(&user_signer);
|
||||
|
||||
match send_gift_wrap(&client, signer, &public_key, &rumor, public_key).await {
|
||||
Ok((report, _)) => reports.push(report),
|
||||
Err(report) => reports.push(report),
|
||||
// Determine the signer to use
|
||||
let signer = match signer_kind {
|
||||
SignerKind::Auto => {
|
||||
if sender.announcement().is_some()
|
||||
&& let Some(encryption_signer) = encryption_signer.clone()
|
||||
{
|
||||
// Safe to unwrap due to earlier checks
|
||||
encryption_signer
|
||||
} else {
|
||||
user_signer.clone()
|
||||
}
|
||||
}
|
||||
SignerKind::Encryption => {
|
||||
// Safe to unwrap due to earlier checks
|
||||
encryption_signer.as_ref().unwrap().clone()
|
||||
}
|
||||
SignerKind::User => user_signer.clone(),
|
||||
};
|
||||
|
||||
match send_gift_wrap(&client, &signer, &sender, &rumor, signer_kind).await {
|
||||
Ok(report) => reports.push(report),
|
||||
Err(error) => {
|
||||
let report = SendReport::new(public_key).error(error.to_string());
|
||||
reports.push(report);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,30 +591,50 @@ impl Room {
|
||||
async fn send_gift_wrap<T>(
|
||||
client: &Client,
|
||||
signer: &T,
|
||||
receiver: &PublicKey,
|
||||
receiver: &Person,
|
||||
rumor: &UnsignedEvent,
|
||||
public_key: PublicKey,
|
||||
) -> Result<(SendReport, bool), SendReport>
|
||||
config: &SignerKind,
|
||||
) -> Result<SendReport, Error>
|
||||
where
|
||||
T: NostrSigner + 'static,
|
||||
{
|
||||
match EventBuilder::gift_wrap(signer, receiver, rumor.clone(), []).await {
|
||||
Ok(event) => {
|
||||
match client
|
||||
.send_event(&event)
|
||||
.to_nip17()
|
||||
.ack_policy(AckPolicy::none())
|
||||
.await
|
||||
{
|
||||
Ok(output) => Ok((
|
||||
SendReport::new(public_key)
|
||||
.gift_wrap_id(event.id)
|
||||
.output(output),
|
||||
true,
|
||||
)),
|
||||
Err(e) => Err(SendReport::new(public_key).error(e.to_string())),
|
||||
let mut extra_tags = vec![];
|
||||
|
||||
// Determine the receiver public key based on the config
|
||||
let receiver = match config {
|
||||
SignerKind::Auto => {
|
||||
if let Some(announcement) = receiver.announcement().as_ref() {
|
||||
extra_tags.push(Tag::public_key(receiver.public_key()));
|
||||
announcement.public_key()
|
||||
} else {
|
||||
receiver.public_key()
|
||||
}
|
||||
}
|
||||
Err(e) => Err(SendReport::new(public_key).error(e.to_string())),
|
||||
}
|
||||
SignerKind::Encryption => {
|
||||
if let Some(announcement) = receiver.announcement().as_ref() {
|
||||
extra_tags.push(Tag::public_key(receiver.public_key()));
|
||||
announcement.public_key()
|
||||
} else {
|
||||
return Err(anyhow!("User has no encryption announcement"));
|
||||
}
|
||||
}
|
||||
SignerKind::User => receiver.public_key(),
|
||||
};
|
||||
|
||||
// Construct the gift wrap event
|
||||
let event = EventBuilder::gift_wrap(signer, &receiver, rumor.clone(), extra_tags).await?;
|
||||
|
||||
// Send the gift wrap event and collect the report
|
||||
let report = client
|
||||
.send_event(&event)
|
||||
.to_nip17()
|
||||
.ack_policy(AckPolicy::none())
|
||||
.await
|
||||
.map(|output| {
|
||||
SendReport::new(receiver)
|
||||
.gift_wrap_id(event.id)
|
||||
.output(output)
|
||||
})?;
|
||||
|
||||
Ok(report)
|
||||
}
|
||||
|
||||
@@ -379,9 +379,13 @@ impl ChatPanel {
|
||||
/// Send message in the background and wait for the response
|
||||
fn send_and_wait(&mut self, rumor: UnsignedEvent, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let sent_ids = self.sent_ids.clone();
|
||||
|
||||
// This can't fail, because we already ensured that the ID is set
|
||||
let id = rumor.id.unwrap();
|
||||
|
||||
// Add empty reports
|
||||
self.insert_reports(id, vec![], cx);
|
||||
|
||||
// Upgrade room reference
|
||||
let Some(room) = self.room.upgrade() else {
|
||||
return;
|
||||
@@ -430,7 +434,7 @@ impl ChatPanel {
|
||||
/// Insert reports
|
||||
fn insert_reports(&mut self, id: EventId, reports: Vec<SendReport>, cx: &mut Context<Self>) {
|
||||
self.reports_by_id.update(cx, |this, cx| {
|
||||
this.insert(id, reports);
|
||||
this.entry(id).or_default().extend(reports);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
@@ -465,14 +469,6 @@ impl ChatPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a message is pending
|
||||
fn sent_pending(&self, id: &EventId, cx: &App) -> bool {
|
||||
self.reports_by_id
|
||||
.read(cx)
|
||||
.get(id)
|
||||
.is_some_and(|reports| reports.iter().all(|r| r.pending()))
|
||||
}
|
||||
|
||||
/// Check if a message has any reports
|
||||
fn has_reports(&self, id: &EventId, cx: &App) -> bool {
|
||||
self.reports_by_id.read(cx).get(id).is_some()
|
||||
@@ -802,8 +798,6 @@ impl ChatPanel {
|
||||
|
||||
let replies = message.replies_to.as_slice();
|
||||
let has_replies = !replies.is_empty();
|
||||
|
||||
let sent_pending = self.sent_pending(&id, cx);
|
||||
let has_reports = self.has_reports(&id, cx);
|
||||
|
||||
// Hide avatar setting
|
||||
@@ -851,9 +845,6 @@ impl ChatPanel {
|
||||
.child(author.name()),
|
||||
)
|
||||
.child(message.created_at.to_human_time())
|
||||
.when(sent_pending, |this| {
|
||||
this.child(SharedString::from("• Sending..."))
|
||||
})
|
||||
.when(has_reports, |this| {
|
||||
this.child(deferred(self.render_sent_reports(&id, cx)))
|
||||
}),
|
||||
@@ -937,20 +928,26 @@ impl ChatPanel {
|
||||
fn render_sent_reports(&self, id: &EventId, cx: &App) -> impl IntoElement {
|
||||
let reports = self.sent_reports(id, cx);
|
||||
|
||||
let pending = reports
|
||||
.as_ref()
|
||||
.is_some_and(|reports| reports.is_empty() || reports.iter().any(|r| r.pending()));
|
||||
|
||||
let success = reports
|
||||
.as_ref()
|
||||
.is_some_and(|reports| reports.iter().any(|r| r.success()));
|
||||
.is_some_and(|reports| !reports.is_empty() && reports.iter().any(|r| r.success()));
|
||||
|
||||
let failed = reports
|
||||
.as_ref()
|
||||
.is_some_and(|reports| reports.iter().all(|r| r.failed()));
|
||||
.is_some_and(|reports| !reports.is_empty() && reports.iter().all(|r| r.failed()));
|
||||
|
||||
let label = if success {
|
||||
SharedString::from("• Sent")
|
||||
} else if failed {
|
||||
SharedString::from("• Failed")
|
||||
} else {
|
||||
SharedString::from("• Error")
|
||||
} else if pending {
|
||||
SharedString::from("• Sending...")
|
||||
} else {
|
||||
SharedString::from("• Unknown")
|
||||
};
|
||||
|
||||
div()
|
||||
@@ -958,22 +955,24 @@ impl ChatPanel {
|
||||
.child(label)
|
||||
.when(failed, |this| this.text_color(cx.theme().text_danger))
|
||||
.when_some(reports, |this, reports| {
|
||||
this.on_click(move |_e, window, cx| {
|
||||
let reports = reports.clone();
|
||||
this.when(!pending, |this| {
|
||||
this.on_click(move |_e, window, cx| {
|
||||
let reports = reports.clone();
|
||||
|
||||
window.open_modal(cx, move |this, _window, cx| {
|
||||
this.title(SharedString::from("Sent Reports"))
|
||||
.show_close(true)
|
||||
.child(v_flex().gap_4().children({
|
||||
let mut items = Vec::with_capacity(reports.len());
|
||||
window.open_modal(cx, move |this, _window, cx| {
|
||||
this.title(SharedString::from("Sent Reports"))
|
||||
.show_close(true)
|
||||
.child(v_flex().gap_4().children({
|
||||
let mut items = Vec::with_capacity(reports.len());
|
||||
|
||||
for report in reports.iter() {
|
||||
items.push(Self::render_report(report, cx))
|
||||
}
|
||||
for report in reports.iter() {
|
||||
items.push(Self::render_report(report, cx))
|
||||
}
|
||||
|
||||
items
|
||||
}))
|
||||
});
|
||||
items
|
||||
}))
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use theme::ActiveTheme;
|
||||
use ui::avatar::Avatar;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::notification::Notification;
|
||||
use ui::{Disableable, IconName, Sizable, WindowExtension, h_flex, v_flex};
|
||||
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
|
||||
const IDENTIFIER: &str = "coop:device";
|
||||
const MSG: &str = "You've requested an encryption key from another device. \
|
||||
@@ -85,6 +85,9 @@ pub struct DeviceRegistry {
|
||||
/// Whether the registry is waiting for encryption key approval from other devices
|
||||
pub requesting: bool,
|
||||
|
||||
/// Whether there is a pending request for encryption key approval
|
||||
pub has_pending_request: bool,
|
||||
|
||||
/// Async tasks
|
||||
tasks: Vec<Task<Result<(), Error>>>,
|
||||
|
||||
@@ -130,6 +133,7 @@ impl DeviceRegistry {
|
||||
Self {
|
||||
subscribing: false,
|
||||
requesting: false,
|
||||
has_pending_request: false,
|
||||
tasks: vec![],
|
||||
_subscription: Some(subscription),
|
||||
}
|
||||
@@ -208,6 +212,12 @@ impl DeviceRegistry {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Set whether there is a pending request for encryption key approval
|
||||
fn set_has_pending_request(&mut self, pending: bool, cx: &mut Context<Self>) {
|
||||
self.has_pending_request = pending;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Set the decoupled encryption key for the current user
|
||||
fn set_signer<S>(&mut self, new: S, cx: &mut Context<Self>)
|
||||
where
|
||||
@@ -611,7 +621,6 @@ impl DeviceRegistry {
|
||||
fn approve(&mut self, event: &Event, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let client = nostr.read(cx).client();
|
||||
let signer = nostr.read(cx).signer();
|
||||
|
||||
// Get user's write relays
|
||||
let event = event.clone();
|
||||
@@ -631,14 +640,14 @@ impl DeviceRegistry {
|
||||
.context("Target is not a valid public key")?;
|
||||
|
||||
// Encrypt the device keys with the user's signer
|
||||
let payload = signer.nip44_encrypt(&target, &secret).await?;
|
||||
let payload = keys.nip44_encrypt(&target, &secret).await?;
|
||||
|
||||
// Construct the response event
|
||||
//
|
||||
// P tag: the current device's public key
|
||||
// p tag: the requester's public key
|
||||
let builder = EventBuilder::new(Kind::Custom(4455), payload).tags(vec![
|
||||
Tag::custom(TagKind::custom("P"), vec![keys.public_key()]),
|
||||
Tag::custom(TagKind::custom("P"), vec![keys.public_key().to_hex()]),
|
||||
Tag::public_key(target),
|
||||
]);
|
||||
|
||||
@@ -675,15 +684,15 @@ impl DeviceRegistry {
|
||||
|
||||
/// Handle encryption request
|
||||
fn ask_for_approval(&mut self, event: Event, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let notification = self.notification(event, cx);
|
||||
// Ignore if there is already a pending request
|
||||
if self.has_pending_request {
|
||||
return;
|
||||
}
|
||||
self.set_has_pending_request(true, cx);
|
||||
|
||||
cx.spawn_in(window, async move |_this, cx| {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(notification, cx);
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
// Show notification
|
||||
let notification = self.notification(event, cx);
|
||||
window.push_notification(notification, cx);
|
||||
}
|
||||
|
||||
/// Build a notification for the encryption request.
|
||||
@@ -720,13 +729,14 @@ impl DeviceRegistry {
|
||||
.text_sm()
|
||||
.child(
|
||||
div()
|
||||
.font_semibold()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("Requester:")),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.h_7()
|
||||
.h_8()
|
||||
.w_full()
|
||||
.px_2()
|
||||
.rounded(cx.theme().radius)
|
||||
@@ -745,13 +755,14 @@ impl DeviceRegistry {
|
||||
.text_sm()
|
||||
.child(
|
||||
div()
|
||||
.font_semibold()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("Client:")),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.h_7()
|
||||
.h_8()
|
||||
.w_full()
|
||||
.px_2()
|
||||
.rounded(cx.theme().radius)
|
||||
|
||||
@@ -11,7 +11,7 @@ nostr.workspace = true
|
||||
nostr-sdk.workspace = true
|
||||
nostr-lmdb.workspace = true
|
||||
nostr-memory.workspace = true
|
||||
nostr-gossip-sqlite.workspace = true
|
||||
nostr-gossip-memory.workspace = true
|
||||
nostr-connect.workspace = true
|
||||
nostr-blossom.workspace = true
|
||||
|
||||
|
||||
@@ -36,14 +36,16 @@ pub const NOSTR_CONNECT_RELAY: &str = "wss://relay.nip46.com";
|
||||
/// Default vertex relays
|
||||
pub const WOT_RELAYS: [&str; 1] = ["wss://relay.vertexlab.io"];
|
||||
|
||||
/// Default search relays
|
||||
pub const INDEXER_RELAYS: [&str; 1] = ["wss://indexer.coracle.social"];
|
||||
|
||||
/// Default search relays
|
||||
pub const SEARCH_RELAYS: [&str; 2] = ["wss://antiprimal.net", "wss://search.nos.today"];
|
||||
|
||||
/// Default bootstrap relays
|
||||
pub const BOOTSTRAP_RELAYS: [&str; 4] = [
|
||||
pub const BOOTSTRAP_RELAYS: [&str; 3] = [
|
||||
"wss://relay.damus.io",
|
||||
"wss://relay.primal.net",
|
||||
"wss://indexer.coracle.social",
|
||||
"wss://user.kindpag.es",
|
||||
];
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use anyhow::{Context as AnyhowContext, Error, anyhow};
|
||||
use common::config_dir;
|
||||
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Task, Window};
|
||||
use nostr_connect::prelude::*;
|
||||
use nostr_gossip_sqlite::prelude::*;
|
||||
use nostr_gossip_memory::prelude::*;
|
||||
use nostr_lmdb::prelude::*;
|
||||
use nostr_memory::prelude::*;
|
||||
use nostr_sdk::prelude::*;
|
||||
@@ -114,17 +114,16 @@ impl NostrRegistry {
|
||||
// Construct the nostr npubs entity
|
||||
let npubs = cx.new(|_| vec![]);
|
||||
|
||||
// Construct the nostr gossip instance
|
||||
let gossip = cx.foreground_executor().block_on(async move {
|
||||
NostrGossipSqlite::open(config_dir().join("gossip"))
|
||||
.await
|
||||
.expect("Failed to initialize gossip instance")
|
||||
});
|
||||
|
||||
// Construct the nostr client builder
|
||||
let mut builder = ClientBuilder::default()
|
||||
.signer(signer.clone())
|
||||
.gossip(gossip)
|
||||
.gossip(NostrGossipMemory::unbounded())
|
||||
.gossip_config(
|
||||
GossipConfig::default()
|
||||
.no_background_refresh()
|
||||
.sync_idle_timeout(Duration::from_secs(TIMEOUT))
|
||||
.sync_initial_timeout(Duration::from_millis(600)),
|
||||
)
|
||||
.automatic_authentication(false)
|
||||
.verify_subscriptions(false)
|
||||
.connect_timeout(Duration::from_secs(10))
|
||||
@@ -189,7 +188,18 @@ impl NostrRegistry {
|
||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||
// Add search relay to the relay pool
|
||||
for url in SEARCH_RELAYS.into_iter() {
|
||||
client.add_relay(url).await?;
|
||||
client
|
||||
.add_relay(url)
|
||||
.capabilities(RelayCapabilities::READ)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Add indexer relay to the relay pool
|
||||
for url in INDEXER_RELAYS.into_iter() {
|
||||
client
|
||||
.add_relay(url)
|
||||
.capabilities(RelayCapabilities::DISCOVERY)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Add bootstrap relay to the relay pool
|
||||
@@ -198,7 +208,10 @@ impl NostrRegistry {
|
||||
}
|
||||
|
||||
// Connect to all added relays
|
||||
client.connect().await;
|
||||
client
|
||||
.connect()
|
||||
.and_wait(Duration::from_secs(TIMEOUT))
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user