feat: (re)add tracking for where messages have been seen #26
@@ -87,6 +87,9 @@ pub struct ChatRegistry {
|
|||||||
/// Tracking events seen on which relays in the current session
|
/// Tracking events seen on which relays in the current session
|
||||||
seens: Arc<RwLock<HashMap<EventId, HashSet<RelayUrl>>>>,
|
seens: Arc<RwLock<HashMap<EventId, HashSet<RelayUrl>>>>,
|
||||||
|
|
||||||
|
/// Mapping of unwrapped event ids to their gift wrap event ids
|
||||||
|
event_map: Arc<RwLock<HashMap<EventId, EventId>>>,
|
||||||
|
|
||||||
/// Tracking the status of unwrapping gift wrap events.
|
/// Tracking the status of unwrapping gift wrap events.
|
||||||
tracking_flag: Arc<AtomicBool>,
|
tracking_flag: Arc<AtomicBool>,
|
||||||
|
|
||||||
@@ -150,6 +153,7 @@ impl ChatRegistry {
|
|||||||
rooms: vec![],
|
rooms: vec![],
|
||||||
trashes: cx.new(|_| BTreeSet::default()),
|
trashes: cx.new(|_| BTreeSet::default()),
|
||||||
seens: Arc::new(RwLock::new(HashMap::default())),
|
seens: Arc::new(RwLock::new(HashMap::default())),
|
||||||
|
event_map: Arc::new(RwLock::new(HashMap::default())),
|
||||||
tracking_flag: Arc::new(AtomicBool::new(false)),
|
tracking_flag: Arc::new(AtomicBool::new(false)),
|
||||||
signal_rx: rx,
|
signal_rx: rx,
|
||||||
signal_tx: tx,
|
signal_tx: tx,
|
||||||
@@ -165,6 +169,7 @@ impl ChatRegistry {
|
|||||||
let signer = nostr.read(cx).signer();
|
let signer = nostr.read(cx).signer();
|
||||||
let status = self.tracking_flag.clone();
|
let status = self.tracking_flag.clone();
|
||||||
let seens = self.seens.clone();
|
let seens = self.seens.clone();
|
||||||
|
let event_map = self.event_map.clone();
|
||||||
let trashes = self.trashes.downgrade();
|
let trashes = self.trashes.downgrade();
|
||||||
|
|
||||||
let initialized_at = Timestamp::now();
|
let initialized_at = Timestamp::now();
|
||||||
@@ -206,6 +211,13 @@ impl ChatRegistry {
|
|||||||
// Extract the rumor from the gift wrap event
|
// Extract the rumor from the gift wrap event
|
||||||
match extract_rumor(&client, &signer, event.as_ref()).await {
|
match extract_rumor(&client, &signer, event.as_ref()).await {
|
||||||
Ok(rumor) => {
|
Ok(rumor) => {
|
||||||
|
// Map the rumor id to the gift wrap event id for later lookup
|
||||||
|
{
|
||||||
|
let mut event_map = event_map.write().await;
|
||||||
|
event_map.insert(rumor.id.unwrap(), event.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the rumor has a recipient
|
||||||
if rumor.tags.is_empty() {
|
if rumor.tags.is_empty() {
|
||||||
let signal =
|
let signal =
|
||||||
Signal::error(event.as_ref(), "Recipient is missing");
|
Signal::error(event.as_ref(), "Recipient is missing");
|
||||||
@@ -214,6 +226,7 @@ impl ChatRegistry {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the rumor was created after the chat was initialized (for detecting new messages)
|
||||||
if rumor.created_at >= initialized_at {
|
if rumor.created_at >= initialized_at {
|
||||||
let signal = Signal::message(event.id, rumor);
|
let signal = Signal::message(event.id, rumor);
|
||||||
tx.send_async(signal).await?;
|
tx.send_async(signal).await?;
|
||||||
@@ -455,7 +468,15 @@ impl ChatRegistry {
|
|||||||
self.trashes.clone()
|
self.trashes.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the relays that have seen a given message.
|
/// Get the relays that have seen a given rumor id.
|
||||||
|
pub fn rumor_seen_on(&self, id: &EventId) -> Option<HashSet<RelayUrl>> {
|
||||||
|
self.event_map
|
||||||
|
.read_blocking()
|
||||||
|
.get(id)
|
||||||
|
.map(|id| self.seen_on(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the relays that have seen a given gift wrap id.
|
||||||
pub fn seen_on(&self, id: &EventId) -> HashSet<RelayUrl> {
|
pub fn seen_on(&self, id: &EventId) -> HashSet<RelayUrl> {
|
||||||
self.seens
|
self.seens
|
||||||
.read_blocking()
|
.read_blocking()
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ pub enum Command {
|
|||||||
Copy(PublicKey),
|
Copy(PublicKey),
|
||||||
Relays(PublicKey),
|
Relays(PublicKey),
|
||||||
Njump(PublicKey),
|
Njump(PublicKey),
|
||||||
|
Trace(EventId),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
pub use actions::*;
|
pub use actions::*;
|
||||||
use anyhow::{Context as AnyhowContext, Error};
|
use anyhow::{Context as AnyhowContext, Error};
|
||||||
use chat::{Message, RenderedMessage, Room, RoomEvent, SendReport, SendStatus};
|
use chat::{ChatRegistry, Message, RenderedMessage, Room, RoomEvent, SendReport, SendStatus};
|
||||||
use common::RenderedTimestamp;
|
use common::RenderedTimestamp;
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@@ -658,8 +658,55 @@ impl ChatPanel {
|
|||||||
Command::Njump(public_key) => {
|
Command::Njump(public_key) => {
|
||||||
self.open_njump(public_key, cx);
|
self.open_njump(public_key, cx);
|
||||||
}
|
}
|
||||||
|
Command::Trace(id) => {
|
||||||
|
self.open_trace(id, window, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_trace(&mut self, id: &EventId, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
let chat = ChatRegistry::global(cx);
|
||||||
|
let seen_on = chat.read(cx).rumor_seen_on(id);
|
||||||
|
|
||||||
|
window.open_modal(cx, move |this, _window, cx| {
|
||||||
|
this.title("Seen on").show_close(true).child(
|
||||||
|
v_flex()
|
||||||
|
.gap_1()
|
||||||
|
.when_none(&seen_on, |this| {
|
||||||
|
this.child(
|
||||||
|
h_flex()
|
||||||
|
.h_10()
|
||||||
|
.justify_center()
|
||||||
|
.text_sm()
|
||||||
|
.bg(cx.theme().elevated_surface_background)
|
||||||
|
.rounded(cx.theme().radius)
|
||||||
|
.child("Message isn't traced yet"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.when_some(seen_on.as_ref(), |this, relays| {
|
||||||
|
this.children({
|
||||||
|
let mut items = vec![];
|
||||||
|
|
||||||
|
for url in relays.iter() {
|
||||||
|
items.push(
|
||||||
|
h_flex()
|
||||||
|
.h_7()
|
||||||
|
.px_2()
|
||||||
|
.gap_2()
|
||||||
|
.bg(cx.theme().elevated_surface_background)
|
||||||
|
.rounded(cx.theme().radius)
|
||||||
|
.text_sm()
|
||||||
|
.child(div().size_1p5().rounded_full().bg(gpui::green()))
|
||||||
|
.child(SharedString::from(url.to_string())),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
items
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn open_relays(&mut self, public_key: &PublicKey, window: &mut Window, cx: &mut Context<Self>) {
|
fn open_relays(&mut self, public_key: &PublicKey, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let profile = self.profile(public_key, cx);
|
let profile = self.profile(public_key, cx);
|
||||||
@@ -1131,15 +1178,10 @@ impl ChatPanel {
|
|||||||
.ghost()
|
.ghost()
|
||||||
.dropdown_menu({
|
.dropdown_menu({
|
||||||
let public_key = *public_key;
|
let public_key = *public_key;
|
||||||
let _id = *id;
|
let id = *id;
|
||||||
move |this, _window, _cx| {
|
move |this, _window, _cx| {
|
||||||
this.menu("Copy author", Box::new(Command::Copy(public_key)))
|
this.menu("Copy author", Box::new(Command::Copy(public_key)))
|
||||||
/*
|
.menu("Seen on", Box::new(Command::Trace(id)))
|
||||||
.menu(
|
|
||||||
"Trace",
|
|
||||||
Box::new(Command::Trace(id)),
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user