feat: custom gossip implementation (#181)

* .

* rename global to app_state

* refactor event tracker

* gossip

* .

* .
This commit is contained in:
reya
2025-10-10 17:36:38 +07:00
committed by GitHub
parent b7693444e6
commit 68a8ec7a69
34 changed files with 1020 additions and 913 deletions

View File

@@ -6,7 +6,7 @@ publish.workspace = true
[dependencies]
common = { path = "../common" }
global = { path = "../global" }
app_state = { path = "../app_state" }
settings = { path = "../settings" }
gpui.workspace = true

View File

@@ -2,10 +2,11 @@ use std::cmp::Reverse;
use std::collections::{HashMap, HashSet};
use anyhow::Error;
use app_state::nostr_client;
use app_state::state::UnwrappingStatus;
use common::event::EventUtils;
use fuzzy_matcher::skim::SkimMatcherV2;
use fuzzy_matcher::FuzzyMatcher;
use global::{nostr_client, UnwrappingStatus};
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Task, WeakEntity, Window};
use itertools::Itertools;
use nostr_sdk::prelude::*;

View File

@@ -4,12 +4,11 @@ use std::hash::{Hash, Hasher};
use std::time::Duration;
use anyhow::{anyhow, Error};
use app_state::constants::SEND_RETRY;
use app_state::{app_state, nostr_client};
use common::display::RenderedProfile;
use common::event::EventUtils;
use global::constants::SEND_RETRY;
use global::{app_state, nostr_client};
use gpui::{App, AppContext, Context, EventEmitter, SharedString, SharedUri, Task};
use itertools::Itertools;
use nostr_sdk::prelude::*;
use crate::Registry;
@@ -358,18 +357,6 @@ impl Room {
})
}
pub fn disconnect(&self, relays: Vec<RelayUrl>, cx: &App) -> Task<Result<(), Error>> {
cx.background_spawn(async move {
let client = nostr_client();
for relay in relays.into_iter() {
client.disconnect_relay(relay).await?;
}
Ok(())
})
}
/// Loads all messages for this room from the database
pub fn load_messages(&self, cx: &App) -> Task<Result<Vec<Event>, Error>> {
let members = self.members.clone();
@@ -378,13 +365,14 @@ impl Room {
let client = nostr_client();
let signer = client.signer().await?;
let public_key = signer.get_public_key().await?;
let sent_ids = app_state()
.sent_ids
let sent_ids: Vec<EventId> = app_state()
.event_tracker
.read()
.await
.sent_ids()
.iter()
.copied()
.collect_vec();
.collect();
// Get seen events from database
let filter = Filter::new()
@@ -508,12 +496,17 @@ impl Room {
let rumor = rumor.clone();
let event = EventBuilder::gift_wrap(&signer, &receiver, rumor, vec![]).await?;
let Ok(relay_urls) = Self::messaging_relays(receiver).await else {
let gossip = app_state.gossip.read().await;
let urls = gossip.messaging_relays(&receiver);
// Check if there are any relays to send the event to
if urls.is_empty() {
reports.push(SendReport::new(receiver).not_found());
continue;
};
}
match client.send_event_to(relay_urls, &event).await {
// Send the event to the relays
match client.send_event_to(urls, &event).await {
Ok(output) => {
let id = output.id().to_owned();
let auth_required = output.failed.iter().any(|m| m.1.starts_with("auth-"));
@@ -522,7 +515,8 @@ impl Room {
if auth_required {
// Wait for authenticated and resent event successfully
for attempt in 0..=SEND_RETRY {
let ids = app_state.resent_ids.read().await;
let retry_manager = app_state.event_tracker.read().await;
let ids = retry_manager.resent_ids();
// Check if event was successfully resent
if let Some(output) = ids.iter().find(|e| e.id() == &id).cloned() {
@@ -555,8 +549,15 @@ impl Room {
// Only send a backup message to current user if sent successfully to others
if reports.iter().all(|r| r.is_sent_success()) && backup {
if let Ok(relay_urls) = Self::messaging_relays(public_key).await {
match client.send_event_to(relay_urls, &event).await {
let gossip = app_state.gossip.read().await;
let urls = gossip.messaging_relays(&public_key);
// Check if there are any relays to send the event to
if urls.is_empty() {
reports.push(SendReport::new(public_key).not_found());
} else {
// Send the event to the relays
match client.send_event_to(urls, &event).await {
Ok(output) => {
reports.push(SendReport::new(public_key).status(output));
}
@@ -564,8 +565,6 @@ impl Room {
reports.push(SendReport::new(public_key).error(e.to_string()));
}
}
} else {
reports.push(SendReport::new(public_key).not_found());
}
} else {
reports.push(SendReport::new(public_key).on_hold(event));
@@ -583,6 +582,8 @@ impl Room {
) -> Task<Result<Vec<SendReport>, Error>> {
cx.background_spawn(async move {
let client = nostr_client();
let app_state = app_state();
let mut resend_reports = vec![];
for report in reports.into_iter() {
@@ -611,8 +612,15 @@ impl Room {
// Process the on hold event if it exists
if let Some(event) = report.on_hold {
if let Ok(relay_urls) = Self::messaging_relays(receiver).await {
match client.send_event_to(relay_urls, &event).await {
let gossip = app_state.gossip.read().await;
let urls = gossip.messaging_relays(&receiver);
// Check if there are any relays to send the event to
if urls.is_empty() {
resend_reports.push(SendReport::new(receiver).not_found());
} else {
// Send the event to the relays
match client.send_event_to(urls, &event).await {
Ok(output) => {
resend_reports.push(SendReport::new(receiver).status(output));
}
@@ -620,8 +628,6 @@ impl Room {
resend_reports.push(SendReport::new(receiver).error(e.to_string()));
}
}
} else {
resend_reports.push(SendReport::new(receiver).not_found());
}
}
}
@@ -629,36 +635,4 @@ impl Room {
Ok(resend_reports)
})
}
/// Gets messaging relays for public key
async fn messaging_relays(public_key: PublicKey) -> Result<Vec<RelayUrl>, Error> {
let client = nostr_client();
let mut relay_urls = vec![];
let filter = Filter::new()
.kind(Kind::InboxRelays)
.author(public_key)
.limit(1);
if let Some(event) = client.database().query(filter).await?.first_owned() {
let urls: Vec<RelayUrl> = nip17::extract_owned_relay_list(event).collect();
// Check if at least one URL exists
if urls.is_empty() {
return Err(anyhow!("Not found"));
}
// Connect to relays
for url in urls.iter() {
client.add_relay(url).await?;
client.connect_relay(url).await?;
}
relay_urls.extend(urls.into_iter().take(3).unique());
} else {
return Err(anyhow!("Not found"));
}
Ok(relay_urls)
}
}