use negentropy sync
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Error, anyhow};
|
||||
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Task};
|
||||
use nostr_connect::prelude::*;
|
||||
use nostr_sdk::client::SyncSummary;
|
||||
use nostr_sdk::prelude::*;
|
||||
use signed_core::filters;
|
||||
use signed_nostr::{NostrBackend, SignedAuthUrlHandler, UniversalSigner, Update};
|
||||
@@ -39,6 +41,10 @@ pub enum BackendEvent {
|
||||
Connected,
|
||||
/// A new event was received from a relay and stored in the database.
|
||||
NostrUpdate(Update),
|
||||
/// A negentropy sync completed; the database was updated directly,
|
||||
/// so stores should re-query (no [`BackendEvent::NostrUpdate`] is fired
|
||||
/// for synced events).
|
||||
Synced,
|
||||
/// An event built locally was signed, broadcast and stored.
|
||||
Published(Box<Event>),
|
||||
/// An error occurred.
|
||||
@@ -479,6 +485,56 @@ impl Backend {
|
||||
}));
|
||||
}
|
||||
|
||||
/// Start a one-shot subscription targeted only at the bootstrap relays,
|
||||
/// auto-closing after EOSE or a short timeout. Matching events are stored
|
||||
/// in the database and surface as [`BackendEvent::NostrUpdate`] while the
|
||||
/// subscription is open.
|
||||
pub fn subscribe_bootstrap(&mut self, filters: Vec<Filter>, cx: &mut Context<Self>) {
|
||||
let backend = self.inner.clone();
|
||||
|
||||
let task = cx.background_spawn(async move {
|
||||
subscribe_bootstrap_only(&backend.client(), filters).await
|
||||
});
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
if let Err(e) = task.await {
|
||||
this.update(cx, |_this, cx| cx.emit(BackendEvent::error(e.to_string())))?;
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Negentropy-sync the given filter against the bootstrap relays:
|
||||
/// reconciles the local database with the relays in both directions.
|
||||
/// Emits [`BackendEvent::Synced`] on completion.
|
||||
pub fn sync_bootstrap(&mut self, filter: Filter, cx: &mut Context<Self>) {
|
||||
let backend = self.inner.clone();
|
||||
|
||||
let task = cx.background_spawn(async move {
|
||||
sync_bootstrap_only(&backend.client(), filter).await
|
||||
});
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
match task.await {
|
||||
Ok(summary) => {
|
||||
log::debug!(
|
||||
"sync done: {} received, {} sent",
|
||||
summary.received.len(),
|
||||
summary.sent.len()
|
||||
);
|
||||
this.update(cx, |_this, cx| {
|
||||
cx.emit(BackendEvent::Synced);
|
||||
cx.notify();
|
||||
})?;
|
||||
}
|
||||
Err(e) => {
|
||||
this.update(cx, |_this, cx| cx.emit(BackendEvent::error(e.to_string())))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Sign, broadcast and locally store an event. Emits
|
||||
/// [`BackendEvent::Published`] on success so stores can refresh.
|
||||
///
|
||||
@@ -517,3 +573,30 @@ impl Backend {
|
||||
rx
|
||||
}
|
||||
}
|
||||
|
||||
/// Subscribe only on the bootstrap relays, auto-closing after EOSE or a
|
||||
/// short timeout. Use for one-shot data fetches (repo events, profiles)
|
||||
/// instead of persistent gossip-routed subscriptions.
|
||||
pub(crate) async fn subscribe_bootstrap_only(client: &Client, filters: Vec<Filter>) -> Result<(), Error> {
|
||||
let opts = SubscribeAutoCloseOptions::default()
|
||||
.exit_policy(ReqExitPolicy::ExitOnEOSE)
|
||||
.timeout(Some(Duration::from_secs(10)));
|
||||
|
||||
let target: HashMap<&str, Vec<Filter>> = BOOTSTRAP_RELAYS
|
||||
.iter()
|
||||
.map(|relay| (*relay, filters.clone()))
|
||||
.collect();
|
||||
|
||||
client.subscribe(target).close_on(opts).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Negentropy-sync the filter against the bootstrap relays only.
|
||||
pub(crate) async fn sync_bootstrap_only(
|
||||
client: &Client,
|
||||
filter: Filter,
|
||||
) -> Result<SyncSummary, Error> {
|
||||
let output = client.sync(filter).with(BOOTSTRAP_RELAYS).await?;
|
||||
Ok(output.value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user