diff --git a/src/nostr.rs b/src/nostr.rs index 058dad2..3b20711 100644 --- a/src/nostr.rs +++ b/src/nostr.rs @@ -4,7 +4,7 @@ use crate::reply::{NostrReply, NostrReplyPrefix}; use crate::WebSocketService; use hyper_tungstenite::tungstenite::Message; use pocket_types::json::{eat_whitespace, json_unescape, verify_char}; -use pocket_types::{Event, Filter, Kind, OwnedFilter, Pubkey, Time}; +use pocket_types::{Event, Filter, Hll8, Kind, OwnedFilter, Pubkey, Time}; use url::Url; impl WebSocketService { @@ -170,7 +170,18 @@ impl WebSocketService { events.dedup(); if count { - let reply = NostrReply::Count(subid, events.len()); + // HyperLogLog count + let mut opthll: Option = None; + if filters.len() == 1 { + if let Ok(Some(offset)) = filters[0].hyperloglog_offset() { + let mut hll8 = Hll8::new(); + for event in events.iter() { + hll8.add_element(event.pubkey().as_bytes(), offset)?; + } + opthll = Some(hll8); + } + } + let reply = NostrReply::Count(subid, events.len(), opthll); self.send(Message::text(reply.as_json())).await?; } else { for event in events.drain(..) { diff --git a/src/reply.rs b/src/reply.rs index 075996d..056b111 100644 --- a/src/reply.rs +++ b/src/reply.rs @@ -1,4 +1,4 @@ -use pocket_types::{Event, Id}; +use pocket_types::{Event, Hll8, Id}; use std::fmt; pub enum NostrReplyPrefix { @@ -36,7 +36,7 @@ pub enum NostrReply<'a> { Eose(&'a str), Closed(&'a str, NostrReplyPrefix, String), Notice(String), - Count(&'a str, usize), + Count(&'a str, usize, Option), } impl NostrReply<'_> { @@ -50,7 +50,14 @@ impl NostrReply<'_> { format!(r#"["CLOSED","{subid}","{prefix}{msg}"]"#) } NostrReply::Notice(msg) => format!(r#"["NOTICE","{msg}"]"#), - NostrReply::Count(subid, c) => format!(r#"["COUNT","{subid}",{{"count":{c}}}"#), + NostrReply::Count(subid, c, opthll) => { + if let Some(hll) = opthll { + let hll = hll.to_hex_string(); + format!(r#"["COUNT","{subid}",{{"count":{c}, "hll":"{hll}"}}]"#) + } else { + format!(r#"["COUNT","{subid}",{{"count":{c}}}]"#) + } + } } } }