chore: follow up on nip-4e (#195)

* update deps

* .

* remove resend button

* clean up

* .

* .

* .

* .

* .
This commit is contained in:
reya
2025-10-28 14:37:30 +07:00
committed by GitHub
parent b5ed079a0e
commit b9297d3a01
21 changed files with 199 additions and 176 deletions

View File

@@ -245,7 +245,7 @@ impl Registry {
pub fn search_by_public_key(&self, public_key: PublicKey, cx: &App) -> Vec<Entity<Room>> {
self.rooms
.iter()
.filter(|room| room.read(cx).members.contains_key(&public_key))
.filter(|room| room.read(cx).members.contains(&public_key))
.cloned()
.collect()
}

View File

@@ -8,20 +8,10 @@ use common::display::RenderedProfile;
use common::event::EventUtils;
use gpui::{App, AppContext, Context, EventEmitter, SharedString, SharedUri, Task};
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use states::app_state;
use states::constants::SEND_RETRY;
use states::{app_state, SignerKind, SEND_RETRY};
use crate::Registry;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Deserialize, Serialize)]
pub enum SignerKind {
Encryption,
User,
#[default]
Auto,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SendOptions {
pub backup: bool,
@@ -127,8 +117,6 @@ pub enum RoomKind {
Request,
}
type DevicePublicKey = PublicKey;
#[derive(Debug)]
pub struct Room {
pub id: u64,
@@ -136,7 +124,7 @@ pub struct Room {
/// Subject of the room
pub subject: Option<String>,
/// All members of the room
pub members: HashMap<PublicKey, Option<DevicePublicKey>>,
pub members: Vec<PublicKey>,
/// Kind
pub kind: RoomKind,
}
@@ -175,11 +163,7 @@ impl From<&Event> for Room {
let created_at = val.created_at;
// Get the members from the event's tags and event's pubkey
let members: HashMap<PublicKey, Option<DevicePublicKey>> = val
.all_pubkeys()
.into_iter()
.map(|public_key| (public_key, None))
.collect();
let members = val.all_pubkeys();
// Get subject from tags
let subject = val
@@ -203,11 +187,7 @@ impl From<&UnsignedEvent> for Room {
let created_at = val.created_at;
// Get the members from the event's tags and event's pubkey
let members: HashMap<PublicKey, Option<DevicePublicKey>> = val
.all_pubkeys()
.into_iter()
.map(|public_key| (public_key, None))
.collect();
let members = val.all_pubkeys();
// Get subject from tags
let subject = val
@@ -289,7 +269,7 @@ impl Room {
/// Returns the members of the room
pub fn members(&self) -> Vec<PublicKey> {
self.members.keys().cloned().collect()
self.members.clone()
}
/// Checks if the room has more than two members (group)
@@ -324,9 +304,9 @@ impl Room {
let target_member = self
.members
.keys()
.iter()
.find(|&member| Some(member) != signer_pubkey.as_ref())
.or_else(|| self.members.keys().next())
.or_else(|| self.members.first())
.expect("Room should have at least one member");
registry.read(cx).get_person(target_member, cx)
@@ -339,7 +319,7 @@ impl Room {
if self.is_group() {
let profiles: Vec<Profile> = self
.members
.keys()
.iter()
.map(|public_key| registry.get_person(public_key, cx))
.collect();
@@ -447,7 +427,7 @@ impl Room {
// Add receivers
//
// NOTE: current user will be removed from the list of receivers
for (member, _) in self.members.iter() {
for member in self.members.iter() {
// Get relay hint if available
let relay_url = relay_cache
.get(member)
@@ -505,54 +485,75 @@ impl Room {
opts: &SendOptions,
cx: &App,
) -> Task<Result<Vec<SendReport>, Error>> {
let mut members = self.members.clone();
let rumor = rumor.to_owned();
let opts = opts.to_owned();
// Get all members
let mut members = self.members();
cx.background_spawn(async move {
let state = app_state();
let client = state.client();
let signer_kind = opts.signer_kind;
let relay_cache = state.relay_cache.read().await;
let device = state.device.read().await.encryption.clone();
let announcement_cache = state.announcement_cache.read().await;
let encryption = state.device.read().await.encryption.clone();
// Get the encryption public key
let encryption_pubkey = if let Some(signer) = encryption.as_ref() {
signer.get_public_key().await.ok()
} else {
None
};
let user_signer = client.signer().await?;
let user_pubkey = user_signer.get_public_key().await?;
// Remove the current user's public key from the list of receivers
// Current user will be handled separately
let (public_key, device_pubkey) = members.remove_entry(&user_pubkey).unwrap();
// the current user will be handled separately
members.retain(|&pk| pk != user_pubkey);
// Determine the signer will be used based on the provided options
let (signer, signer_kind) =
Self::select_signer(&opts.signer_kind, device, user_signer)?;
let signer = Self::select_signer(&opts.signer_kind, user_signer, encryption)?;
// Collect the send reports
let mut reports: Vec<SendReport> = vec![];
for (user, device_pubkey) in members.into_iter() {
let urls = relay_cache.get(&user).cloned().unwrap_or_default();
for member in members.into_iter() {
// Get user's messaging relays
let urls = relay_cache.get(&member).cloned().unwrap_or_default();
// Check if there are any relays to send the message to
if urls.is_empty() {
reports.push(SendReport::new(user).relays_not_found());
reports.push(SendReport::new(member).relays_not_found());
continue;
}
// Skip sending if using encryption keys but device not found
if device_pubkey.is_none() && matches!(opts.signer_kind, SignerKind::Encryption) {
reports.push(SendReport::new(user).device_not_found());
// Ensure connection to the relays
for url in urls.iter() {
client.add_relay(url).await.ok();
client.connect_relay(url).await.ok();
}
// Get user's encryption public key if available
let encryption = announcement_cache
.get(&member)
.and_then(|a| a.to_owned().map(|a| a.public_key()));
// Skip sending if using encryption signer but receiver's encryption keys not found
if encryption.is_none() && matches!(signer_kind, SignerKind::Encryption) {
reports.push(SendReport::new(member).device_not_found());
continue;
}
// Determine the receiver based on the signer kind
let receiver = Self::select_receiver(&opts.signer_kind, user, device_pubkey)?;
let receiver = Self::select_receiver(&signer_kind, member, encryption)?;
let rumor = rumor.clone();
// Construct the gift wrap event
let rumor = rumor.clone();
let event = EventBuilder::gift_wrap(&signer, &receiver, rumor, []).await?;
// Send the event to the messaging relays
// Send the gift wrap event to the messaging relays
match client.send_event_to(urls, &event).await {
Ok(output) => {
let id = output.id().to_owned();
@@ -590,33 +591,32 @@ impl Room {
}
}
// Select a signer based on previous usage, not from the options
let receiver = Self::select_receiver(&signer_kind, public_key, device_pubkey)?;
// Construct a gift wrap to back up to current user's owned messaging relays
let receiver = Self::select_receiver(&signer_kind, user_pubkey, encryption_pubkey)?;
let rumor = rumor.clone();
// Construct the gift-wrapped event
let event = EventBuilder::gift_wrap(&signer, &receiver, rumor, []).await?;
// Only send a backup message to current user if sent successfully to others
if opts.backup() && reports.iter().all(|r| r.is_sent_success()) {
let urls = relay_cache.get(&public_key).cloned().unwrap_or_default();
let urls = relay_cache.get(&user_pubkey).cloned().unwrap_or_default();
// Check if there are any relays to send the event to
if urls.is_empty() {
reports.push(SendReport::new(public_key).relays_not_found());
reports.push(SendReport::new(user_pubkey).relays_not_found());
} else {
// Send the event to the messaging relays
match client.send_event_to(urls, &event).await {
Ok(output) => {
reports.push(SendReport::new(public_key).status(output));
reports.push(SendReport::new(user_pubkey).status(output));
}
Err(e) => {
reports.push(SendReport::new(public_key).error(e.to_string()));
reports.push(SendReport::new(user_pubkey).error(e.to_string()));
}
}
}
} else {
reports.push(SendReport::new(public_key).on_hold(event));
reports.push(SendReport::new(user_pubkey).on_hold(event));
}
Ok(reports)
@@ -683,37 +683,30 @@ impl Room {
})
}
fn select_signer<T>(
kind: &SignerKind,
device: Option<T>,
user: T,
) -> Result<(T, SignerKind), Error>
fn select_signer<T>(kind: &SignerKind, user: T, encryption: Option<T>) -> Result<T, Error>
where
T: NostrSigner,
{
match kind {
SignerKind::Auto => device
.map(|d| (d, SignerKind::Encryption))
.or(Some((user, SignerKind::User)))
.ok_or_else(|| anyhow!("No signer available")),
SignerKind::Encryption => device
.map(|d| (d, SignerKind::Encryption))
.ok_or_else(|| anyhow!("No encryption key found")),
SignerKind::User => Ok((user, SignerKind::User)),
SignerKind::Encryption => {
Ok(encryption.ok_or_else(|| anyhow!("No encryption key found"))?)
}
SignerKind::User => Ok(user),
SignerKind::Auto => Ok(encryption.unwrap_or(user)),
}
}
fn select_receiver(
kind: &SignerKind,
user: PublicKey,
device: Option<PublicKey>,
encryption: Option<PublicKey>,
) -> Result<PublicKey, Error> {
match kind {
SignerKind::Encryption => {
Ok(device.ok_or_else(|| anyhow!("Receiver's encryption key not found"))?)
Ok(encryption.ok_or_else(|| anyhow!("Receiver's encryption key not found"))?)
}
SignerKind::User => Ok(user),
SignerKind::Auto => Ok(device.unwrap_or(user)),
SignerKind::Auto => Ok(encryption.unwrap_or(user)),
}
}
}