This commit is contained in:
2026-01-03 20:39:18 +07:00
parent bb455871e5
commit 067f88dfa6
26 changed files with 1212 additions and 2117 deletions

View File

@@ -1,6 +1,6 @@
use std::borrow::Cow;
use std::cell::Cell;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
@@ -12,7 +12,7 @@ use gpui::{
use nostr_sdk::prelude::*;
use settings::AppSettings;
use smallvec::{smallvec, SmallVec};
use state::NostrRegistry;
use state::{tracker, NostrRegistry};
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::notification::Notification;
@@ -25,10 +25,7 @@ pub fn init(window: &mut Window, cx: &mut App) {
RelayAuth::set_global(cx.new(|cx| RelayAuth::new(window, cx)), cx);
}
struct GlobalRelayAuth(Entity<RelayAuth>);
impl Global for GlobalRelayAuth {}
/// Authentication request
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct AuthRequest {
pub url: RelayUrl,
@@ -50,6 +47,11 @@ impl AuthRequest {
}
}
struct GlobalRelayAuth(Entity<RelayAuth>);
impl Global for GlobalRelayAuth {}
// Relay authentication
#[derive(Debug)]
pub struct RelayAuth {
/// Entity for managing auth requests
@@ -77,8 +79,13 @@ impl RelayAuth {
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
// Get the current entity
let entity = cx.entity();
// Channel for communication between nostr and gpui
let (tx, rx) = flume::bounded::<AuthRequest>(100);
let mut subscriptions = smallvec![];
let mut tasks = smallvec![];
@@ -103,26 +110,20 @@ impl RelayAuth {
);
tasks.push(
// Handle notifications
// Handle nostr notifications
cx.background_spawn(async move {
Self::handle_notifications(&client, &tx).await;
}),
);
tasks.push(
// Update GPUI states
cx.spawn(async move |this, cx| {
let mut notifications = client.notifications();
let mut challenges: HashSet<Cow<'_, str>> = HashSet::new();
while let Ok(notification) = notifications.recv().await {
let RelayPoolNotification::Message { message, relay_url } = notification else {
// Skip if the notification is not a message
continue;
};
if let RelayMessage::Auth { challenge } = message {
if challenges.insert(challenge.clone()) {
this.update(cx, |this, cx| {
this.requests.insert(AuthRequest::new(challenge, relay_url));
cx.notify();
})
.expect("Entity has been released");
};
}
while let Ok(request) = rx.recv_async().await {
this.update(cx, |this, cx| {
this.add_request(request, cx);
})
.ok();
}
}),
);
@@ -134,6 +135,31 @@ impl RelayAuth {
}
}
// Handle nostr notifications
async fn handle_notifications(client: &Client, tx: &flume::Sender<AuthRequest>) {
let mut notifications = client.notifications();
let mut processed_challenges = HashSet::new();
while let Ok(notification) = notifications.recv().await {
if let RelayPoolNotification::Message {
message: RelayMessage::Auth { challenge },
relay_url,
} = notification
{
if processed_challenges.insert(challenge.clone()) {
let request = AuthRequest::new(challenge, relay_url);
tx.send_async(request).await.ok();
};
}
}
}
/// Add a new authentication request.
fn add_request(&mut self, request: AuthRequest, cx: &mut Context<Self>) {
self.requests.insert(request);
cx.notify();
}
/// Get the number of pending requests.
pub fn pending_requests(&self, _cx: &App) -> usize {
self.requests.len()
@@ -152,7 +178,6 @@ impl RelayAuth {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let tracker = nostr.read(cx).tracker();
let challenge = req.challenge.to_owned();
let url = req.url.to_owned();
@@ -190,30 +215,14 @@ impl RelayAuth {
// Re-subscribe to previous subscription
relay.resubscribe().await?;
// Get all failed events that need to be resent
let mut tracker = tracker.write().await;
let ids: Vec<EventId> = tracker
.resend_queue
.iter()
.filter(|(_, url)| relay_url == *url)
.map(|(id, _)| *id)
.collect();
// Get all pending events that need to be resent
let mut tracker = tracker().write().await;
let ids: Vec<EventId> = tracker.pending_resend(relay_url);
for id in ids.into_iter() {
if let Some(relay_url) = tracker.resend_queue.remove(&id) {
if let Some(event) = client.database().event_by_id(&id).await? {
let event_id = relay.send_event(&event).await?;
let output = Output {
val: event_id,
failed: HashMap::new(),
success: HashSet::from([relay_url]),
};
tracker.sent_ids.insert(event_id);
tracker.resent_ids.push(output);
}
if let Some(event) = client.database().event_by_id(&id).await? {
let event_id = relay.send_event(&event).await?;
tracker.sent(event_id);
}
}