wip
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m46s

This commit is contained in:
2026-02-17 13:23:43 +07:00
parent 1d8e3724a8
commit 8026a4f5a5
9 changed files with 145 additions and 196 deletions

View File

@@ -149,6 +149,8 @@ impl ChatRegistry {
continue;
}
log::info!("Received gift-wrap event: {event:?}");
// Extract the rumor from the gift wrap event
match Self::extract_rumor(&client, &device_signer, event.as_ref()).await {
Ok(rumor) => match rumor.created_at >= initialized_at {

View File

@@ -524,9 +524,7 @@ impl Room {
};
// Create and send gift-wrapped event
match EventBuilder::gift_wrap(&signer_to_use, &receiver, rumor.clone(), vec![])
.await
{
match EventBuilder::gift_wrap(&signer_to_use, &receiver, rumor.clone(), []).await {
Ok(event) => {
match client
.send_event(&event)

View File

@@ -84,20 +84,20 @@ fn main() {
// Initialize the nostr client
state::init(cx);
// Initialize relay auth registry
relay_auth::init(window, cx);
// Initialize person registry
person::init(cx);
// Initialize device signer
//
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
device::init(window, cx);
// Initialize relay auth registry
relay_auth::init(window, cx);
// Initialize app registry
chat::init(cx);
// Initialize person registry
person::init(cx);
// Initialize auto update
auto_update::init(cx);

View File

@@ -1,11 +1,11 @@
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::time::Duration;
use anyhow::{anyhow, Context as AnyhowContext, Error};
use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task, Window};
use nostr_sdk::prelude::*;
use smallvec::{smallvec, SmallVec};
use state::{app_name, NostrRegistry, RelayState, TIMEOUT};
use state::{app_name, NostrRegistry, RelayState, DEVICE_GIFTWRAP, TIMEOUT};
mod device;
@@ -174,14 +174,48 @@ impl DeviceRegistry {
self.tasks.push(cx.spawn(async move |this, cx| {
signer.set_encryption_signer(new).await;
// Update state
this.update(cx, |this, cx| {
this.set_state(DeviceState::Set, cx);
this.get_messages(cx);
})?;
Ok(())
}));
}
/// Continuously get gift wrap events for the current encryption keys
fn get_messages(&mut self, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let signer = nostr.read(cx).signer();
let messaging_relays = nostr.read(cx).messaging_relays(cx);
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let encryption_signer = signer
.get_encryption_signer()
.await
.context("Signer not found")?;
let public_key = encryption_signer.get_public_key().await?;
let urls = messaging_relays.await;
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
let id = SubscriptionId::new(DEVICE_GIFTWRAP);
// Construct target for subscription
let target: HashMap<&RelayUrl, Filter> =
urls.iter().map(|relay| (relay, filter.clone())).collect();
client.subscribe(target).with_id(id).await?;
log::info!("Subscribed to encryption gift-wrap messages");
Ok(())
});
task.detach();
}
/// Set the device state
fn set_state(&mut self, state: DeviceState, cx: &mut Context<Self>) {
self.state = state;

View File

@@ -144,6 +144,7 @@ impl PersonRegistry {
/// Handle nostr notifications
async fn handle_notifications(client: &Client, tx: &flume::Sender<Dispatch>) {
let mut notifications = client.notifications();
let mut processed: HashSet<EventId> = HashSet::new();
while let Some(notification) = notifications.next().await {
let ClientNotification::Message { message, .. } = notification else {
@@ -152,6 +153,11 @@ impl PersonRegistry {
};
if let RelayMessage::Event { event, .. } = message {
// Skip if the event has already been processed
if !processed.insert(event.id) {
continue;
}
match event.kind {
Kind::Metadata => {
let metadata = Metadata::from_json(&event.content).unwrap_or_default();

View File

@@ -142,7 +142,6 @@ impl RelayAuth {
// Handle authentication messages
if let Some(MachineReadablePrefix::AuthRequired) = msg {
let signal = Signal::Pending((event_id, relay_url));
tx.send_async(signal).await.ok();
}
}
@@ -242,29 +241,35 @@ impl RelayAuth {
.send_msg(ClientMessage::Auth(Cow::Borrowed(&event)))
.await?;
log::info!("Sending AUTH event");
while let Some(notification) = notifications.next().await {
match notification {
RelayNotification::Message {
message: RelayMessage::Ok { event_id, .. },
} => {
if id == event_id {
// Get all subscriptions
let subscriptions = relay.subscriptions().await;
// Re-subscribe to previous subscriptions
for (id, filters) in subscriptions.into_iter() {
relay.subscribe(filters).with_id(id).await?;
}
// Re-send pending events
for id in pending_events {
if let Some(event) = client.database().event_by_id(&id).await? {
relay.send_event(&event).await?;
}
}
return Ok(());
if id != event_id {
continue;
}
// Get all subscriptions
let subscriptions = relay.subscriptions().await;
// Re-subscribe to previous subscriptions
for (id, filters) in subscriptions.into_iter() {
if !filters.is_empty() {
relay.send_msg(ClientMessage::req(id, filters)).await?;
}
}
// Re-send pending events
for id in pending_events {
if let Some(event) = client.database().event_by_id(&id).await? {
relay.send_event(&event).await?;
}
}
return Ok(());
}
RelayNotification::AuthenticationFailed => break,
_ => {}

View File

@@ -1,76 +0,0 @@
use gpui::SharedString;
use nostr_sdk::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum DeviceState {
#[default]
Idle,
Requesting,
Set,
}
impl DeviceState {
pub fn idle(&self) -> bool {
matches!(self, DeviceState::Idle)
}
pub fn requesting(&self) -> bool {
matches!(self, DeviceState::Requesting)
}
pub fn set(&self) -> bool {
matches!(self, DeviceState::Set)
}
}
/// Announcement
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Announcement {
/// The public key of the device that created this announcement.
public_key: PublicKey,
/// The name of the device that created this announcement.
client_name: Option<String>,
}
impl From<&Event> for Announcement {
fn from(val: &Event) -> Self {
let public_key = val
.tags
.iter()
.find(|tag| tag.kind().as_str() == "n")
.and_then(|tag| tag.content())
.and_then(|c| PublicKey::parse(c).ok())
.unwrap_or(val.pubkey);
let client_name = val
.tags
.find(TagKind::Client)
.and_then(|tag| tag.content())
.map(|c| c.to_string());
Self::new(public_key, client_name)
}
}
impl Announcement {
pub fn new(public_key: PublicKey, client_name: Option<String>) -> Self {
Self {
public_key,
client_name,
}
}
/// Returns the public key of the device that created this announcement.
pub fn public_key(&self) -> PublicKey {
self.public_key
}
/// Returns the client name of the device that created this announcement.
pub fn client_name(&self) -> SharedString {
self.client_name
.as_ref()
.map(SharedString::from)
.unwrap_or(SharedString::from("Unknown"))
}
}

View File

@@ -276,8 +276,7 @@ impl NostrRegistry {
.unwrap_or_default();
for relay in relays.iter() {
client.add_relay(relay).await.ok();
client.connect_relay(relay).await.ok();
client.add_relay(relay).and_connect().await.ok();
}
relays
@@ -324,6 +323,7 @@ impl NostrRegistry {
// Update states
this.update(cx, |this, cx| {
this.reset_relay_states(cx);
this.get_relay_list(cx);
})?;
Ok(())
@@ -358,6 +358,7 @@ impl NostrRegistry {
let mut stream = client
.stream_events(target)
.policy(ReqExitPolicy::WaitForEvents(1))
.timeout(Duration::from_secs(TIMEOUT))
.await?;
@@ -435,6 +436,7 @@ impl NostrRegistry {
// Stream events from the write relays
let mut stream = client
.stream_events(filter)
.policy(ReqExitPolicy::WaitForEvents(1))
.timeout(Duration::from_secs(TIMEOUT))
.await?;
@@ -492,37 +494,20 @@ impl NostrRegistry {
let urls = messaging_relays.await;
let public_key = signer.get_public_key().await?;
// Get messages with dekey
if let Some(signer) = signer.get_encryption_signer().await.as_ref() {
let device_pkey = signer.get_public_key().await?;
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(device_pkey);
let id = SubscriptionId::new(DEVICE_GIFTWRAP);
// Construct target for subscription
let target = urls
.iter()
.map(|relay| (relay, vec![filter.clone()]))
.collect::<HashMap<_, _>>();
client.subscribe(target).with_id(id).await?;
}
// Get messages with user key
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
let id = SubscriptionId::new(USER_GIFTWRAP);
// Construct target for subscription
let target = urls
.iter()
.map(|relay| (relay, vec![filter.clone()]))
.collect::<HashMap<_, _>>();
let target: HashMap<&RelayUrl, Filter> =
urls.iter().map(|relay| (relay, filter.clone())).collect();
client.subscribe(target).with_id(id).await?;
log::info!("Subscribed to user gift-wrap messages");
Ok(())
});
task.detach_and_log_err(cx);
task.detach();
}
/// Get profile and contact list for current user
@@ -595,6 +580,7 @@ impl NostrRegistry {
fn set_default_signer(&mut self, cx: &mut Context<Self>) {
let client = self.client();
let keys = Keys::generate();
let async_keys = keys.clone();
// Create a write credential task
let write_credential = cx.write_credentials(
@@ -603,21 +589,18 @@ impl NostrRegistry {
&keys.secret_key().to_secret_bytes(),
);
// Update the signer
self.set_signer(keys, false, cx);
// Set the creating signer status
self.set_creating_signer(true, cx);
// Run async tasks in background
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let signer = client.signer().context("Signer not found")?;
let signer = async_keys.into_nostr_signer();
// Get default relay list
let relay_list = default_relay_list();
// Publish relay list event
let event = EventBuilder::relay_list(relay_list).sign(signer).await?;
let event = EventBuilder::relay_list(relay_list).sign(&signer).await?;
client
.send_event(&event)
.broadcast()
@@ -630,7 +613,7 @@ impl NostrRegistry {
let metadata = Metadata::new().display_name(&name).picture(avatar);
// Publish metadata event
let event = EventBuilder::metadata(&metadata).sign(signer).await?;
let event = EventBuilder::metadata(&metadata).sign(&signer).await?;
client
.send_event(&event)
.broadcast()
@@ -642,7 +625,7 @@ impl NostrRegistry {
let contacts = vec![Contact::new(PublicKey::parse(COOP_PUBKEY).unwrap())];
// Publish contact list event
let event = EventBuilder::contact_list(contacts).sign(signer).await?;
let event = EventBuilder::contact_list(contacts).sign(&signer).await?;
client
.send_event(&event)
.broadcast()
@@ -654,7 +637,7 @@ impl NostrRegistry {
let relays = default_messaging_relays();
// Publish messaging relay list event
let event = EventBuilder::nip17_relay_list(relays).sign(signer).await?;
let event = EventBuilder::nip17_relay_list(relays).sign(&signer).await?;
client
.send_event(&event)
.to_nip65()
@@ -674,7 +657,7 @@ impl NostrRegistry {
this.update(cx, |this, cx| {
this.set_creating_signer(false, cx);
this.get_relay_list(cx);
this.set_signer(keys, false, cx);
})?;
Ok(())
@@ -693,7 +676,6 @@ impl NostrRegistry {
this.update(cx, |this, cx| {
this.set_signer(keys, false, cx);
this.get_relay_list(cx);
})?;
}
_ => {
@@ -736,7 +718,6 @@ impl NostrRegistry {
Ok(signer) => {
this.update(cx, |this, cx| {
this.set_signer(signer, true, cx);
this.get_relay_list(cx);
})
.ok();
}