mirror of
https://github.com/mikedilger/gossip.git
synced 2024-10-04 10:50:57 +00:00
Big rewrite of DbPerson to match database
This commit is contained in:
parent
0a5814163d
commit
9b267f6c99
@ -16,9 +16,6 @@ pub use event_relationship::DbEventRelationship;
|
|||||||
mod relay;
|
mod relay;
|
||||||
pub use relay::DbRelay;
|
pub use relay::DbRelay;
|
||||||
|
|
||||||
mod person;
|
|
||||||
pub use person::DbPerson;
|
|
||||||
|
|
||||||
mod contact;
|
mod contact;
|
||||||
pub use contact::DbContact;
|
pub use contact::DbContact;
|
||||||
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
use nostr_types::PublicKeyHex;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct DbPerson {
|
|
||||||
pub pubkey: PublicKeyHex,
|
|
||||||
pub name: Option<String>,
|
|
||||||
pub about: Option<String>,
|
|
||||||
pub picture: Option<String>,
|
|
||||||
pub dns_id: Option<String>,
|
|
||||||
pub dns_id_valid: u8,
|
|
||||||
pub dns_id_last_checked: Option<u64>,
|
|
||||||
pub metadata_at: Option<i64>,
|
|
||||||
pub followed: u8,
|
|
||||||
pub followed_last_updated: i64,
|
|
||||||
}
|
|
45
src/nip05.rs
45
src/nip05.rs
@ -1,7 +1,8 @@
|
|||||||
use crate::db::{DbPerson, DbPersonRelay, DbRelay};
|
use crate::db::{DbPersonRelay, DbRelay};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::globals::GLOBALS;
|
use crate::globals::GLOBALS;
|
||||||
use nostr_types::{Nip05, Unixtime, Url};
|
use crate::people::DbPerson;
|
||||||
|
use nostr_types::{Metadata, Nip05, Unixtime, Url};
|
||||||
|
|
||||||
// This updates the people map and the database with the result
|
// This updates the people map and the database with the result
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -9,29 +10,31 @@ pub async fn validate_nip05(person: DbPerson) -> Result<(), Error> {
|
|||||||
let now = Unixtime::now().unwrap();
|
let now = Unixtime::now().unwrap();
|
||||||
|
|
||||||
// invalid if their nip-05 is not set
|
// invalid if their nip-05 is not set
|
||||||
if person.dns_id.is_none() {
|
if person.metadata.is_none() || matches!(person.metadata, Some(Metadata { nip05: None, .. })) {
|
||||||
GLOBALS
|
GLOBALS
|
||||||
.people
|
.people
|
||||||
.upsert_nip05_validity(&person.pubkey, person.dns_id, false, now.0 as u64)
|
.upsert_nip05_validity(&person.pubkey, None, false, now.0 as u64)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let metadata = person.metadata.as_ref().unwrap().to_owned();
|
||||||
|
let nip05 = metadata.nip05.as_ref().unwrap().to_owned();
|
||||||
|
|
||||||
// Split their DNS ID
|
// Split their DNS ID
|
||||||
let dns_id = person.dns_id.clone().unwrap();
|
let (user, domain) = match parse_nip05(&nip05) {
|
||||||
let (user, domain) = match parse_dns_id(&dns_id) {
|
|
||||||
Ok(pair) => pair,
|
Ok(pair) => pair,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
GLOBALS
|
GLOBALS
|
||||||
.people
|
.people
|
||||||
.upsert_nip05_validity(&person.pubkey, person.dns_id, false, now.0 as u64)
|
.upsert_nip05_validity(&person.pubkey, Some(nip05), false, now.0 as u64)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch NIP-05
|
// Fetch NIP-05
|
||||||
let nip05 = match fetch_nip05(&user, &domain).await {
|
let nip05file = match fetch_nip05(&user, &domain).await {
|
||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("NIP-05 fetch issue with {}@{}", user, domain);
|
tracing::error!("NIP-05 fetch issue with {}@{}", user, domain);
|
||||||
@ -40,13 +43,13 @@ pub async fn validate_nip05(person: DbPerson) -> Result<(), Error> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if the response matches their public key
|
// Check if the response matches their public key
|
||||||
match nip05.names.get(&user) {
|
match nip05file.names.get(&user) {
|
||||||
Some(pk) => {
|
Some(pk) => {
|
||||||
if *pk == person.pubkey {
|
if *pk == person.pubkey {
|
||||||
// Validated
|
// Validated
|
||||||
GLOBALS
|
GLOBALS
|
||||||
.people
|
.people
|
||||||
.upsert_nip05_validity(&person.pubkey, person.dns_id, true, now.0 as u64)
|
.upsert_nip05_validity(&person.pubkey, Some(nip05), true, now.0 as u64)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,7 +57,7 @@ pub async fn validate_nip05(person: DbPerson) -> Result<(), Error> {
|
|||||||
// Failed
|
// Failed
|
||||||
GLOBALS
|
GLOBALS
|
||||||
.people
|
.people
|
||||||
.upsert_nip05_validity(&person.pubkey, person.dns_id, false, now.0 as u64)
|
.upsert_nip05_validity(&person.pubkey, Some(nip05), false, now.0 as u64)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,15 +65,15 @@ pub async fn validate_nip05(person: DbPerson) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_and_follow_nip05(dns_id: String) -> Result<(), Error> {
|
pub async fn get_and_follow_nip05(nip05: String) -> Result<(), Error> {
|
||||||
// Split their DNS ID
|
// Split their DNS ID
|
||||||
let (user, domain) = parse_dns_id(&dns_id)?;
|
let (user, domain) = parse_nip05(&nip05)?;
|
||||||
|
|
||||||
// Fetch NIP-05
|
// Fetch NIP-05
|
||||||
let nip05 = fetch_nip05(&user, &domain).await?;
|
let nip05file = fetch_nip05(&user, &domain).await?;
|
||||||
|
|
||||||
// Get their pubkey
|
// Get their pubkey
|
||||||
let pubkey = match nip05.names.get(&user) {
|
let pubkey = match nip05file.names.get(&user) {
|
||||||
Some(pk) => pk,
|
Some(pk) => pk,
|
||||||
None => return Err(Error::Nip05KeyNotFound),
|
None => return Err(Error::Nip05KeyNotFound),
|
||||||
};
|
};
|
||||||
@ -80,7 +83,7 @@ pub async fn get_and_follow_nip05(dns_id: String) -> Result<(), Error> {
|
|||||||
.people
|
.people
|
||||||
.upsert_nip05_validity(
|
.upsert_nip05_validity(
|
||||||
pubkey,
|
pubkey,
|
||||||
Some(dns_id.clone()),
|
Some(nip05.clone()),
|
||||||
true,
|
true,
|
||||||
Unixtime::now().unwrap().0 as u64,
|
Unixtime::now().unwrap().0 as u64,
|
||||||
)
|
)
|
||||||
@ -89,10 +92,10 @@ pub async fn get_and_follow_nip05(dns_id: String) -> Result<(), Error> {
|
|||||||
// Mark as followed
|
// Mark as followed
|
||||||
GLOBALS.people.async_follow(pubkey, true).await?;
|
GLOBALS.people.async_follow(pubkey, true).await?;
|
||||||
|
|
||||||
tracing::info!("Followed {}", &dns_id);
|
tracing::info!("Followed {}", &nip05);
|
||||||
|
|
||||||
// Set their relays
|
// Set their relays
|
||||||
let relays = match nip05.relays.get(pubkey) {
|
let relays = match nip05file.relays.get(pubkey) {
|
||||||
Some(relays) => relays,
|
Some(relays) => relays,
|
||||||
None => return Err(Error::Nip05RelaysNotFound),
|
None => return Err(Error::Nip05RelaysNotFound),
|
||||||
};
|
};
|
||||||
@ -113,14 +116,14 @@ pub async fn get_and_follow_nip05(dns_id: String) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::info!("Setup {} relays for {}", relays.len(), &dns_id);
|
tracing::info!("Setup {} relays for {}", relays.len(), &nip05);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns user and domain
|
// returns user and domain
|
||||||
fn parse_dns_id(dns_id: &str) -> Result<(String, String), Error> {
|
fn parse_nip05(nip05: &str) -> Result<(String, String), Error> {
|
||||||
let mut parts: Vec<&str> = dns_id.split('@').collect();
|
let mut parts: Vec<&str> = nip05.split('@').collect();
|
||||||
|
|
||||||
// Add the underscore as a username if they just specified a domain name.
|
// Add the underscore as a username if they just specified a domain name.
|
||||||
if parts.len() == 1 {
|
if parts.len() == 1 {
|
||||||
|
@ -393,9 +393,9 @@ impl Overlord {
|
|||||||
ToOverlordMessage::FollowHex(hex, relay) => {
|
ToOverlordMessage::FollowHex(hex, relay) => {
|
||||||
Overlord::follow_hexkey(hex, relay).await?;
|
Overlord::follow_hexkey(hex, relay).await?;
|
||||||
}
|
}
|
||||||
ToOverlordMessage::FollowNip05(dns_id) => {
|
ToOverlordMessage::FollowNip05(nip05) => {
|
||||||
let _ = tokio::spawn(async move {
|
let _ = tokio::spawn(async move {
|
||||||
if let Err(e) = crate::nip05::get_and_follow_nip05(dns_id).await {
|
if let Err(e) = crate::nip05::get_and_follow_nip05(nip05).await {
|
||||||
tracing::error!("{}", e);
|
tracing::error!("{}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
293
src/people.rs
293
src/people.rs
@ -1,4 +1,4 @@
|
|||||||
use crate::db::{DbPerson, DbPersonRelay};
|
use crate::db::DbPersonRelay;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::globals::GLOBALS;
|
use crate::globals::GLOBALS;
|
||||||
use crate::AVATAR_SIZE;
|
use crate::AVATAR_SIZE;
|
||||||
@ -9,10 +9,56 @@ use image::imageops::FilterType;
|
|||||||
use nostr_types::{
|
use nostr_types::{
|
||||||
Event, EventKind, Metadata, PreEvent, PublicKey, PublicKeyHex, Tag, Unixtime, Url,
|
Event, EventKind, Metadata, PreEvent, PublicKey, PublicKeyHex, Tag, Unixtime, Url,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct DbPerson {
|
||||||
|
pub pubkey: PublicKeyHex,
|
||||||
|
pub metadata: Option<Metadata>,
|
||||||
|
pub metadata_at: Option<i64>,
|
||||||
|
pub nip05_valid: u8,
|
||||||
|
pub nip05_last_checked: Option<u64>,
|
||||||
|
pub followed: u8,
|
||||||
|
pub followed_last_updated: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbPerson {
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
if let Some(md) = &self.metadata {
|
||||||
|
md.name.as_deref()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn about(&self) -> Option<&str> {
|
||||||
|
if let Some(md) = &self.metadata {
|
||||||
|
md.about.as_deref()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn picture(&self) -> Option<&str> {
|
||||||
|
if let Some(md) = &self.metadata {
|
||||||
|
md.picture.as_deref()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nip05(&self) -> Option<&str> {
|
||||||
|
if let Some(md) = &self.metadata {
|
||||||
|
md.nip05.as_deref()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct People {
|
pub struct People {
|
||||||
people: DashMap<PublicKeyHex, DbPerson>,
|
people: DashMap<PublicKeyHex, DbPerson>,
|
||||||
|
|
||||||
@ -110,17 +156,17 @@ impl People {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if doit {
|
if doit {
|
||||||
// Process fresh metadata
|
let nip05_changed = if let Some(md) = &person.metadata {
|
||||||
|
metadata.nip05 != md.nip05.clone()
|
||||||
person.name = metadata.name;
|
} else {
|
||||||
person.about = metadata.about;
|
metadata.nip05.is_some()
|
||||||
person.picture = metadata.picture;
|
};
|
||||||
if person.dns_id != metadata.nip05 {
|
person.metadata = Some(metadata);
|
||||||
person.dns_id = metadata.nip05;
|
|
||||||
person.dns_id_valid = 0; // changed, so reset to invalid
|
|
||||||
person.dns_id_last_checked = None; // we haven't checked this one yet
|
|
||||||
}
|
|
||||||
person.metadata_at = Some(asof.0);
|
person.metadata_at = Some(asof.0);
|
||||||
|
if nip05_changed {
|
||||||
|
person.nip05_valid = 0; // changed, so reset to invalid
|
||||||
|
person.nip05_last_checked = None; // we haven't checked this one yet
|
||||||
|
}
|
||||||
|
|
||||||
// Update the database
|
// Update the database
|
||||||
let person = person.clone();
|
let person = person.clone();
|
||||||
@ -129,15 +175,20 @@ impl People {
|
|||||||
let maybe_db = GLOBALS.db.blocking_lock();
|
let maybe_db = GLOBALS.db.blocking_lock();
|
||||||
let db = maybe_db.as_ref().unwrap();
|
let db = maybe_db.as_ref().unwrap();
|
||||||
|
|
||||||
|
let metadata_json: Option<String> = if let Some(md) = &person.metadata {
|
||||||
|
Some(serde_json::to_string(md)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut stmt = db.prepare(
|
let mut stmt = db.prepare(
|
||||||
"UPDATE person SET name=?, about=?, picture=?, dns_id=?, metadata_at=? WHERE pubkey=?"
|
"UPDATE person SET metadata=?, metadata_at=?, nip05_valid=?, nip05_last_checked=? WHERE pubkey=?"
|
||||||
)?;
|
)?;
|
||||||
stmt.execute((
|
stmt.execute((
|
||||||
&person.name,
|
&metadata_json,
|
||||||
&person.about,
|
|
||||||
&person.picture,
|
|
||||||
&person.dns_id,
|
|
||||||
&person.metadata_at,
|
&person.metadata_at,
|
||||||
|
&person.nip05_valid,
|
||||||
|
&person.nip05_last_checked,
|
||||||
&pubkeyhex2.0,
|
&pubkeyhex2.0,
|
||||||
))?;
|
))?;
|
||||||
Ok::<(), Error>(())
|
Ok::<(), Error>(())
|
||||||
@ -151,20 +202,26 @@ impl People {
|
|||||||
let person = person.to_owned();
|
let person = person.to_owned();
|
||||||
|
|
||||||
// Only if they have a nip05 dns id set
|
// Only if they have a nip05 dns id set
|
||||||
if person.dns_id.is_some() {
|
if matches!(
|
||||||
|
person,
|
||||||
|
DbPerson {
|
||||||
|
metadata: Some(Metadata { nip05: Some(_), .. }),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
) {
|
||||||
// Recheck nip05 every day if invalid, and every two weeks if valid
|
// Recheck nip05 every day if invalid, and every two weeks if valid
|
||||||
// FIXME make these settings
|
// FIXME make these settings
|
||||||
let recheck_duration = if person.dns_id_valid > 0 {
|
let recheck_duration = if person.nip05_valid > 0 {
|
||||||
Duration::from_secs(60 * 60 * 24 * 14)
|
Duration::from_secs(60 * 60 * 24 * 14)
|
||||||
} else {
|
} else {
|
||||||
Duration::from_secs(60 * 60 * 24)
|
Duration::from_secs(60 * 60 * 24)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Maybe validate nip05
|
// Maybe validate nip05
|
||||||
if let Some(last) = person.dns_id_last_checked {
|
if let Some(last) = person.nip05_last_checked {
|
||||||
if Unixtime::now().unwrap() - Unixtime(last as i64) > recheck_duration {
|
if Unixtime::now().unwrap() - Unixtime(last as i64) > recheck_duration {
|
||||||
// recheck
|
// recheck
|
||||||
self.update_dns_id_last_checked(person.pubkey.clone())
|
self.update_nip05_last_checked(person.pubkey.clone())
|
||||||
.await?;
|
.await?;
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
if let Err(e) = crate::nip05::validate_nip05(person).await {
|
if let Err(e) = crate::nip05::validate_nip05(person).await {
|
||||||
@ -173,7 +230,7 @@ impl People {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.update_dns_id_last_checked(person.pubkey.clone())
|
self.update_nip05_last_checked(person.pubkey.clone())
|
||||||
.await?;
|
.await?;
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
if let Err(e) = crate::nip05::validate_nip05(person).await {
|
if let Err(e) = crate::nip05::validate_nip05(person).await {
|
||||||
@ -194,9 +251,8 @@ impl People {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let sql =
|
let sql = "SELECT pubkey, metadata, metadata_at, nip05_valid, nip05_last_checked, \
|
||||||
"SELECT pubkey, name, about, picture, dns_id, dns_id_valid, dns_id_last_checked, \
|
followed, followed_last_updated FROM person WHERE followed=1"
|
||||||
metadata_at, followed, followed_last_updated FROM person WHERE followed=1"
|
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let output: Result<Vec<DbPerson>, Error> = task::spawn_blocking(move || {
|
let output: Result<Vec<DbPerson>, Error> = task::spawn_blocking(move || {
|
||||||
@ -204,23 +260,23 @@ impl People {
|
|||||||
let db = maybe_db.as_ref().unwrap();
|
let db = maybe_db.as_ref().unwrap();
|
||||||
|
|
||||||
let mut stmt = db.prepare(&sql)?;
|
let mut stmt = db.prepare(&sql)?;
|
||||||
let rows = stmt.query_map([], |row| {
|
let mut rows = stmt.query([])?;
|
||||||
Ok(DbPerson {
|
|
||||||
pubkey: PublicKeyHex(row.get(0)?),
|
|
||||||
name: row.get(1)?,
|
|
||||||
about: row.get(2)?,
|
|
||||||
picture: row.get(3)?,
|
|
||||||
dns_id: row.get(4)?,
|
|
||||||
dns_id_valid: row.get(5)?,
|
|
||||||
dns_id_last_checked: row.get(6)?,
|
|
||||||
metadata_at: row.get(7)?,
|
|
||||||
followed: row.get(8)?,
|
|
||||||
followed_last_updated: row.get(9)?,
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
let mut output: Vec<DbPerson> = Vec::new();
|
let mut output: Vec<DbPerson> = Vec::new();
|
||||||
for row in rows {
|
while let Some(row) = rows.next()? {
|
||||||
output.push(row?);
|
let metadata_json: Option<String> = row.get(1)?;
|
||||||
|
let metadata = match metadata_json {
|
||||||
|
Some(s) => serde_json::from_str(&s)?,
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
output.push(DbPerson {
|
||||||
|
pubkey: PublicKeyHex(row.get(0)?),
|
||||||
|
metadata,
|
||||||
|
metadata_at: row.get(2)?,
|
||||||
|
nip05_valid: row.get(3)?,
|
||||||
|
nip05_last_checked: row.get(4)?,
|
||||||
|
followed: row.get(5)?,
|
||||||
|
followed_last_updated: row.get(6)?,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ok(output)
|
Ok(output)
|
||||||
})
|
})
|
||||||
@ -258,7 +314,7 @@ impl People {
|
|||||||
pub fn get_all(&self) -> Vec<DbPerson> {
|
pub fn get_all(&self) -> Vec<DbPerson> {
|
||||||
let mut v: Vec<DbPerson> = self.people.iter().map(|e| e.value().to_owned()).collect();
|
let mut v: Vec<DbPerson> = self.people.iter().map(|e| e.value().to_owned()).collect();
|
||||||
v.sort_by(|a, b| {
|
v.sort_by(|a, b| {
|
||||||
let c = a.name.cmp(&b.name);
|
let c = a.name().cmp(&b.name());
|
||||||
if c == Ordering::Equal {
|
if c == Ordering::Equal {
|
||||||
a.pubkey.cmp(&b.pubkey)
|
a.pubkey.cmp(&b.pubkey)
|
||||||
} else {
|
} else {
|
||||||
@ -296,13 +352,13 @@ impl People {
|
|||||||
// Fail if they don't have a picture url
|
// Fail if they don't have a picture url
|
||||||
// FIXME: we could get metadata that sets this while we are running, so just failing for
|
// FIXME: we could get metadata that sets this while we are running, so just failing for
|
||||||
// the duration of the client isn't quite right. But for now, retrying is taxing.
|
// the duration of the client isn't quite right. But for now, retrying is taxing.
|
||||||
if person.picture.is_none() {
|
if person.picture().is_none() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: we could get metadata that sets this while we are running, so just failing for
|
// FIXME: we could get metadata that sets this while we are running, so just failing for
|
||||||
// the duration of the client isn't quite right. But for now, retrying is taxing.
|
// the duration of the client isn't quite right. But for now, retrying is taxing.
|
||||||
let url = Url::new(person.picture.as_ref().unwrap());
|
let url = Url::new(person.picture().unwrap());
|
||||||
if !url.is_valid() {
|
if !url.is_valid() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@ -370,7 +426,7 @@ impl People {
|
|||||||
let mut result_name = String::from("");
|
let mut result_name = String::from("");
|
||||||
|
|
||||||
// search for users by name
|
// search for users by name
|
||||||
if let Some(name) = &person.name.as_ref() {
|
if let Some(name) = &person.name() {
|
||||||
let matchable = name.to_lowercase();
|
let matchable = name.to_lowercase();
|
||||||
if matchable.starts_with(&search) {
|
if matchable.starts_with(&search) {
|
||||||
score = 300;
|
score = 300;
|
||||||
@ -383,15 +439,15 @@ impl People {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search for users by nip05 id
|
// search for users by nip05 id
|
||||||
if score == 0 && person.dns_id_valid > 0 {
|
if score == 0 && person.nip05_valid > 0 {
|
||||||
if let Some(dns_id) = &person.dns_id.as_ref().map(|n| n.to_lowercase()) {
|
if let Some(nip05) = &person.nip05().map(|n| n.to_lowercase()) {
|
||||||
if dns_id.starts_with(&search) {
|
if nip05.starts_with(&search) {
|
||||||
score = 400;
|
score = 400;
|
||||||
result_name = dns_id.to_string();
|
result_name = nip05.to_string();
|
||||||
}
|
}
|
||||||
if dns_id.contains(&search) {
|
if nip05.contains(&search) {
|
||||||
score = 100;
|
score = 100;
|
||||||
result_name = dns_id.to_string();
|
result_name = nip05.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -602,10 +658,10 @@ impl People {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_dns_id_last_checked(&self, pubkeyhex: PublicKeyHex) -> Result<(), Error> {
|
pub async fn update_nip05_last_checked(&self, pubkeyhex: PublicKeyHex) -> Result<(), Error> {
|
||||||
let maybe_db = GLOBALS.db.lock().await;
|
let maybe_db = GLOBALS.db.lock().await;
|
||||||
let db = maybe_db.as_ref().unwrap();
|
let db = maybe_db.as_ref().unwrap();
|
||||||
let mut stmt = db.prepare("UPDATE person SET dns_id_last_checked=? WHERE pubkey=?")?;
|
let mut stmt = db.prepare("UPDATE person SET nip05_last_checked=? WHERE pubkey=?")?;
|
||||||
let now = Unixtime::now().unwrap().0;
|
let now = Unixtime::now().unwrap().0;
|
||||||
stmt.execute((&now, &pubkeyhex.0))?;
|
stmt.execute((&now, &pubkeyhex.0))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -614,36 +670,54 @@ impl People {
|
|||||||
pub async fn upsert_nip05_validity(
|
pub async fn upsert_nip05_validity(
|
||||||
&self,
|
&self,
|
||||||
pubkeyhex: &PublicKeyHex,
|
pubkeyhex: &PublicKeyHex,
|
||||||
dns_id: Option<String>,
|
nip05: Option<String>,
|
||||||
dns_id_valid: bool,
|
nip05_valid: bool,
|
||||||
dns_id_last_checked: u64,
|
nip05_last_checked: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Update memory
|
// Update memory
|
||||||
if let Some(mut dbperson) = self.people.get_mut(pubkeyhex) {
|
if let Some(mut dbperson) = self.people.get_mut(pubkeyhex) {
|
||||||
dbperson.dns_id = dns_id.clone();
|
if let Some(metadata) = &mut dbperson.metadata {
|
||||||
dbperson.dns_id_valid = u8::from(dns_id_valid);
|
metadata.nip05 = nip05.clone()
|
||||||
dbperson.dns_id_last_checked = Some(dns_id_last_checked);
|
} else {
|
||||||
|
let mut metadata = Metadata::new();
|
||||||
|
metadata.nip05 = nip05.clone();
|
||||||
|
dbperson.metadata = Some(metadata);
|
||||||
|
}
|
||||||
|
dbperson.nip05_valid = u8::from(nip05_valid);
|
||||||
|
dbperson.nip05_last_checked = Some(nip05_last_checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update in database
|
// Update in database
|
||||||
let sql = "INSERT INTO person (pubkey, dns_id, dns_id_valid, dns_id_last_checked) \
|
let sql = "INSERT INTO person (pubkey, metadata, nip05_valid, nip05_last_checked) \
|
||||||
values (?, ?, ?, ?) \
|
values (?, ?, ?, ?) \
|
||||||
ON CONFLICT(pubkey) DO UPDATE SET dns_id=?, dns_id_valid=?, dns_id_last_checked=?";
|
ON CONFLICT(pubkey) DO \
|
||||||
|
UPDATE SET metadata=json_patch(metadata, ?), nip05_valid=?, nip05_last_checked=?";
|
||||||
|
|
||||||
let pubkeyhex2 = pubkeyhex.to_owned();
|
let pubkeyhex2 = pubkeyhex.to_owned();
|
||||||
task::spawn_blocking(move || {
|
task::spawn_blocking(move || {
|
||||||
let maybe_db = GLOBALS.db.blocking_lock();
|
let maybe_db = GLOBALS.db.blocking_lock();
|
||||||
let db = maybe_db.as_ref().unwrap();
|
let db = maybe_db.as_ref().unwrap();
|
||||||
|
|
||||||
|
let mut metadata = Metadata::new();
|
||||||
|
metadata.nip05 = nip05.clone();
|
||||||
|
let metadata_json: Option<String> = Some(serde_json::to_string(&metadata)?);
|
||||||
|
let metadata_patch = format!(
|
||||||
|
"{{\"nip05\": {}}}",
|
||||||
|
match nip05 {
|
||||||
|
Some(s) => s,
|
||||||
|
None => "null".to_owned(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
let mut stmt = db.prepare(sql)?;
|
let mut stmt = db.prepare(sql)?;
|
||||||
stmt.execute((
|
stmt.execute((
|
||||||
&pubkeyhex2.0,
|
&pubkeyhex2.0,
|
||||||
&dns_id,
|
&metadata_json,
|
||||||
&dns_id_valid,
|
&nip05_valid,
|
||||||
&dns_id_last_checked,
|
&nip05_last_checked,
|
||||||
&dns_id,
|
&metadata_patch,
|
||||||
&dns_id_valid,
|
&nip05_valid,
|
||||||
&dns_id_last_checked,
|
&nip05_last_checked,
|
||||||
))?;
|
))?;
|
||||||
Ok::<(), Error>(())
|
Ok::<(), Error>(())
|
||||||
})
|
})
|
||||||
@ -653,9 +727,9 @@ impl People {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch(criteria: Option<&str>) -> Result<Vec<DbPerson>, Error> {
|
async fn fetch(criteria: Option<&str>) -> Result<Vec<DbPerson>, Error> {
|
||||||
let sql =
|
let sql = "SELECT pubkey, metadata, metadata_at, \
|
||||||
"SELECT pubkey, name, about, picture, dns_id, dns_id_valid, dns_id_last_checked, \
|
nip05_valid, nip05_last_checked, \
|
||||||
metadata_at, followed, followed_last_updated FROM person"
|
followed, followed_last_updated FROM person"
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let sql = match criteria {
|
let sql = match criteria {
|
||||||
None => sql,
|
None => sql,
|
||||||
@ -667,24 +741,23 @@ impl People {
|
|||||||
let db = maybe_db.as_ref().unwrap();
|
let db = maybe_db.as_ref().unwrap();
|
||||||
|
|
||||||
let mut stmt = db.prepare(&sql)?;
|
let mut stmt = db.prepare(&sql)?;
|
||||||
let rows = stmt.query_map([], |row| {
|
let mut rows = stmt.query([])?;
|
||||||
Ok(DbPerson {
|
|
||||||
pubkey: PublicKeyHex(row.get(0)?),
|
|
||||||
name: row.get(1)?,
|
|
||||||
about: row.get(2)?,
|
|
||||||
picture: row.get(3)?,
|
|
||||||
dns_id: row.get(4)?,
|
|
||||||
dns_id_valid: row.get(5)?,
|
|
||||||
dns_id_last_checked: row.get(6)?,
|
|
||||||
metadata_at: row.get(7)?,
|
|
||||||
followed: row.get(8)?,
|
|
||||||
followed_last_updated: row.get(9)?,
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut output: Vec<DbPerson> = Vec::new();
|
let mut output: Vec<DbPerson> = Vec::new();
|
||||||
for row in rows {
|
while let Some(row) = rows.next()? {
|
||||||
output.push(row?);
|
let metadata_json: Option<String> = row.get(1)?;
|
||||||
|
let metadata = match metadata_json {
|
||||||
|
Some(s) => serde_json::from_str(&s)?,
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
output.push(DbPerson {
|
||||||
|
pubkey: PublicKeyHex(row.get(0)?),
|
||||||
|
metadata,
|
||||||
|
metadata_at: row.get(2)?,
|
||||||
|
nip05_valid: row.get(3)?,
|
||||||
|
nip05_last_checked: row.get(4)?,
|
||||||
|
followed: row.get(5)?,
|
||||||
|
followed_last_updated: row.get(6)?,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ok(output)
|
Ok(output)
|
||||||
})
|
})
|
||||||
@ -705,8 +778,10 @@ impl People {
|
|||||||
|
|
||||||
async fn fetch_many(pubkeys: &[&PublicKeyHex]) -> Result<Vec<DbPerson>, Error> {
|
async fn fetch_many(pubkeys: &[&PublicKeyHex]) -> Result<Vec<DbPerson>, Error> {
|
||||||
let sql = format!(
|
let sql = format!(
|
||||||
"SELECT pubkey, name, about, picture, dns_id, dns_id_valid, dns_id_last_checked, \
|
"SELECT pubkey, metadata, metadata_at, \
|
||||||
metadata_at, followed, followed_last_updated FROM person WHERE pubkey IN ({})",
|
nip05_valid, nip05_last_checked, \
|
||||||
|
followed, followed_last_updated \
|
||||||
|
FROM person WHERE pubkey IN ({})",
|
||||||
repeat_vars(pubkeys.len())
|
repeat_vars(pubkeys.len())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -727,17 +802,19 @@ impl People {
|
|||||||
let mut rows = stmt.raw_query();
|
let mut rows = stmt.raw_query();
|
||||||
let mut people: Vec<DbPerson> = Vec::new();
|
let mut people: Vec<DbPerson> = Vec::new();
|
||||||
while let Some(row) = rows.next()? {
|
while let Some(row) = rows.next()? {
|
||||||
|
let metadata_json: Option<String> = row.get(1)?;
|
||||||
|
let metadata = match metadata_json {
|
||||||
|
Some(s) => serde_json::from_str(&s)?,
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
people.push(DbPerson {
|
people.push(DbPerson {
|
||||||
pubkey: PublicKeyHex(row.get(0)?),
|
pubkey: PublicKeyHex(row.get(0)?),
|
||||||
name: row.get(1)?,
|
metadata,
|
||||||
about: row.get(2)?,
|
metadata_at: row.get(2)?,
|
||||||
picture: row.get(3)?,
|
nip05_valid: row.get(3)?,
|
||||||
dns_id: row.get(4)?,
|
nip05_last_checked: row.get(4)?,
|
||||||
dns_id_valid: row.get(5)?,
|
followed: row.get(5)?,
|
||||||
dns_id_last_checked: row.get(6)?,
|
followed_last_updated: row.get(6)?,
|
||||||
metadata_at: row.get(7)?,
|
|
||||||
followed: row.get(8)?,
|
|
||||||
followed_last_updated: row.get(9)?,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,25 +827,27 @@ impl People {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
async fn insert(person: DbPerson) -> Result<(), Error> {
|
async fn insert(person: DbPerson) -> Result<(), Error> {
|
||||||
let sql =
|
let sql = "INSERT OR IGNORE INTO person (pubkey, metadata, metadata_at, \
|
||||||
"INSERT OR IGNORE INTO person (pubkey, name, about, picture, dns_id, dns_id_valid, \
|
nip05_valid, nip05_last_checked, followed, followed_last_updated) \
|
||||||
dns_id_last_checked, metadata_at, followed, followed_last_updated) \
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)";
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)";
|
|
||||||
|
|
||||||
task::spawn_blocking(move || {
|
task::spawn_blocking(move || {
|
||||||
let maybe_db = GLOBALS.db.blocking_lock();
|
let maybe_db = GLOBALS.db.blocking_lock();
|
||||||
let db = maybe_db.as_ref().unwrap();
|
let db = maybe_db.as_ref().unwrap();
|
||||||
|
|
||||||
|
let metadata_json: Option<String> = if let Some(md) = &person.metadata {
|
||||||
|
Some(serde_json::to_string(md)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut stmt = db.prepare(sql)?;
|
let mut stmt = db.prepare(sql)?;
|
||||||
stmt.execute((
|
stmt.execute((
|
||||||
&person.pubkey.0,
|
&person.pubkey.0,
|
||||||
&person.name,
|
&metadata_json,
|
||||||
&person.about,
|
|
||||||
&person.picture,
|
|
||||||
&person.dns_id,
|
|
||||||
&person.dns_id_valid,
|
|
||||||
&person.dns_id_last_checked,
|
|
||||||
&person.metadata_at,
|
&person.metadata_at,
|
||||||
|
&person.nip05_valid,
|
||||||
|
&person.nip05_last_checked,
|
||||||
&person.followed,
|
&person.followed,
|
||||||
&person.followed_last_updated,
|
&person.followed_last_updated,
|
||||||
))?;
|
))?;
|
||||||
|
@ -203,12 +203,12 @@ fn real_posting_area(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
|
|||||||
// List tags that will be applied (FIXME: list tags from parent event too in case of reply)
|
// List tags that will be applied (FIXME: list tags from parent event too in case of reply)
|
||||||
for (i, (npub, pubkey)) in keys_from_text(&app.draft).iter().enumerate() {
|
for (i, (npub, pubkey)) in keys_from_text(&app.draft).iter().enumerate() {
|
||||||
let rendered = if let Some(person) = GLOBALS.people.get(&pubkey.as_hex_string().into()) {
|
let rendered = if let Some(person) = GLOBALS.people.get(&pubkey.as_hex_string().into()) {
|
||||||
match person.name {
|
match person.name() {
|
||||||
Some(name) => name,
|
Some(name) => name.to_owned(),
|
||||||
None => npub.to_string(),
|
None => npub.to_owned(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
npub.to_string()
|
npub.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
ui.label(format!("{}: {}", i, rendered));
|
ui.label(format!("{}: {}", i, rendered));
|
||||||
@ -357,9 +357,9 @@ fn render_post_actual(
|
|||||||
// name
|
// name
|
||||||
// about
|
// about
|
||||||
// picture
|
// picture
|
||||||
// dns_id
|
// nip05
|
||||||
// dns_id_valid
|
// nip05_valid
|
||||||
// dns_id_last_checked
|
// nip05_last_checked
|
||||||
// metadata_at
|
// metadata_at
|
||||||
// followed
|
// followed
|
||||||
|
|
||||||
@ -626,7 +626,7 @@ fn render_content(app: &mut GossipUi, ui: &mut Ui, tag_re: ®ex::Regex, event:
|
|||||||
match tag {
|
match tag {
|
||||||
Tag::Pubkey { pubkey, .. } => {
|
Tag::Pubkey { pubkey, .. } => {
|
||||||
let nam = match GLOBALS.people.get(pubkey) {
|
let nam = match GLOBALS.people.get(pubkey) {
|
||||||
Some(p) => match p.name {
|
Some(p) => match p.name() {
|
||||||
Some(n) => format!("@{}", n),
|
Some(n) => format!("@{}", n),
|
||||||
None => format!("@{}", GossipUi::hex_pubkey_short(pubkey)),
|
None => format!("@{}", GossipUi::hex_pubkey_short(pubkey)),
|
||||||
},
|
},
|
||||||
|
@ -8,10 +8,10 @@ mod widgets;
|
|||||||
mod you;
|
mod you;
|
||||||
|
|
||||||
use crate::about::About;
|
use crate::about::About;
|
||||||
use crate::db::DbPerson;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::feed::FeedKind;
|
use crate::feed::FeedKind;
|
||||||
use crate::globals::GLOBALS;
|
use crate::globals::GLOBALS;
|
||||||
|
use crate::people::DbPerson;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use crate::ui::widgets::CopyButton;
|
use crate::ui::widgets::CopyButton;
|
||||||
use eframe::{egui, IconData, Theme};
|
use eframe::{egui, IconData, Theme};
|
||||||
@ -377,7 +377,7 @@ impl GossipUi {
|
|||||||
pub fn render_person_name_line(ui: &mut Ui, maybe_person: Option<&DbPerson>) {
|
pub fn render_person_name_line(ui: &mut Ui, maybe_person: Option<&DbPerson>) {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if let Some(person) = maybe_person {
|
if let Some(person) = maybe_person {
|
||||||
if let Some(name) = &person.name {
|
if let Some(name) = person.name() {
|
||||||
ui.label(RichText::new(name).strong());
|
ui.label(RichText::new(name).strong());
|
||||||
} else {
|
} else {
|
||||||
ui.label(RichText::new(GossipUi::hex_pubkey_short(&person.pubkey)).weak());
|
ui.label(RichText::new(GossipUi::hex_pubkey_short(&person.pubkey)).weak());
|
||||||
@ -387,15 +387,15 @@ impl GossipUi {
|
|||||||
ui.label("🚶");
|
ui.label("🚶");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut dns_id) = person.dns_id.clone() {
|
if let Some(mut nip05) = person.nip05().map(|s| s.to_owned()) {
|
||||||
if dns_id.starts_with("_@") {
|
if nip05.starts_with("_@") {
|
||||||
dns_id = dns_id.get(2..).unwrap().to_string();
|
nip05 = nip05.get(2..).unwrap().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if person.dns_id_valid > 0 {
|
if person.nip05_valid > 0 {
|
||||||
ui.label(RichText::new(dns_id).monospace().small());
|
ui.label(RichText::new(nip05).monospace().small());
|
||||||
} else {
|
} else {
|
||||||
ui.label(RichText::new(dns_id).monospace().small().strikethrough());
|
ui.label(RichText::new(nip05).monospace().small().strikethrough());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::{GossipUi, Page};
|
use super::{GossipUi, Page};
|
||||||
use crate::comms::ToOverlordMessage;
|
use crate::comms::ToOverlordMessage;
|
||||||
use crate::db::DbPerson;
|
|
||||||
use crate::globals::GLOBALS;
|
use crate::globals::GLOBALS;
|
||||||
|
use crate::people::DbPerson;
|
||||||
use crate::AVATAR_SIZE_F32;
|
use crate::AVATAR_SIZE_F32;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::{Context, Image, RichText, ScrollArea, Sense, Ui, Vec2};
|
use egui::{Context, Image, RichText, ScrollArea, Sense, Ui, Vec2};
|
||||||
@ -107,7 +107,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_name(person: &DbPerson) -> String {
|
fn get_name(person: &DbPerson) -> String {
|
||||||
if let Some(name) = &person.name {
|
if let Some(name) = person.name() {
|
||||||
name.to_owned()
|
name.to_owned()
|
||||||
} else {
|
} else {
|
||||||
GossipUi::hex_pubkey_short(&person.pubkey)
|
GossipUi::hex_pubkey_short(&person.pubkey)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use super::{GossipUi, Page};
|
use super::{GossipUi, Page};
|
||||||
use crate::comms::ToOverlordMessage;
|
use crate::comms::ToOverlordMessage;
|
||||||
use crate::db::DbPerson;
|
|
||||||
use crate::feed::FeedKind;
|
use crate::feed::FeedKind;
|
||||||
use crate::globals::GLOBALS;
|
use crate::globals::GLOBALS;
|
||||||
|
use crate::people::DbPerson;
|
||||||
use crate::AVATAR_SIZE_F32;
|
use crate::AVATAR_SIZE_F32;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::{Context, RichText, Ui, Vec2};
|
use egui::{Context, RichText, Ui, Vec2};
|
||||||
@ -50,7 +50,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
|
|||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
|
|
||||||
if let Some(person) = &maybe_person {
|
if let Some(person) = &maybe_person {
|
||||||
if let Some(about) = person.about.as_deref() {
|
if let Some(about) = person.about() {
|
||||||
ui.label(about);
|
ui.label(about);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_name(person: &DbPerson) -> String {
|
fn get_name(person: &DbPerson) -> String {
|
||||||
if let Some(name) = &person.name {
|
if let Some(name) = person.name() {
|
||||||
name.to_owned()
|
name.to_owned()
|
||||||
} else {
|
} else {
|
||||||
GossipUi::hex_pubkey_short(&person.pubkey)
|
GossipUi::hex_pubkey_short(&person.pubkey)
|
||||||
|
Loading…
Reference in New Issue
Block a user