Major rework away from PublicKeyHex towards using PublicKey instead. NOTES:

We plan to switch to a different secp256k1 library soon, at which point this PublicKey will
become interoperable again, e.g. in gossip-relay-picker
This commit is contained in:
Mike Dilger 2023-07-25 09:46:56 +12:00
parent f5538f4476
commit 6b43ae7558
24 changed files with 367 additions and 435 deletions

View File

@ -1,5 +1,5 @@
use nostr_types::{
Event, Id, IdHex, Metadata, MilliSatoshi, PublicKey, PublicKeyHex, RelayUrl, Tag, UncheckedUrl,
Event, Id, IdHex, Metadata, MilliSatoshi, PublicKey, RelayUrl, Tag, UncheckedUrl,
};
/// This is a message sent to the Overlord
@ -38,14 +38,14 @@ pub enum ToOverlordMessage {
RankRelay(RelayUrl, u8),
SaveSettings,
Search(String),
SetActivePerson(PublicKeyHex),
SetActivePerson(PublicKey),
AdjustRelayUsageBit(RelayUrl, u64, bool),
SetThreadFeed(Id, Id, Vec<RelayUrl>, Option<PublicKeyHex>),
SetThreadFeed(Id, Id, Vec<RelayUrl>, Option<PublicKey>),
Shutdown,
UnlockKey(String),
UpdateFollowing(bool),
UpdateMetadata(PublicKeyHex),
UpdateMetadataInBulk(Vec<PublicKeyHex>),
UpdateMetadata(PublicKey),
UpdateMetadataInBulk(Vec<PublicKey>),
VisibleNotesChanged(Vec<Id>),
ZapStart(Id, PublicKey, UncheckedUrl),
Zap(Id, PublicKey, MilliSatoshi, String),
@ -77,12 +77,12 @@ pub enum ToMinionPayloadDetail {
Shutdown,
SubscribeAugments(Vec<IdHex>),
SubscribeConfig,
SubscribeDiscover(Vec<PublicKeyHex>),
SubscribeGeneralFeed(Vec<PublicKeyHex>),
SubscribeDiscover(Vec<PublicKey>),
SubscribeGeneralFeed(Vec<PublicKey>),
SubscribeMentions,
SubscribePersonFeed(PublicKeyHex),
SubscribePersonFeed(PublicKey),
SubscribeThreadFeed(IdHex, Vec<IdHex>),
TempSubscribeMetadata(Vec<PublicKeyHex>),
TempSubscribeMetadata(Vec<PublicKey>),
UnsubscribePersonFeed,
UnsubscribeThreadFeed,
}

View File

@ -1,7 +1,7 @@
use crate::comms::{ToMinionMessage, ToMinionPayload, ToMinionPayloadDetail, ToOverlordMessage};
use crate::error::Error;
use crate::globals::GLOBALS;
use nostr_types::{EventDelegation, EventKind, Id, PublicKey, PublicKeyHex, RelayUrl, Unixtime};
use nostr_types::{EventDelegation, EventKind, Id, PublicKey, RelayUrl, Unixtime};
use parking_lot::RwLock;
use std::collections::HashSet;
use std::sync::atomic::{AtomicBool, Ordering};
@ -15,9 +15,9 @@ pub enum FeedKind {
Thread {
id: Id,
referenced_by: Id,
author: Option<PublicKeyHex>,
author: Option<PublicKey>,
},
Person(PublicKeyHex),
Person(PublicKey),
}
pub struct Feed {
@ -106,12 +106,12 @@ impl Feed {
id: Id,
referenced_by: Id,
relays: Vec<RelayUrl>,
author: Option<PublicKeyHex>,
author: Option<PublicKey>,
) {
*self.current_feed_kind.write() = FeedKind::Thread {
id,
referenced_by,
author: author.clone(),
author,
};
// Parent starts with the post itself
@ -136,8 +136,8 @@ impl Feed {
));
}
pub fn set_feed_to_person(&self, pubkey: PublicKeyHex) {
*self.current_feed_kind.write() = FeedKind::Person(pubkey.clone());
pub fn set_feed_to_person(&self, pubkey: PublicKey) {
*self.current_feed_kind.write() = FeedKind::Person(pubkey);
*self.thread_parent.write() = None;
// Recompute as they switch
@ -243,12 +243,7 @@ impl Feed {
let current_feed_kind = self.current_feed_kind.read().to_owned();
match current_feed_kind {
FeedKind::Followed(with_replies) => {
let mut followed_pubkeys: Vec<PublicKey> = GLOBALS
.people
.get_followed_pubkeys()
.iter()
.map(|pk| PublicKey::try_from_hex_string(pk).unwrap())
.collect();
let mut followed_pubkeys: Vec<PublicKey> = GLOBALS.people.get_followed_pubkeys();
if let Some(pubkey) = GLOBALS.signer.public_key() {
followed_pubkeys.push(pubkey); // add the user
@ -371,11 +366,11 @@ impl Feed {
if dismissed.contains(&e.id) {
return false;
} // not dismissed
if e.pubkey.as_hex_string() == person_pubkey.as_str() {
if e.pubkey == person_pubkey {
true
} else {
if let EventDelegation::DelegatedBy(pk) = e.delegation() {
pk.as_hex_string() == person_pubkey.as_str()
pk == person_pubkey
} else {
false
}

View File

@ -4,7 +4,7 @@ use crate::delegation::Delegation;
use crate::feed::Feed;
use crate::fetcher::Fetcher;
use crate::media::Media;
use crate::people::{Person, People};
use crate::people::{People, Person};
use crate::relay_picker_hooks::Hooks;
use crate::settings::Settings;
use crate::signer::Signer;
@ -12,9 +12,7 @@ use crate::status::StatusQueue;
use crate::storage::Storage;
use dashmap::DashMap;
use gossip_relay_picker::RelayPicker;
use nostr_types::{
Event, Id, PayRequestData, Profile, PublicKey, PublicKeyHex, RelayUrl, UncheckedUrl,
};
use nostr_types::{Event, Id, PayRequestData, Profile, PublicKey, RelayUrl, UncheckedUrl};
use parking_lot::RwLock as PRwLock;
use regex::Regex;
use rusqlite::Connection;
@ -83,7 +81,7 @@ pub struct Globals {
/// Failed Avatars
/// If in this map, the avatar failed to load or process and is unrecoverable
/// (but we will take them out and try again if new metadata flows in)
pub failed_avatars: RwLock<HashSet<PublicKeyHex>>,
pub failed_avatars: RwLock<HashSet<PublicKey>>,
pub pixels_per_point_times_100: AtomicU32,
@ -108,7 +106,7 @@ pub struct Globals {
/// UI note cache invalidation per person
// when we update a Person, the UI must recompute all notes by them
pub ui_people_to_invalidate: PRwLock<Vec<PublicKeyHex>>,
pub ui_people_to_invalidate: PRwLock<Vec<PublicKey>>,
/// Current zap data, for UI
pub current_zap: PRwLock<ZapState>,

View File

@ -2,7 +2,7 @@ use crate::db::PersonRelay;
use crate::error::{Error, ErrorKind};
use crate::globals::GLOBALS;
use crate::people::Person;
use nostr_types::{Metadata, Nip05, PublicKeyHex, RelayUrl, Unixtime};
use nostr_types::{Metadata, Nip05, PublicKey, RelayUrl, Unixtime};
use std::sync::atomic::Ordering;
// This updates the people map and the database with the result
@ -50,13 +50,26 @@ pub async fn validate_nip05(person: Person) -> Result<(), Error> {
let mut valid = false;
match nip05file.names.get(&user) {
Some(pk) => {
if *pk == person.pubkey {
// Validated
if let Ok(pubkey) = PublicKey::try_from_hex_string(pk) {
if pubkey == person.pubkey {
// Validated
GLOBALS
.people
.upsert_nip05_validity(
&person.pubkey,
Some(nip05.clone()),
true,
now.0 as u64,
)
.await?;
valid = true;
}
} else {
// Failed
GLOBALS
.people
.upsert_nip05_validity(&person.pubkey, Some(nip05.clone()), true, now.0 as u64)
.upsert_nip05_validity(&person.pubkey, Some(nip05.clone()), false, now.0 as u64)
.await?;
valid = true;
}
}
None => {
@ -69,10 +82,7 @@ pub async fn validate_nip05(person: Person) -> Result<(), Error> {
}
// UI cache invalidation (so notes of the person get rerendered)
GLOBALS
.ui_people_to_invalidate
.write()
.push(person.pubkey.clone());
GLOBALS.ui_people_to_invalidate.write().push(person.pubkey);
if valid {
update_relays(nip05, nip05file, &person.pubkey).await?;
@ -90,7 +100,7 @@ pub async fn get_and_follow_nip05(nip05: String) -> Result<(), Error> {
// Get their pubkey
let pubkey = match nip05file.names.get(&user) {
Some(pk) => pk.to_owned(),
Some(pk) => PublicKey::try_from_hex_string(pk)?,
None => return Err((ErrorKind::Nip05KeyNotFound, file!(), line!()).into()),
};
@ -115,13 +125,9 @@ pub async fn get_and_follow_nip05(nip05: String) -> Result<(), Error> {
Ok(())
}
async fn update_relays(
nip05: String,
nip05file: Nip05,
pubkey: &PublicKeyHex,
) -> Result<(), Error> {
async fn update_relays(nip05: String, nip05file: Nip05, pubkey: &PublicKey) -> Result<(), Error> {
// Set their relays
let relays = match nip05file.relays.get(pubkey) {
let relays = match nip05file.relays.get(&(*pubkey).into()) {
Some(relays) => relays,
None => return Ok(()),
};
@ -132,7 +138,7 @@ async fn update_relays(
// Save person_relay
PersonRelay::upsert_last_suggested_nip05(
pubkey.to_owned(),
(*pubkey).into(),
relay_url,
Unixtime::now().unwrap().0 as u64,
)

View File

@ -15,8 +15,8 @@ use http::uri::{Parts, Scheme};
use http::Uri;
use mime::Mime;
use nostr_types::{
ClientMessage, EventKind, Filter, Id, IdHex, IdHexPrefix, PublicKeyHex, PublicKeyHexPrefix,
RelayInformationDocument, RelayUrl, Unixtime,
ClientMessage, EventKind, Filter, Id, IdHex, IdHexPrefix, PublicKey, PublicKeyHex,
PublicKeyHexPrefix, RelayInformationDocument, RelayUrl, Unixtime,
};
use reqwest::Response;
use std::borrow::Cow;
@ -347,16 +347,15 @@ impl Minion {
ToMinionPayloadDetail::SubscribeDiscover(pubkeys) => {
self.subscribe_discover(message.job_id, pubkeys).await?;
}
ToMinionPayloadDetail::SubscribePersonFeed(pubkeyhex) => {
self.subscribe_person_feed(message.job_id, pubkeyhex)
.await?;
ToMinionPayloadDetail::SubscribePersonFeed(pubkey) => {
self.subscribe_person_feed(message.job_id, pubkey).await?;
}
ToMinionPayloadDetail::SubscribeThreadFeed(main, parents) => {
self.subscribe_thread_feed(message.job_id, main, parents)
.await?;
}
ToMinionPayloadDetail::TempSubscribeMetadata(pubkeyhexs) => {
self.temp_subscribe_metadata(message.job_id, pubkeyhexs)
ToMinionPayloadDetail::TempSubscribeMetadata(pubkeys) => {
self.temp_subscribe_metadata(message.job_id, pubkeys)
.await?;
}
ToMinionPayloadDetail::UnsubscribePersonFeed => {
@ -406,7 +405,7 @@ impl Minion {
async fn subscribe_general_feed(
&mut self,
job_id: u64,
followed_pubkeys: Vec<PublicKeyHex>,
followed_pubkeys: Vec<PublicKey>,
) -> Result<(), Error> {
let mut filters: Vec<Filter> = Vec::new();
let (overlap, feed_chunk) = {
@ -472,7 +471,7 @@ impl Minion {
if !followed_pubkeys.is_empty() {
let pkp: Vec<PublicKeyHexPrefix> = followed_pubkeys
.iter()
.map(|pk| pk.prefix(16)) // quarter-size
.map(|pk| Into::<PublicKeyHex>::into(*pk).prefix(16)) // quarter-size
.collect();
// feed related by people followed
@ -493,7 +492,7 @@ impl Minion {
.people
.get_followed_pubkeys_needing_relay_lists(&followed_pubkeys)
.drain(..)
.map(|pk| pk.prefix(16)) // quarter-size
.map(|pk| Into::<PublicKeyHex>::into(pk).prefix(16)) // quarter-size
.collect();
if !keys_needing_relay_lists.is_empty() {
@ -634,10 +633,13 @@ impl Minion {
async fn subscribe_discover(
&mut self,
job_id: u64,
pubkeys: Vec<PublicKeyHex>,
pubkeys: Vec<PublicKey>,
) -> Result<(), Error> {
if !pubkeys.is_empty() {
let pkp: Vec<PublicKeyHexPrefix> = pubkeys.iter().map(|pk| pk.prefix(16)).collect(); // quarter-size prefix
let pkp: Vec<PublicKeyHexPrefix> = pubkeys
.iter()
.map(|pk| Into::<PublicKeyHex>::into(*pk).prefix(16))
.collect(); // quarter-size prefix
let filters: Vec<Filter> = vec![Filter {
authors: pkp,
@ -653,11 +655,7 @@ impl Minion {
}
// Subscribe to the posts a person generates on the relays they write to
async fn subscribe_person_feed(
&mut self,
job_id: u64,
pubkey: PublicKeyHex,
) -> Result<(), Error> {
async fn subscribe_person_feed(&mut self, job_id: u64, pubkey: PublicKey) -> Result<(), Error> {
// NOTE we do not unsubscribe to the general feed
// Allow all feed related event kinds
@ -667,7 +665,7 @@ impl Minion {
.retain(|f| *f != EventKind::EncryptedDirectMessage && *f != EventKind::Reaction);
let filters: Vec<Filter> = vec![Filter {
authors: vec![pubkey.clone().into()],
authors: vec![Into::<PublicKeyHex>::into(pubkey).prefix(16)],
kinds: event_kinds,
// No since, just a limit on quantity of posts
limit: Some(25),
@ -922,12 +920,12 @@ impl Minion {
async fn temp_subscribe_metadata(
&mut self,
job_id: u64,
mut pubkeyhexs: Vec<PublicKeyHex>,
mut pubkeys: Vec<PublicKey>,
) -> Result<(), Error> {
let pkhp: Vec<PublicKeyHexPrefix> = pubkeyhexs
let pkhp: Vec<PublicKeyHexPrefix> = pubkeys
.drain(..)
.map(
|pk| pk.prefix(16), // quarter-size
|pk| Into::<PublicKeyHex>::into(pk).prefix(16), // quarter-size
)
.collect();

View File

@ -3,7 +3,7 @@ mod minion;
use crate::comms::{
RelayJob, ToMinionMessage, ToMinionPayload, ToMinionPayloadDetail, ToOverlordMessage,
};
use crate::db::{PersonRelay, DbRelay};
use crate::db::{DbRelay, PersonRelay};
use crate::error::{Error, ErrorKind};
use crate::globals::{ZapState, GLOBALS};
use crate::people::People;
@ -15,9 +15,8 @@ use gossip_relay_picker::{Direction, RelayAssignment};
use http::StatusCode;
use minion::Minion;
use nostr_types::{
EncryptedPrivateKey, EventKind, Id, IdHex, Metadata, MilliSatoshi, NostrBech32,
PayRequestData, PreEvent, PrivateKey, Profile, PublicKey, PublicKeyHex, RelayUrl, Tag,
UncheckedUrl, Unixtime,
EncryptedPrivateKey, EventKind, Id, IdHex, Metadata, MilliSatoshi, NostrBech32, PayRequestData,
PreEvent, PrivateKey, Profile, PublicKey, PublicKeyHex, RelayUrl, Tag, UncheckedUrl, Unixtime,
};
use std::collections::HashMap;
use std::sync::atomic::Ordering;
@ -715,7 +714,7 @@ impl Overlord {
}
ToOverlordMessage::UpdateMetadata(pubkey) => {
let best_relays =
PersonRelay::get_best_relays(pubkey.clone(), Direction::Write).await?;
PersonRelay::get_best_relays(pubkey.into(), Direction::Write).await?;
let num_relays_per_person = GLOBALS.settings.read().num_relays_per_person;
// we do 1 more than num_relays_per_person, which is really for main posts,
@ -730,9 +729,7 @@ impl Overlord {
reason: "tmp-metadata",
payload: ToMinionPayload {
job_id: rand::random::<u64>(),
detail: ToMinionPayloadDetail::TempSubscribeMetadata(vec![
pubkey.clone()
]),
detail: ToMinionPayloadDetail::TempSubscribeMetadata(vec![pubkey]),
},
persistent: false,
}],
@ -746,16 +743,16 @@ impl Overlord {
}
ToOverlordMessage::UpdateMetadataInBulk(mut pubkeys) => {
let num_relays_per_person = GLOBALS.settings.read().num_relays_per_person;
let mut map: HashMap<RelayUrl, Vec<PublicKeyHex>> = HashMap::new();
let mut map: HashMap<RelayUrl, Vec<PublicKey>> = HashMap::new();
for pubkey in pubkeys.drain(..) {
let best_relays =
PersonRelay::get_best_relays(pubkey.clone(), Direction::Write).await?;
PersonRelay::get_best_relays(pubkey.into(), Direction::Write).await?;
for (relay_url, _score) in
best_relays.iter().take(num_relays_per_person as usize + 1)
{
map.entry(relay_url.to_owned())
.and_modify(|entry| entry.push(pubkey.clone()))
.or_insert_with(|| vec![pubkey.clone()]);
.and_modify(|entry| entry.push(pubkey))
.or_insert_with(|| vec![pubkey]);
}
}
for (relay_url, pubkeys) in map.drain() {
@ -826,14 +823,13 @@ impl Overlord {
pubkeystr: String,
relay: RelayUrl,
) -> Result<(), Error> {
let pk = match PublicKey::try_from_bech32_string(&pubkeystr) {
let pubkey = match PublicKey::try_from_bech32_string(&pubkeystr) {
Ok(pk) => pk,
Err(_) => PublicKey::try_from_hex_string(&pubkeystr)?,
};
let pkhex: PublicKeyHex = pk.into();
GLOBALS.people.async_follow(&pkhex, true).await?;
GLOBALS.people.async_follow(&pubkey, true).await?;
tracing::debug!("Followed {}", &pkhex);
tracing::debug!("Followed {}", &pubkey.as_hex_string());
// Save relay
let db_relay = DbRelay::new(relay.clone());
@ -843,7 +839,7 @@ impl Overlord {
// Save person_relay
PersonRelay::insert(PersonRelay {
person: pkhex.to_string(),
person: pubkey.as_hex_string(),
relay,
last_fetched: None,
last_suggested_kind3: Some(now), // consider it our claim in our contact list
@ -860,7 +856,7 @@ impl Overlord {
// Pick relays to start tracking them now
self.pick_relays().await;
tracing::info!("Setup 1 relay for {}", &pkhex);
tracing::info!("Setup 1 relay for {}", &pubkey.as_hex_string());
Ok(())
}
@ -1347,23 +1343,23 @@ impl Overlord {
// add own pubkey as well
if let Some(pubkey) = GLOBALS.signer.public_key() {
pubkeys.push(pubkey.into())
pubkeys.push(pubkey)
}
let num_relays_per_person = GLOBALS.settings.read().num_relays_per_person;
let mut map: HashMap<RelayUrl, Vec<PublicKeyHex>> = HashMap::new();
let mut map: HashMap<RelayUrl, Vec<PublicKey>> = HashMap::new();
// Sort the people into the relays we will find their metadata at
for pubkey in &pubkeys {
for relayscore in PersonRelay::get_best_relays(pubkey.to_owned(), Direction::Write)
for relayscore in PersonRelay::get_best_relays((*pubkey).into(), Direction::Write)
.await?
.drain(..)
.take(num_relays_per_person as usize)
{
map.entry(relayscore.0)
.and_modify(|e| e.push(pubkey.to_owned()))
.or_insert_with(|| vec![pubkey.to_owned()]);
.and_modify(|e| e.push(*pubkey))
.or_insert_with(|| vec![*pubkey]);
}
}
@ -1503,7 +1499,7 @@ impl Overlord {
id: Id,
referenced_by: Id,
mut relays: Vec<RelayUrl>,
author: Option<PublicKeyHex>,
author: Option<PublicKey>,
) -> Result<(), Error> {
// We are responsible for loading all the ancestors and all the replies, and
// process.rs is responsible for building the relationships.
@ -1522,19 +1518,25 @@ impl Overlord {
// Include the relays where the referenced_by event was seen
relays.extend(
GLOBALS.storage.get_event_seen_on_relay(referenced_by)?
GLOBALS
.storage
.get_event_seen_on_relay(referenced_by)?
.drain(..)
.map(|(url, _time)| url));
.map(|(url, _time)| url),
);
relays.extend(
GLOBALS.storage.get_event_seen_on_relay(id)?
GLOBALS
.storage
.get_event_seen_on_relay(id)?
.drain(..)
.map(|(url, _time)| url));
.map(|(url, _time)| url),
);
// If we have less than 2 relays, include the write relays of the author
if relays.len() < 2 {
if let Some(pkh) = author {
if let Some(pk) = author {
let author_relays: Vec<RelayUrl> =
PersonRelay::get_best_relays(pkh, Direction::Write)
PersonRelay::get_best_relays(pk.into(), Direction::Write)
.await?
.drain(..)
.map(|pair| pair.0)
@ -1626,8 +1628,7 @@ impl Overlord {
}
async fn follow_nprofile(&mut self, nprofile: Profile) -> Result<(), Error> {
let pubkey = nprofile.pubkey.into();
GLOBALS.people.async_follow(&pubkey, true).await?;
GLOBALS.people.async_follow(&nprofile.pubkey, true).await?;
// Set their relays
for relay in nprofile.relays.iter() {
@ -1638,7 +1639,7 @@ impl Overlord {
// Save person_relay
PersonRelay::upsert_last_suggested_nip05(
pubkey.to_owned(),
nprofile.pubkey.into(),
relay_url,
Unixtime::now().unwrap().0 as u64,
)
@ -1756,7 +1757,7 @@ impl Overlord {
}
};
let mut pubkeys: Vec<PublicKeyHex> = Vec::new();
let mut pubkeys: Vec<PublicKey> = Vec::new();
let now = Unixtime::now().unwrap();
@ -1768,33 +1769,34 @@ impl Overlord {
..
} = tag
{
// Make sure we have that person
GLOBALS
.people
.create_all_if_missing(&[pubkey.to_owned()])
.await?;
if let Ok(pubkey) = PublicKey::try_from_hex_string(pubkey) {
// Make sure we have that person
GLOBALS
.people
.create_all_if_missing(&[pubkey.to_owned()])
.await?;
// Save the pubkey for actual following them (outside of the loop in a batch)
pubkeys.push(pubkey.to_owned());
// Save the pubkey for actual following them (outside of the loop in a batch)
pubkeys.push(pubkey.to_owned());
// If there is a URL
if let Some(url) = recommended_relay_url
.as_ref()
.and_then(|rru| RelayUrl::try_from_unchecked_url(rru).ok())
{
// Save relay if missing
GLOBALS.storage.write_relay_if_missing(&url)?;
// If there is a URL
if let Some(url) = recommended_relay_url
.as_ref()
.and_then(|rru| RelayUrl::try_from_unchecked_url(rru).ok())
{
// Save relay if missing
GLOBALS.storage.write_relay_if_missing(&url)?;
// create or update person_relay last_suggested_kind3
PersonRelay::upsert_last_suggested_kind3(
pubkey.to_string(),
url,
now.0 as u64,
)
.await?;
// create or update person_relay last_suggested_kind3
PersonRelay::upsert_last_suggested_kind3(
pubkey.as_hex_string(),
url,
now.0 as u64,
)
.await?;
}
// TBD: do something with the petname
}
// TBD: do something with the petname
}
}

View File

@ -20,7 +20,7 @@ use tokio::task;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Person {
pub pubkey: PublicKeyHex,
pub pubkey: PublicKey,
pub petname: Option<String>,
pub followed: u8,
pub followed_last_updated: i64,
@ -36,7 +36,7 @@ pub struct Person {
}
impl Person {
pub fn new(pubkey: PublicKeyHex) -> Person {
pub fn new(pubkey: PublicKey) -> Person {
Person {
pubkey,
petname: None,
@ -103,30 +103,30 @@ impl Person {
}
pub struct People {
people: DashMap<PublicKeyHex, Person>,
people: DashMap<PublicKey, Person>,
// active person's relays (pull from db as needed)
active_person: RwLock<Option<PublicKeyHex>>,
active_person: RwLock<Option<PublicKey>>,
active_persons_write_relays: RwLock<Vec<(RelayUrl, u64)>>,
// We fetch (with Fetcher), process, and temporarily hold avatars
// until the UI next asks for them, at which point we remove them
// and hand them over. This way we can do the work that takes
// longer and the UI can do as little work as possible.
avatars_temp: DashMap<PublicKeyHex, ColorImage>,
avatars_pending_processing: DashSet<PublicKeyHex>,
avatars_temp: DashMap<PublicKey, ColorImage>,
avatars_pending_processing: DashSet<PublicKey>,
// When we manually ask for updating metadata, we want to recheck
// the person's NIP-05 when that metadata come in. We remember this here.
recheck_nip05: DashSet<PublicKeyHex>,
recheck_nip05: DashSet<PublicKey>,
// People that need metadata, which the UI has asked for. These people
// might simply not be loaded from the database yet.
need_metadata: DashSet<PublicKeyHex>,
need_metadata: DashSet<PublicKey>,
// People who we already tried to get their metadata. We only try once
// per gossip run (this set only grows)
tried_metadata: DashSet<PublicKeyHex>,
tried_metadata: DashSet<PublicKey>,
// Date of the last self-owned contact list we have an event for
pub last_contact_list_asof: AtomicI64,
@ -173,25 +173,25 @@ impl People {
});
}
pub fn get_followed_pubkeys(&self) -> Vec<PublicKeyHex> {
let mut output: Vec<PublicKeyHex> = Vec::new();
pub fn get_followed_pubkeys(&self) -> Vec<PublicKey> {
let mut output: Vec<PublicKey> = Vec::new();
for person in self
.people
.iter()
.filter_map(|p| if p.followed == 1 { Some(p) } else { None })
{
output.push(person.pubkey.clone());
output.push(person.pubkey);
}
output
}
pub fn get_followed_pubkeys_needing_relay_lists(
&self,
among_these: &[PublicKeyHex],
) -> Vec<PublicKeyHex> {
among_these: &[PublicKey],
) -> Vec<PublicKey> {
// FIXME make this a setting (8 hours)
let one_day_ago = Unixtime::now().unwrap().0 - (60 * 60 * 8);
let mut output: Vec<PublicKeyHex> = Vec::new();
let mut output: Vec<PublicKey> = Vec::new();
for person in self.people.iter().filter_map(|p| {
if p.followed == 1
&& p.relay_list_last_received < one_day_ago
@ -202,22 +202,22 @@ impl People {
None
}
}) {
output.push(person.pubkey.clone());
output.push(person.pubkey);
}
output
}
pub fn create_if_missing_sync(&self, pubkey: PublicKeyHex) {
task::spawn(async {
pub fn create_if_missing_sync(&self, pubkey: PublicKey) {
task::spawn(async move {
if let Err(e) = GLOBALS.people.create_all_if_missing(&[pubkey]).await {
tracing::error!("{}", e);
}
});
}
pub async fn create_all_if_missing(&self, pubkeys: &[PublicKeyHex]) -> Result<(), Error> {
pub async fn create_all_if_missing(&self, pubkeys: &[PublicKey]) -> Result<(), Error> {
// Collect the public keys that we don't have already (by checking in memory).
let pubkeys: Vec<&PublicKeyHex> = pubkeys
let pubkeys: Vec<&PublicKey> = pubkeys
.iter()
.filter(|pk| !self.people.contains_key(pk))
.collect();
@ -231,7 +231,7 @@ impl People {
sql.push_str(&"(?),".repeat(pubkeys.len()));
sql.pop(); // remove trailing comma
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.to_string()).collect();
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.as_hex_string()).collect();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
@ -249,9 +249,7 @@ impl People {
// Now load them from the database (some of them may have had records already)
let mut loaded_people = Self::fetch_many(&pubkeys).await?;
for loaded_person in loaded_people.drain(..) {
let _ = self
.people
.insert(loaded_person.pubkey.clone(), loaded_person);
let _ = self.people.insert(loaded_person.pubkey, loaded_person);
}
Ok(())
@ -259,23 +257,23 @@ impl People {
// If this person doesn't have metadata, and we are automatically fetching
// metadata, then add this person to the list of people that need metadata.
pub fn person_of_interest(&self, pubkeyhex: PublicKeyHex) {
pub fn person_of_interest(&self, pubkey: PublicKey) {
// Don't get metadata if disabled
if !GLOBALS.settings.read().automatically_fetch_metadata {
return;
}
// Don't try over and over. We try just once per gossip run.
if self.tried_metadata.contains(&pubkeyhex) {
if self.tried_metadata.contains(&pubkey) {
return;
}
match self.people.get(&pubkeyhex) {
match self.people.get(&pubkey) {
Some(person) => {
// If we haven't loaded the person from the database yet
if !person.loaded {
// Trigger a future load
self.create_if_missing_sync(pubkeyhex.clone());
self.create_if_missing_sync(pubkey);
// Don't load metadata now, we may have it on disk and get
// it from the future load.
@ -296,13 +294,13 @@ impl People {
// Record that we need it.
// the periodic task will take care of it.
if !self.need_metadata.contains(&pubkeyhex) {
self.need_metadata.insert(pubkeyhex.clone());
if !self.need_metadata.contains(&pubkey) {
self.need_metadata.insert(pubkey);
}
}
None => {
// Trigger a future create and load
self.create_if_missing_sync(pubkeyhex.clone());
self.create_if_missing_sync(pubkey);
// Don't load metadata now, we may have it on disk and get
// it from the future load.
@ -313,10 +311,10 @@ impl People {
// This is run periodically. It checks the database first, only then does it
// ask the overlord to update the metadata from the relays.
async fn maybe_fetch_metadata(&self) {
let mut verified_need: Vec<PublicKeyHex> = Vec::new();
let mut verified_need: Vec<PublicKey> = Vec::new();
// Take from self.need_metadata;
let mut need_metadata: Vec<PublicKeyHex> = self
let mut need_metadata: Vec<PublicKey> = self
.need_metadata
.iter()
.map(|refmulti| refmulti.key().to_owned())
@ -330,8 +328,8 @@ impl People {
for pubkey in need_metadata.drain(..) {
if let Some(person) = self.people.get(&pubkey) {
if person.loaded {
tracing::debug!("Seeking metadata for {}", &pubkey);
verified_need.push(pubkey.clone());
tracing::debug!("Seeking metadata for {}", pubkey.as_hex_string());
verified_need.push(pubkey);
self.tried_metadata.insert(pubkey);
}
}
@ -342,30 +340,30 @@ impl People {
.send(ToOverlordMessage::UpdateMetadataInBulk(verified_need));
}
pub fn recheck_nip05_on_update_metadata(&self, pubkeyhex: &PublicKeyHex) {
self.recheck_nip05.insert(pubkeyhex.to_owned());
pub fn recheck_nip05_on_update_metadata(&self, pubkey: &PublicKey) {
self.recheck_nip05.insert(pubkey.to_owned());
}
pub async fn update_metadata(
&self,
pubkeyhex: &PublicKeyHex,
pubkey: &PublicKey,
metadata: Metadata,
asof: Unixtime,
) -> Result<(), Error> {
// Sync in from database first
self.create_all_if_missing(&[pubkeyhex.to_owned()]).await?;
self.create_all_if_missing(&[*pubkey]).await?;
let now = Unixtime::now().unwrap();
// Update metadata_last_received, even if we don't update the metadata
{
// Update in memory
if let Some(mut person) = self.people.get_mut(pubkeyhex) {
if let Some(mut person) = self.people.get_mut(pubkey) {
person.metadata_last_received = now.0;
}
// Update in database
let pkh = pubkeyhex.as_str().to_owned();
let pkh: String = pubkey.as_hex_string();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
let mut stmt =
@ -377,10 +375,10 @@ impl People {
}
// Copy the person
let mut person = self.people.get(pubkeyhex).unwrap().to_owned();
let mut person = self.people.get(pubkey).unwrap().to_owned();
// Remove from the list of people that need metadata
self.need_metadata.remove(pubkeyhex);
self.need_metadata.remove(pubkey);
// Determine whether it is fresh
let fresh = match person.metadata_created_at {
@ -397,7 +395,7 @@ impl People {
// Update person in the map, and the local variable
person = {
let mut person_mut = self.people.get_mut(pubkeyhex).unwrap();
let mut person_mut = self.people.get_mut(pubkey).unwrap();
person_mut.metadata = Some(metadata);
person_mut.metadata_created_at = Some(asof.0);
if nip05_changed {
@ -408,7 +406,7 @@ impl People {
};
// Update the database
let pubkeyhex2 = pubkeyhex.to_owned();
let pubkeyhex2: PublicKeyHex = (*pubkey).into();
let person_inner = person.clone();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
@ -434,14 +432,11 @@ impl People {
.await??;
// UI cache invalidation (so notes of the person get rerendered)
GLOBALS
.ui_people_to_invalidate
.write()
.push(pubkeyhex.to_owned());
GLOBALS.ui_people_to_invalidate.write().push(*pubkey);
}
// Remove from failed avatars list so the UI will try to fetch the avatar again if missing
GLOBALS.failed_avatars.write().await.remove(pubkeyhex);
GLOBALS.failed_avatars.write().await.remove(pubkey);
// Only if they have a nip05 dns id set
if matches!(
@ -454,8 +449,8 @@ impl People {
// Recheck nip05 every day if invalid, and every two weeks if valid
let recheck = {
if self.recheck_nip05.contains(pubkeyhex) {
self.recheck_nip05.remove(pubkeyhex);
if self.recheck_nip05.contains(pubkey) {
self.recheck_nip05.remove(pubkey);
true
} else if let Some(last) = person.nip05_last_checked {
// FIXME make these settings
@ -471,8 +466,7 @@ impl People {
};
if recheck {
self.update_nip05_last_checked(person.pubkey.clone())
.await?;
self.update_nip05_last_checked(person.pubkey).await?;
task::spawn(async move {
if let Err(e) = crate::nip05::validate_nip05(person).await {
tracing::error!("{}", e);
@ -521,7 +515,7 @@ impl People {
};
let pk: String = row.get(0)?;
output.push(Person {
pubkey: PublicKeyHex::try_from_string(pk)?,
pubkey: PublicKey::try_from_hex_string(&pk)?,
petname: row.get(1)?,
followed: row.get(2)?,
followed_last_updated: row.get(3)?,
@ -541,25 +535,25 @@ impl People {
.await?;
for person in output? {
self.people.insert(person.pubkey.clone(), person);
self.people.insert(person.pubkey, person);
}
Ok(())
}
// Get from our memory map. If missing, eventually load from the database
pub fn get(&self, pubkeyhex: &PublicKeyHex) -> Option<Person> {
if self.people.contains_key(pubkeyhex) {
self.people.get(pubkeyhex).map(|o| o.value().to_owned())
pub fn get(&self, pubkey: &PublicKey) -> Option<Person> {
if self.people.contains_key(pubkey) {
self.people.get(pubkey).map(|o| o.value().to_owned())
} else {
// We can't get it now, but we can setup a task to do it soon
let pubkeyhex = pubkeyhex.to_owned();
let pubkey = pubkey.to_owned();
tokio::spawn(async move {
#[allow(clippy::map_entry)]
if !GLOBALS.people.people.contains_key(&pubkeyhex) {
match People::fetch_one(&pubkeyhex).await {
if !GLOBALS.people.people.contains_key(&pubkey) {
match People::fetch_one(&pubkey).await {
Ok(Some(person)) => {
let _ = GLOBALS.people.people.insert(pubkeyhex, person);
let _ = GLOBALS.people.people.insert(pubkey, person);
}
Err(e) => tracing::error!("{}", e),
_ => {}
@ -578,7 +572,7 @@ impl People {
.map(|s| s.to_lowercase())
.cmp(&b.display_name().map(|s| s.to_lowercase()));
if c == std::cmp::Ordering::Equal {
a.pubkey.cmp(&b.pubkey)
a.pubkey.as_hex_string().cmp(&b.pubkey.as_hex_string())
} else {
c
}
@ -586,19 +580,19 @@ impl People {
v
}
pub fn get_avatar(&self, pubkeyhex: &PublicKeyHex) -> Option<ColorImage> {
pub fn get_avatar(&self, pubkey: &PublicKey) -> Option<ColorImage> {
// If we have it, hand it over (we won't need a copy anymore)
if let Some(th) = self.avatars_temp.remove(pubkeyhex) {
if let Some(th) = self.avatars_temp.remove(pubkey) {
return Some(th.1);
}
// If it failed before, error out now
if GLOBALS.failed_avatars.blocking_read().contains(pubkeyhex) {
if GLOBALS.failed_avatars.blocking_read().contains(pubkey) {
return None; // cannot recover.
}
// If it is pending processing, respond now
if self.avatars_pending_processing.contains(pubkeyhex) {
if self.avatars_pending_processing.contains(pubkey) {
return None; // will recover after processing completes
}
@ -608,7 +602,7 @@ impl People {
}
// Get the person this is about
let person = match self.people.get(pubkeyhex) {
let person = match self.people.get(pubkey) {
Some(person) => person,
None => {
return None; // can recover once the person is loaded
@ -618,10 +612,7 @@ impl People {
// Fail permanently if they don't have a picture url
if person.picture().is_none() {
// this cannot recover without new metadata
GLOBALS
.failed_avatars
.blocking_write()
.insert(pubkeyhex.to_owned());
GLOBALS.failed_avatars.blocking_write().insert(*pubkey);
return None;
}
@ -632,10 +623,7 @@ impl People {
Ok(url) => url,
Err(_) => {
// this cannot recover without new metadata
GLOBALS
.failed_avatars
.blocking_write()
.insert(pubkeyhex.to_owned());
GLOBALS.failed_avatars.blocking_write().insert(*pubkey);
return None;
}
@ -649,7 +637,7 @@ impl People {
Ok(None) => None,
Ok(Some(bytes)) => {
// Finish this later (spawn)
let apubkeyhex = pubkeyhex.to_owned();
let apubkey = *pubkey;
tokio::spawn(async move {
let size = AVATAR_SIZE * 3 // 3x feed size, 1x people page size
* GLOBALS
@ -691,7 +679,7 @@ impl People {
if GLOBALS.settings.read().theme.round_image() {
round_image(&mut color_image);
}
GLOBALS.people.avatars_temp.insert(apubkeyhex, color_image);
GLOBALS.people.avatars_temp.insert(apubkey, color_image);
} else if let Ok(mut color_image) = egui_extras::image::load_svg_bytes_with_size(
&bytes,
FitTo::Size(size, size),
@ -699,26 +687,19 @@ impl People {
if GLOBALS.settings.read().theme.round_image() {
round_image(&mut color_image);
}
GLOBALS.people.avatars_temp.insert(apubkeyhex, color_image);
GLOBALS.people.avatars_temp.insert(apubkey, color_image);
} else {
// this cannot recover without new metadata
GLOBALS
.failed_avatars
.write()
.await
.insert(apubkeyhex.to_owned());
GLOBALS.failed_avatars.write().await.insert(apubkey);
};
});
self.avatars_pending_processing.insert(pubkeyhex.to_owned());
self.avatars_pending_processing.insert(pubkey.to_owned());
None
}
Err(e) => {
tracing::error!("{}", e);
// this cannot recover without new metadata
GLOBALS
.failed_avatars
.blocking_write()
.insert(pubkeyhex.to_owned());
GLOBALS.failed_avatars.blocking_write().insert(*pubkey);
None
}
}
@ -735,7 +716,7 @@ impl People {
let search = String::from(text).to_lowercase();
// grab all results then sort by score
let mut results: Vec<(u16, String, PublicKeyHex)> = self
let mut results: Vec<(u16, String, PublicKey)> = self
.people
.iter()
.filter_map(|person| {
@ -773,13 +754,13 @@ impl People {
// if there is not a name, fallback to showing the initial chars of the pubkey,
// but this is probably unnecessary and will never happen
if result_name.is_empty() {
result_name = person.pubkey.to_string();
result_name = person.pubkey.as_hex_string();
}
// bigger names have a higher match chance, but they should be scored lower
score -= result_name.len() as u16;
return Some((score, result_name, person.pubkey.clone()));
return Some((score, result_name, person.pubkey));
}
None
@ -794,12 +775,7 @@ impl People {
};
results[0..max]
.iter()
.map(|r| {
(
r.1.to_owned(),
PublicKey::try_from_hex_string(&r.2).unwrap(),
)
})
.map(|r| (r.1.to_owned(), r.2.to_owned()))
.collect()
}
@ -823,10 +799,10 @@ impl People {
let pubkeys = self.get_followed_pubkeys();
for pubkey in &pubkeys {
// Get their best relay
let relays = PersonRelay::get_best_relays(pubkey.clone(), Direction::Write).await?;
let relays = PersonRelay::get_best_relays((*pubkey).into(), Direction::Write).await?;
let maybeurl = relays.get(0);
p_tags.push(Tag::Pubkey {
pubkey: pubkey.clone(),
pubkey: (*pubkey).into(),
recommended_relay_url: maybeurl.map(|(u, _)| u.to_unchecked_url()),
petname: None,
trailing: Vec::new(),
@ -862,19 +838,19 @@ impl People {
GLOBALS.signer.sign_preevent(pre_event, None, None)
}
pub fn follow(&self, pubkeyhex: &PublicKeyHex, follow: bool) {
pub fn follow(&self, pubkey: &PublicKey, follow: bool) {
// We can't do it now, but we spawn a task to do it soon
let pubkeyhex = pubkeyhex.to_owned();
let pubkey = pubkey.to_owned();
tokio::spawn(async move {
if let Err(e) = GLOBALS.people.async_follow(&pubkeyhex, follow).await {
if let Err(e) = GLOBALS.people.async_follow(&pubkey, follow).await {
tracing::error!("{}", e);
}
});
}
pub async fn async_follow(&self, pubkeyhex: &PublicKeyHex, follow: bool) -> Result<(), Error> {
pub async fn async_follow(&self, pubkey: &PublicKey, follow: bool) -> Result<(), Error> {
// Skip if they are already followed (or already not followed)
let already_followed = self.get_followed_pubkeys().contains(pubkeyhex);
let already_followed = self.get_followed_pubkeys().contains(pubkey);
if follow == already_followed {
return Ok(());
}
@ -884,22 +860,22 @@ impl People {
// Follow in database
let sql = "INSERT INTO PERSON (pubkey, followed) values (?, ?) \
ON CONFLICT(pubkey) DO UPDATE SET followed=?";
let pubkeyhex2 = pubkeyhex.to_owned();
let pubkeyhexstr = pubkey.as_hex_string();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
let mut stmt = db.prepare(sql)?;
stmt.execute((pubkeyhex2.as_str(), &follow, &follow))?;
stmt.execute((pubkeyhexstr, &follow, &follow))?;
Ok::<(), Error>(())
})
.await??;
// Make sure memory matches
if let Some(mut dbperson) = self.people.get_mut(pubkeyhex) {
if let Some(mut dbperson) = self.people.get_mut(pubkey) {
dbperson.followed = follow;
} else {
// load
if let Some(person) = Self::fetch_one(pubkeyhex).await? {
self.people.insert(pubkeyhex.to_owned(), person);
if let Some(person) = Self::fetch_one(pubkey).await? {
self.people.insert(pubkey.to_owned(), person);
}
}
@ -907,13 +883,13 @@ impl People {
GLOBALS
.ui_people_to_invalidate
.write()
.push(pubkeyhex.to_owned());
.push(pubkey.to_owned());
if follow > 0 {
// Add the person to the relay_picker for picking
GLOBALS.relay_picker.add_someone(pubkeyhex.to_owned())?;
GLOBALS.relay_picker.add_someone(pubkey.to_owned())?;
} else {
GLOBALS.relay_picker.remove_someone(pubkeyhex.to_owned());
GLOBALS.relay_picker.remove_someone(pubkey.to_owned());
}
// Update last_contact_list_edit
@ -923,7 +899,7 @@ impl People {
Ok(())
}
pub async fn follow_all(&self, pubkeys: &[PublicKeyHex], merge: bool) -> Result<(), Error> {
pub async fn follow_all(&self, pubkeys: &[PublicKey], merge: bool) -> Result<(), Error> {
// If merging, and we already follow all these keys,
// then just bail out
if merge {
@ -956,7 +932,8 @@ impl People {
repeat_vars(pubkeys.len())
);
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.to_string()).collect();
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.as_hex_string()).collect();
let pubkey_strings2 = pubkey_strings.clone();
let now = Unixtime::now().unwrap();
@ -982,14 +959,12 @@ impl People {
repeat_vars(pubkeys.len())
);
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.to_string()).collect();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
let mut stmt = db.prepare(&sql)?;
stmt.raw_bind_parameter(1, now.0)?;
let mut pos = 2;
for pk in pubkey_strings.iter() {
for pk in pubkey_strings2.iter() {
stmt.raw_bind_parameter(pos, pk)?;
pos += 1;
}
@ -1001,9 +976,9 @@ impl People {
// Make sure memory matches
for mut elem in self.people.iter_mut() {
let pkh = elem.key().clone();
let pk = *elem.key();
let person = elem.value_mut();
if pubkeys.contains(&pkh) {
if pubkeys.contains(&pk) {
person.followed = 1;
} else if !merge {
person.followed = 0;
@ -1038,38 +1013,37 @@ impl People {
Ok(())
}
pub fn mute(&self, pubkeyhex: &PublicKeyHex, mute: bool) {
pub fn mute(&self, pubkey: PublicKey, mute: bool) {
// We can't do it now, but we spawn a task to do it soon
let pubkeyhex = pubkeyhex.to_owned();
tokio::spawn(async move {
if let Err(e) = GLOBALS.people.async_mute(&pubkeyhex, mute).await {
if let Err(e) = GLOBALS.people.async_mute(&pubkey, mute).await {
tracing::error!("{}", e);
}
});
}
pub async fn async_mute(&self, pubkeyhex: &PublicKeyHex, mute: bool) -> Result<(), Error> {
pub async fn async_mute(&self, pubkey: &PublicKey, mute: bool) -> Result<(), Error> {
let mute: u8 = u8::from(mute);
// Mute in database
let sql = "INSERT INTO PERSON (pubkey, muted) values (?, ?) \
ON CONFLICT(pubkey) DO UPDATE SET muted=?";
let pubkeyhex2 = pubkeyhex.to_owned();
let pubkeyhexstr = pubkey.as_hex_string();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
let mut stmt = db.prepare(sql)?;
stmt.execute((pubkeyhex2.as_str(), &mute, &mute))?;
stmt.execute((pubkeyhexstr, &mute, &mute))?;
Ok::<(), Error>(())
})
.await??;
// Make sure memory matches
if let Some(mut dbperson) = self.people.get_mut(pubkeyhex) {
if let Some(mut dbperson) = self.people.get_mut(pubkey) {
dbperson.muted = mute;
} else {
// load
if let Some(person) = Self::fetch_one(pubkeyhex).await? {
self.people.insert(pubkeyhex.to_owned(), person);
if let Some(person) = Self::fetch_one(pubkey).await? {
self.people.insert(pubkey.to_owned(), person);
}
}
@ -1077,7 +1051,7 @@ impl People {
GLOBALS
.ui_people_to_invalidate
.write()
.push(pubkeyhex.to_owned());
.push(pubkey.to_owned());
Ok(())
}
@ -1085,14 +1059,14 @@ impl People {
// Returns true if the date passed in is newer than what we already had
pub async fn update_relay_list_stamps(
&self,
pubkeyhex: PublicKeyHex,
pubkey: PublicKey,
mut created_at: i64,
) -> Result<bool, Error> {
let now = Unixtime::now().unwrap().0;
let mut retval = false;
if let Some(mut person) = self.people.get_mut(&pubkeyhex) {
if let Some(mut person) = self.people.get_mut(&pubkey) {
person.relay_list_last_received = now;
if let Some(old_at) = person.relay_list_created_at {
@ -1116,7 +1090,7 @@ impl People {
"UPDATE person SET relay_list_last_received=?, \
relay_list_created_at=? WHERE pubkey=?",
)?;
stmt.execute((&now, &created_at, pubkeyhex.as_str()))?;
stmt.execute((&now, &created_at, pubkey.as_hex_string()))?;
Ok::<(), Error>(())
})
.await??;
@ -1124,17 +1098,17 @@ impl People {
Ok(retval)
}
pub async fn update_nip05_last_checked(&self, pubkeyhex: PublicKeyHex) -> Result<(), Error> {
pub async fn update_nip05_last_checked(&self, pubkey: PublicKey) -> Result<(), Error> {
let now = Unixtime::now().unwrap().0;
if let Some(mut person) = self.people.get_mut(&pubkeyhex) {
if let Some(mut person) = self.people.get_mut(&pubkey) {
person.nip05_last_checked = Some(now as u64);
}
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
let mut stmt = db.prepare("UPDATE person SET nip05_last_checked=? WHERE pubkey=?")?;
stmt.execute((&now, pubkeyhex.as_str()))?;
stmt.execute((&now, pubkey.as_hex_string()))?;
Ok(())
})
.await?
@ -1142,13 +1116,13 @@ impl People {
pub async fn upsert_nip05_validity(
&self,
pubkeyhex: &PublicKeyHex,
pubkey: &PublicKey,
nip05: Option<String>,
nip05_valid: bool,
nip05_last_checked: u64,
) -> Result<(), Error> {
// Update memory
if let Some(mut dbperson) = self.people.get_mut(pubkeyhex) {
if let Some(mut dbperson) = self.people.get_mut(pubkey) {
if let Some(metadata) = &mut dbperson.metadata {
metadata.nip05 = nip05.clone()
} else {
@ -1166,7 +1140,7 @@ impl People {
ON CONFLICT(pubkey) DO \
UPDATE SET metadata=json_patch(metadata, ?), nip05_valid=?, nip05_last_checked=?";
let pubkeyhex2 = pubkeyhex.to_owned();
let pubkey2 = pubkey.to_owned();
task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
let mut metadata = Metadata::new();
@ -1177,7 +1151,7 @@ impl People {
let mut stmt = db.prepare(sql)?;
stmt.execute((
pubkeyhex2.as_str(),
pubkey2.as_hex_string(),
&metadata_json,
&nip05_valid,
&nip05_last_checked,
@ -1193,7 +1167,7 @@ impl People {
GLOBALS
.ui_people_to_invalidate
.write()
.push(pubkeyhex.to_owned());
.push(pubkey.to_owned());
Ok(())
}
@ -1224,7 +1198,7 @@ impl People {
};
let pk: String = row.get(0)?;
output.push(Person {
pubkey: PublicKeyHex::try_from_string(pk)?,
pubkey: PublicKey::try_from_hex_string(&pk)?,
petname: row.get(1)?,
followed: row.get(2)?,
followed_last_updated: row.get(3)?,
@ -1246,8 +1220,8 @@ impl People {
output
}
async fn fetch_one(pubkeyhex: &PublicKeyHex) -> Result<Option<Person>, Error> {
let people = Self::fetch(Some(&format!("pubkey='{}'", pubkeyhex))).await?;
async fn fetch_one(pubkey: &PublicKey) -> Result<Option<Person>, Error> {
let people = Self::fetch(Some(&format!("pubkey='{}'", pubkey.as_hex_string()))).await?;
if people.is_empty() {
Ok(None)
@ -1256,7 +1230,7 @@ impl People {
}
}
async fn fetch_many(pubkeys: &[&PublicKeyHex]) -> Result<Vec<Person>, Error> {
async fn fetch_many(pubkeys: &[&PublicKey]) -> Result<Vec<Person>, Error> {
let sql = format!(
"SELECT pubkey, petname, \
followed, followed_last_updated, muted, \
@ -1267,7 +1241,7 @@ impl People {
repeat_vars(pubkeys.len())
);
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.to_string()).collect();
let pubkey_strings: Vec<String> = pubkeys.iter().map(|p| p.as_hex_string()).collect();
let output: Result<Vec<Person>, Error> = task::spawn_blocking(move || {
let db = GLOBALS.db.blocking_lock();
@ -1288,7 +1262,7 @@ impl People {
};
let pk: String = row.get(0)?;
people.push(Person {
pubkey: PublicKeyHex::try_from_string(pk)?,
pubkey: PublicKey::try_from_hex_string(&pk)?,
petname: row.get(1)?,
followed: row.get(2)?,
followed_last_updated: row.get(3)?,
@ -1318,19 +1292,19 @@ impl People {
}
*/
pub async fn set_active_person(&self, pubkey: PublicKeyHex) -> Result<(), Error> {
pub async fn set_active_person(&self, pubkey: PublicKey) -> Result<(), Error> {
// Set the active person
*self.active_person.write().await = Some(pubkey.clone());
*self.active_person.write().await = Some(pubkey);
// Load their relays
let best_relays = PersonRelay::get_best_relays(pubkey, Direction::Write).await?;
let best_relays = PersonRelay::get_best_relays(pubkey.into(), Direction::Write).await?;
*self.active_persons_write_relays.write().await = best_relays;
Ok(())
}
pub fn get_active_person(&self) -> Option<PublicKeyHex> {
self.active_person.blocking_read().clone()
pub fn get_active_person(&self) -> Option<PublicKey> {
*self.active_person.blocking_read()
}
pub fn get_active_person_write_relays(&self) -> Vec<(RelayUrl, u64)> {

View File

@ -1,9 +1,9 @@
use crate::comms::ToOverlordMessage;
use crate::db::{PersonRelay, DbRelay};
use crate::db::{DbRelay, PersonRelay};
use crate::error::Error;
use crate::globals::GLOBALS;
use nostr_types::{
Event, EventKind, Metadata, NostrBech32, RelayUrl, SimpleRelayList, Tag, Unixtime,
Event, EventKind, Metadata, NostrBech32, PublicKey, RelayUrl, SimpleRelayList, Tag, Unixtime,
};
use std::sync::atomic::Ordering;
@ -83,7 +83,7 @@ pub async fn process_new_event(
// Create the person if missing in the database
GLOBALS
.people
.create_all_if_missing(&[event.pubkey.into()])
.create_all_if_missing(&[event.pubkey])
.await?;
if let Some(ref url) = seen_on {
@ -114,22 +114,21 @@ pub async fn process_new_event(
recommended_relay_url: Some(should_be_url),
..
} => {
if let Ok(url) = RelayUrl::try_from_unchecked_url(should_be_url) {
GLOBALS.storage.write_relay_if_missing(&url)?;
if let Ok(pubkey) = PublicKey::try_from_hex_string(pubkey) {
if let Ok(url) = RelayUrl::try_from_unchecked_url(should_be_url) {
GLOBALS.storage.write_relay_if_missing(&url)?;
// Add person if missing
GLOBALS
.people
.create_all_if_missing(&[pubkey.clone()])
// Add person if missing
GLOBALS.people.create_all_if_missing(&[pubkey]).await?;
// upsert person_relay.last_suggested_bytag
PersonRelay::upsert_last_suggested_bytag(
pubkey.as_hex_string(),
url,
now.0 as u64,
)
.await?;
// upsert person_relay.last_suggested_bytag
PersonRelay::upsert_last_suggested_bytag(
pubkey.to_string(),
url,
now.0 as u64,
)
.await?;
}
}
}
_ => {}
@ -138,7 +137,7 @@ pub async fn process_new_event(
}
// Save event relationships (whether from a relay or not)
let invalid_ids = GLOBALS.storage.process_relationships_of_event(&event)?;
let invalid_ids = GLOBALS.storage.process_relationships_of_event(event)?;
// Invalidate UI events indicated by those relationships
GLOBALS.ui_notes_to_invalidate.write().extend(&invalid_ids);
@ -157,7 +156,7 @@ pub async fn process_new_event(
GLOBALS
.people
.update_metadata(&event.pubkey.into(), metadata, event.created_at)
.update_metadata(&event.pubkey, metadata, event.created_at)
.await?;
}
@ -235,7 +234,7 @@ async fn process_relay_list(event: &Event) -> Result<(), Error> {
// if this relay list happens to be newer)
let newer = GLOBALS
.people
.update_relay_list_stamps(event.pubkey.into(), event.created_at.0)
.update_relay_list_stamps(event.pubkey, event.created_at.0)
.await?;
if !newer {
@ -339,7 +338,7 @@ async fn process_somebody_elses_contact_list(event: &Event) -> Result<(), Error>
// if this relay list happens to be newer)
let newer = GLOBALS
.people
.update_relay_list_stamps(event.pubkey.into(), event.created_at.0)
.update_relay_list_stamps(event.pubkey, event.created_at.0)
.await?;
if !newer {

View File

@ -3,7 +3,7 @@ use crate::error::Error;
use crate::globals::GLOBALS;
use async_trait::async_trait;
use gossip_relay_picker::{Direction, RelayPickerHooks};
use nostr_types::{PublicKeyHex, RelayUrl};
use nostr_types::{PublicKey, RelayUrl};
#[derive(Default)]
pub struct Hooks {}
@ -23,10 +23,10 @@ impl RelayPickerHooks for Hooks {
/// Returns all relays that this public key uses in the given Direction
async fn get_relays_for_pubkey(
&self,
pubkey: PublicKeyHex,
pubkey: PublicKey,
direction: Direction,
) -> Result<Vec<(RelayUrl, u64)>, Error> {
PersonRelay::get_best_relays(pubkey, direction).await
PersonRelay::get_best_relays(pubkey.into(), direction).await
}
/// Is the relay currently connected?
@ -46,7 +46,7 @@ impl RelayPickerHooks for Hooks {
}
/// Returns the public keys of all the people followed
fn get_followed_pubkeys(&self) -> Vec<PublicKeyHex> {
fn get_followed_pubkeys(&self) -> Vec<PublicKey> {
GLOBALS.people.get_followed_pubkeys()
}

View File

@ -12,7 +12,8 @@ impl Storage {
return Err(ErrorKind::General(format!(
"Migration level {} unknown: This client is older than your data.",
level
)).into());
))
.into());
}
while level < Self::MIGRATION_LEVEL {

View File

@ -831,7 +831,6 @@ impl Storage {
// This returns IDs that should be UI invalidated
pub fn process_relationships_of_event(&self, event: &Event) -> Result<Vec<Id>, Error> {
let mut invalidate: Vec<Id> = Vec::new();
// replies to
@ -841,11 +840,7 @@ impl Storage {
// reacts to
if let Some((id, reaction, _maybe_url)) = event.reacts_to() {
self.write_relationship(
id,
event.id,
Relationship::Reaction(event.pubkey, reaction),
)?;
self.write_relationship(id, event.id, Relationship::Reaction(event.pubkey, reaction))?;
invalidate.push(id);
}
@ -857,11 +852,7 @@ impl Storage {
for id in ids {
// since it is a delete, we don't actually desire the event.
self.write_relationship(
id,
event.id,
Relationship::Deletion(reason.clone()),
)?;
self.write_relationship(id, event.id, Relationship::Deletion(reason.clone()))?;
}
}

View File

@ -137,13 +137,13 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
render_a_feed(app, ctx, frame, ui, vec![parent], true, &id.as_hex_string());
}
}
FeedKind::Person(pubkeyhex) => {
FeedKind::Person(pubkey) => {
ui.horizontal(|ui| {
recompute_btn(app, ui);
});
let feed = GLOBALS.feed.get_person_feed();
render_a_feed(app, ctx, frame, ui, feed, false, pubkeyhex.as_str());
render_a_feed(app, ctx, frame, ui, feed, false, &pubkey.as_hex_string());
}
}

View File

@ -7,7 +7,7 @@ use eframe::{
epaint::Vec2,
};
use egui::{RichText, Ui};
use nostr_types::{ContentSegment, Id, IdHex, NostrBech32, PublicKeyHex, Span, Tag, Url};
use nostr_types::{ContentSegment, Id, IdHex, NostrBech32, PublicKey, Span, Tag, Url};
use std::{
cell::{Ref, RefCell},
rc::Rc,
@ -95,10 +95,10 @@ pub(super) fn render_content(
}
}
NostrBech32::Profile(prof) => {
render_profile_link(app, ui, &prof.pubkey.into());
render_profile_link(app, ui, &prof.pubkey);
}
NostrBech32::Pubkey(pk) => {
render_profile_link(app, ui, &(*pk).into());
NostrBech32::Pubkey(pubkey) => {
render_profile_link(app, ui, pubkey);
}
NostrBech32::Relay(url) => {
ui.label(RichText::new(&url.0).underline());
@ -109,7 +109,10 @@ pub(super) fn render_content(
if let Some(tag) = note.event.tags.get(*num) {
match tag {
Tag::Pubkey { pubkey, .. } => {
render_profile_link(app, ui, pubkey);
if let Ok(pubkey) = PublicKey::try_from_hex_string(pubkey.as_str())
{
render_profile_link(app, ui, &pubkey);
}
}
Tag::Event { id, .. } => {
let mut render_link = true;
@ -192,8 +195,8 @@ pub(super) fn render_plain(ui: &mut Ui, note: &Ref<NoteData>, textspan: &Span, a
}
}
pub(super) fn render_profile_link(app: &mut GossipUi, ui: &mut Ui, pubkey: &PublicKeyHex) {
let nam = GossipUi::display_name_from_pubkeyhex_lookup(pubkey);
pub(super) fn render_profile_link(app: &mut GossipUi, ui: &mut Ui, pubkey: &PublicKey) {
let nam = GossipUi::display_name_from_pubkey_lookup(pubkey);
let nam = format!("@{}", nam);
if ui.link(&nam).clicked() {
app.set_page(Page::Person(pubkey.to_owned()));

View File

@ -273,7 +273,7 @@ fn render_note_inner(
)
.clicked()
{
app.set_page(Page::Person(note.author.pubkey.clone()));
app.set_page(Page::Person(note.author.pubkey));
};
ui.add_space(avatar_margin_left);
@ -293,7 +293,7 @@ fn render_note_inner(
app.set_page(Page::Feed(FeedKind::Thread {
id: irt,
referenced_by: note.event.id,
author: Some(note.event.pubkey.into()),
author: Some(note.event.pubkey),
}));
};
ui.reset_style();
@ -343,7 +343,7 @@ fn render_note_inner(
app.set_page(Page::Feed(FeedKind::Thread {
id: note.event.id,
referenced_by: note.event.id,
author: Some(note.event.pubkey.into()),
author: Some(note.event.pubkey),
}));
}
}
@ -431,7 +431,7 @@ fn render_note_inner(
app.set_page(Page::Feed(FeedKind::Thread {
id: note.event.id,
referenced_by: note.event.id,
author: Some(note.event.pubkey.into()),
author: Some(note.event.pubkey),
}));
}
}

View File

@ -1,6 +1,6 @@
use crate::{globals::GLOBALS, people::Person};
use nostr_types::{
ContentSegment, Event, EventDelegation, EventKind, Id, MilliSatoshi, NostrBech32, PublicKeyHex,
ContentSegment, Event, EventDelegation, EventKind, Id, MilliSatoshi, NostrBech32, PublicKey,
ShatteredContent, Tag,
};
@ -154,10 +154,10 @@ impl NoteData {
};
// If delegated, use the delegated person
let author_pubkey: PublicKeyHex = if let EventDelegation::DelegatedBy(pubkey) = delegation {
pubkey.into()
let author_pubkey: PublicKey = if let EventDelegation::DelegatedBy(pubkey) = delegation {
pubkey
} else {
event.pubkey.into()
event.pubkey
};
let author = match GLOBALS.people.get(&author_pubkey) {

View File

@ -1,6 +1,6 @@
use super::notedata::NoteData;
use crate::globals::GLOBALS;
use nostr_types::{Id, PublicKeyHex};
use nostr_types::{Id, PublicKey};
use std::{cell::RefCell, collections::HashMap, rc::Rc};
/// a 'note' is a processed event
@ -29,7 +29,7 @@ impl Notes {
}
/// Drop all NoteData for a given person
pub(in crate::ui) fn cache_invalidate_person(&mut self, pubkey: &PublicKeyHex) {
pub(in crate::ui) fn cache_invalidate_person(&mut self, pubkey: &PublicKey) {
self.notes
.retain(|_, note| note.borrow().author.pubkey != *pubkey);
}

View File

@ -322,7 +322,7 @@ fn real_posting_area(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
NostrBech32::Profile(prof) => &prof.pubkey,
_ => continue,
};
let rendered = if let Some(person) = GLOBALS.people.get(&pk.as_hex_string().into()) {
let rendered = if let Some(person) = GLOBALS.people.get(pk) {
match person.name() {
Some(name) => name.to_owned(),
None => format!("{}", bech32),

View File

@ -42,7 +42,7 @@ use egui::{
#[cfg(feature = "video-ffmpeg")]
use egui_video::{AudioDevice, Player};
use egui_winit::egui::Response;
use nostr_types::{Id, IdHex, Metadata, MilliSatoshi, PublicKey, PublicKeyHex, UncheckedUrl, Url};
use nostr_types::{Id, IdHex, Metadata, MilliSatoshi, PublicKey, UncheckedUrl, Url};
use std::collections::{HashMap, HashSet};
#[cfg(feature = "video-ffmpeg")]
use std::rc::Rc;
@ -98,7 +98,7 @@ enum Page {
PeopleList,
PeopleFollow,
PeopleMuted,
Person(PublicKeyHex),
Person(PublicKey),
YourKeys,
YourMetadata,
YourDelegation,
@ -200,7 +200,7 @@ struct GossipUi {
icon: TextureHandle,
placeholder_avatar: TextureHandle,
settings: Settings,
avatars: HashMap<PublicKeyHex, TextureHandle>,
avatars: HashMap<PublicKey, TextureHandle>,
images: HashMap<Url, TextureHandle>,
/// used when settings.show_media=false to explicitly show
media_show_list: HashSet<Url>,
@ -500,7 +500,7 @@ impl GossipUi {
}) => {
GLOBALS
.feed
.set_feed_to_thread(*id, *referenced_by, vec![], author.clone());
.set_feed_to_thread(*id, *referenced_by, vec![], *author);
}
Page::Feed(FeedKind::Person(pubkey)) => {
GLOBALS.feed.set_feed_to_person(pubkey.to_owned());
@ -626,15 +626,14 @@ impl eframe::App for GossipUi {
)));
}
if let Some(pubkey) = GLOBALS.signer.public_key() {
let pubkeyhex: PublicKeyHex = pubkey.into();
if self.add_selected_label(
ui,
matches!(&self.page, Page::Feed(FeedKind::Person(key)) if key.as_str() == pubkeyhex.as_str()),
matches!(&self.page, Page::Feed(FeedKind::Person(key)) if *key == pubkey),
"My Notes",
)
.clicked()
{
self.set_page(Page::Feed(FeedKind::Person(pubkeyhex)));
self.set_page(Page::Feed(FeedKind::Person(pubkey)));
}
}
if self.add_selected_label(
@ -868,28 +867,15 @@ impl GossipUi {
/// A short rendering of a `PublicKey`
pub fn pubkey_short(pk: &PublicKey) -> String {
let npub = pk.as_bech32_string();
format!("{}", &npub.get(0..20).unwrap_or("????????????????????"))
}
/// A short rendering of a `PublicKeyHex`
pub fn pubkeyhex_short(pubkeyhex: &PublicKeyHex) -> String {
format!(
"{}_{}...{}_{}",
&pubkeyhex.as_str()[0..4],
&pubkeyhex.as_str()[4..8],
&pubkeyhex.as_str()[56..60],
&pubkeyhex.as_str()[60..64],
&npub.get(0..4).unwrap_or("????"),
&npub.get(4..8).unwrap_or("????"),
&npub.get(56..60).unwrap_or("????"),
&npub.get(60..64).unwrap_or("????")
)
}
/// A short rendering of a `PublicKeyHex`, with attempt to convert to bech32
pub fn pubkeyhex_convert_short(pubkeyhex: &PublicKeyHex) -> String {
match PublicKey::try_from_hex_string(pubkeyhex) {
Ok(pk) => Self::pubkey_short(&pk),
Err(_) => GossipUi::pubkeyhex_short(pubkeyhex),
}
}
pub fn hex_id_short(idhex: &IdHex) -> String {
idhex.as_str()[0..8].to_string()
}
@ -898,22 +884,21 @@ impl GossipUi {
pub fn display_name_from_dbperson(dbperson: &Person) -> String {
match dbperson.display_name() {
Some(name) => name.to_owned(),
None => Self::pubkeyhex_convert_short(&dbperson.pubkey),
None => Self::pubkey_short(&dbperson.pubkey),
}
}
/// A display name for a `PublicKeyHex`, via trying to lookup the person
pub fn display_name_from_pubkeyhex_lookup(pkh: &PublicKeyHex) -> String {
match GLOBALS.people.get(pkh) {
pub fn display_name_from_pubkey_lookup(pubkey: &PublicKey) -> String {
match GLOBALS.people.get(pubkey) {
Some(dbperson) => Self::display_name_from_dbperson(&dbperson),
None => Self::pubkeyhex_convert_short(pkh),
None => Self::pubkey_short(pubkey),
}
}
pub fn render_person_name_line(app: &mut GossipUi, ui: &mut Ui, person: &Person) {
// Let the 'People' manager know that we are interested in displaying this person.
// It will take all actions necessary to make the data eventually available.
GLOBALS.people.person_of_interest(person.pubkey.clone());
GLOBALS.people.person_of_interest(person.pubkey);
ui.horizontal_wrapped(|ui| {
let name = GossipUi::display_name_from_dbperson(person);
@ -921,7 +906,7 @@ impl GossipUi {
ui.menu_button(&name, |ui| {
let mute_label = if person.muted == 1 { "Unmute" } else { "Mute" };
if ui.button(mute_label).clicked() {
GLOBALS.people.mute(&person.pubkey, person.muted == 0);
GLOBALS.people.mute(person.pubkey, person.muted == 0);
app.notes.cache_invalidate_person(&person.pubkey);
}
if person.followed == 0 && ui.button("Follow").clicked() {
@ -932,10 +917,10 @@ impl GossipUi {
if ui.button("Update Metadata").clicked() {
let _ = GLOBALS
.to_overlord
.send(ToOverlordMessage::UpdateMetadata(person.pubkey.clone()));
.send(ToOverlordMessage::UpdateMetadata(person.pubkey));
}
if ui.button("View Their Posts").clicked() {
app.set_page(Page::Feed(FeedKind::Person(person.pubkey.clone())));
app.set_page(Page::Feed(FeedKind::Person(person.pubkey)));
}
});
@ -966,28 +951,24 @@ impl GossipUi {
});
}
pub fn try_get_avatar(
&mut self,
ctx: &Context,
pubkeyhex: &PublicKeyHex,
) -> Option<TextureHandle> {
pub fn try_get_avatar(&mut self, ctx: &Context, pubkey: &PublicKey) -> Option<TextureHandle> {
// Do not keep retrying if failed
if GLOBALS.failed_avatars.blocking_read().contains(pubkeyhex) {
if GLOBALS.failed_avatars.blocking_read().contains(pubkey) {
return None;
}
if let Some(th) = self.avatars.get(pubkeyhex) {
if let Some(th) = self.avatars.get(pubkey) {
return Some(th.to_owned());
}
if let Some(color_image) = GLOBALS.people.get_avatar(pubkeyhex) {
if let Some(color_image) = GLOBALS.people.get_avatar(pubkey) {
let texture_handle = ctx.load_texture(
pubkeyhex.to_string(),
pubkey.as_hex_string(),
color_image,
TextureOptions::default(),
);
self.avatars
.insert(pubkeyhex.to_owned(), texture_handle.clone());
.insert(pubkey.to_owned(), texture_handle.clone());
Some(texture_handle)
} else {
None

View File

@ -175,13 +175,11 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
.add(Image::new(&avatar, Vec2 { x: size, y: size }).sense(Sense::click()))
.clicked()
{
app.set_page(Page::Person(person.pubkey.clone()));
app.set_page(Page::Person(person.pubkey));
};
ui.vertical(|ui| {
ui.label(
RichText::new(GossipUi::pubkeyhex_convert_short(&person.pubkey)).weak(),
);
ui.label(RichText::new(GossipUi::pubkey_short(&person.pubkey)).weak());
GossipUi::render_person_name_line(app, ui, person);
});
});

View File

@ -44,17 +44,15 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
.add(Image::new(&avatar, Vec2 { x: size, y: size }).sense(Sense::click()))
.clicked()
{
app.set_page(Page::Person(person.pubkey.clone()));
app.set_page(Page::Person(person.pubkey));
};
ui.vertical(|ui| {
ui.label(
RichText::new(GossipUi::pubkeyhex_convert_short(&person.pubkey)).weak(),
);
ui.label(RichText::new(GossipUi::pubkey_short(&person.pubkey)).weak());
GossipUi::render_person_name_line(app, ui, person);
if ui.button("UNMUTE").clicked() {
GLOBALS.people.mute(&person.pubkey, false);
GLOBALS.people.mute(person.pubkey, false);
}
});
});

View File

@ -6,17 +6,17 @@ use crate::ui::widgets::CopyButton;
use crate::AVATAR_SIZE_F32;
use eframe::egui;
use egui::{Context, Frame, RichText, ScrollArea, Ui, Vec2};
use nostr_types::{PublicKey, PublicKeyHex};
use nostr_types::PublicKey;
use serde_json::Value;
pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) {
let (pubkeyhex, person) = match &app.page {
Page::Person(pubkeyhex) => {
let person = match GLOBALS.people.get(pubkeyhex) {
let (pubkey, person) = match &app.page {
Page::Person(pubkey) => {
let person = match GLOBALS.people.get(pubkey) {
Some(p) => p,
None => Person::new(pubkeyhex.to_owned()),
None => Person::new(pubkey.to_owned()),
};
(pubkeyhex.to_owned(), person)
(pubkey.to_owned(), person)
}
_ => {
ui.label("ERROR");
@ -33,22 +33,16 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
.max_width(f32::INFINITY)
.auto_shrink([false, false])
.show(ui, |ui| {
content(app, ctx, ui, pubkeyhex, person);
content(app, ctx, ui, pubkey, person);
});
}
fn content(
app: &mut GossipUi,
ctx: &Context,
ui: &mut Ui,
pubkeyhex: PublicKeyHex,
person: Person,
) {
fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, person: Person) {
ui.add_space(24.0);
ui.horizontal(|ui| {
// Avatar first
let avatar = if let Some(avatar) = app.try_get_avatar(ctx, &pubkeyhex) {
let avatar = if let Some(avatar) = app.try_get_avatar(ctx, &pubkey) {
avatar
} else {
app.placeholder_avatar.clone()
@ -63,32 +57,29 @@ fn content(
ui.vertical(|ui| {
let name = GossipUi::display_name_from_dbperson(&person);
ui.heading(name);
ui.label(RichText::new(GossipUi::pubkeyhex_convert_short(&pubkeyhex)).weak());
ui.label(RichText::new(GossipUi::pubkey_short(&pubkey)).weak());
GossipUi::render_person_name_line(app, ui, &person);
});
});
ui.add_space(12.0);
let mut npub = "Unable to get npub".to_owned();
if let Ok(pk) = PublicKey::try_from_hex_string(&pubkeyhex) {
npub = pk.as_bech32_string();
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Public Key: ").strong());
ui.label(&npub);
if ui
.add(CopyButton {})
.on_hover_text("Copy Public Key")
.clicked()
{
ui.output_mut(|o| o.copied_text = npub.to_owned());
}
if ui.button("").on_hover_text("Show as QR code").clicked() {
app.qr_codes.remove("person_qr");
app.person_qr = Some("npub");
}
});
}
let npub = pubkey.as_bech32_string();
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Public Key: ").strong());
ui.label(&npub);
if ui
.add(CopyButton {})
.on_hover_text("Copy Public Key")
.clicked()
{
ui.output_mut(|o| o.copied_text = npub.to_owned());
}
if ui.button("").on_hover_text("Show as QR code").clicked() {
app.qr_codes.remove("person_qr");
app.person_qr = Some("npub");
}
});
if let Some(name) = person.name() {
ui.horizontal_wrapped(|ui| {
@ -198,8 +189,9 @@ fn content(
}
let mut need_to_set_active_person = true;
if let Some(ap) = GLOBALS.people.get_active_person() {
if ap == pubkeyhex {
if ap == pubkey {
need_to_set_active_person = false;
app.setting_active_person = false;
@ -217,6 +209,6 @@ fn content(
app.setting_active_person = true;
let _ = GLOBALS
.to_overlord
.send(ToOverlordMessage::SetActivePerson(pubkeyhex.clone()));
.send(ToOverlordMessage::SetActivePerson(pubkey));
}
}

View File

@ -106,7 +106,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
for elem in GLOBALS.relay_picker.pubkey_counts_iter() {
let pk = elem.key();
let count = elem.value();
let name = GossipUi::display_name_from_pubkeyhex_lookup(pk);
let name = GossipUi::display_name_from_pubkey_lookup(pk);
ui.label(format!("{}: coverage short by {} relay(s)", name, count));
}
} else {

View File

@ -77,14 +77,11 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut Frame, ui:
)
.clicked()
{
app.set_page(Page::Person(person.pubkey.clone()));
app.set_page(Page::Person(person.pubkey));
};
ui.vertical(|ui| {
ui.label(
RichText::new(GossipUi::pubkeyhex_convert_short(&person.pubkey))
.weak(),
);
ui.label(RichText::new(GossipUi::pubkey_short(&person.pubkey)).weak());
GossipUi::render_person_name_line(app, ui, person);
});
});
@ -104,8 +101,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut Frame, ui:
.weak(),
);
let pubkeyhex = event.pubkey.into();
if let Some(person) = GLOBALS.people.get(&pubkeyhex) {
if let Some(person) = GLOBALS.people.get(&event.pubkey) {
GossipUi::render_person_name_line(app, ui, &person);
} else {
ui.label(event.pubkey.as_bech32_string());
@ -122,7 +118,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut Frame, ui:
app.set_page(Page::Feed(FeedKind::Thread {
id: event.id,
referenced_by: event.id,
author: Some(event.pubkey.into()),
author: Some(event.pubkey),
}));
}
}

View File

@ -29,11 +29,11 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
}
};
let you = match GLOBALS.people.get(&public_key.into()) {
let you = match GLOBALS.people.get(&public_key) {
Some(dbp) => dbp,
None => {
ui.label("I cannot find you.");
GLOBALS.people.create_if_missing_sync(public_key.into());
GLOBALS.people.create_if_missing_sync(public_key);
return;
}
};