wip
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m46s
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m46s
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
_ => {}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user