Push Contact List

This commit is contained in:
Mike Dilger 2023-01-17 20:27:32 +13:00
parent 9db4ed32e8
commit 4190cee3d1
4 changed files with 106 additions and 7 deletions

View File

@ -1,6 +1,6 @@
use crate::error::Error;
use crate::globals::GLOBALS;
use nostr_types::PublicKeyHex;
use nostr_types::{PublicKeyHex, Url};
use serde::{Deserialize, Serialize};
use tokio::task::spawn_blocking;
@ -216,7 +216,6 @@ impl DbPersonRelay {
Ok(())
}
pub async fn upsert_last_suggested_bytag(
person: String,
relay: String,
@ -330,6 +329,35 @@ impl DbPersonRelay {
output
}
#[allow(dead_code)]
pub async fn get_best_relay(pubkey: PublicKeyHex) -> Result<Option<Url>, Error> {
// This is the ranking we are using. There might be reasons
// for ranking differently:
// nip23 > kind3 > nip05 > kind2 > fetched > bytag
let sql = "SELECT relay FROM person_relay WHERE person=? \
ORDER BY last_suggested_nip23 DESC, last_suggested_kind3 DESC, \
last_suggested_nip05 DESC, last_suggested_kind2 DESC, \
last_fetched DESC, last_suggested_bytag DESC";
let maybe_relay_result: Result<Option<Url>, Error> = spawn_blocking(move || {
let maybe_db = GLOBALS.db.blocking_lock();
let db = maybe_db.as_ref().unwrap();
let mut stmt = db.prepare(sql)?;
stmt.raw_bind_parameter(1, &pubkey.0)?;
let mut rows = stmt.raw_query();
let mut maybe_relay: Option<Url> = None;
if let Some(row) = rows.next()? {
let s: String = row.get(0)?;
maybe_relay = Some(Url::new(&s));
}
Ok(maybe_relay)
})
.await?;
maybe_relay_result
}
/*
pub async fn delete(criteria: &str) -> Result<(), Error> {
let sql = format!("DELETE FROM person_relay WHERE {}", criteria);

View File

@ -473,7 +473,7 @@ impl Overlord {
self.pull_following(false).await?;
}
ToOverlordMessage::PushFollow => {
tracing::error!("Push Follow Unimplemented");
self.push_following().await?;
}
ToOverlordMessage::SaveRelays => {
let dirty_relays: Vec<DbRelay> = GLOBALS
@ -919,6 +919,41 @@ impl Overlord {
Ok(())
}
async fn push_following(&mut self) -> Result<(), Error> {
let event = GLOBALS.people.generate_contact_list_event().await?;
// Push to all of the relays we post to
let relays: Vec<DbRelay> = GLOBALS
.relays
.read()
.await
.iter()
.filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None })
.collect();
for relay in relays {
// Start a minion for it, if there is none
if !GLOBALS
.relays_watching
.read()
.await
.contains(&Url::new(&relay.url))
{
self.start_minion(relay.url.clone()).await?;
}
// Send it the event to pull our followers
tracing::debug!("Pushing ContactList to {}", &relay.url);
let _ = self.to_minions.send(ToMinionMessage {
target: relay.url.clone(),
payload: ToMinionPayload::PostEvent(Box::new(event.clone())),
});
}
Ok(())
}
async fn set_thread_feed(&mut self, id: Id, referenced_by: Id) -> Result<(), Error> {
// Cancel current thread subscriptions, if any
let _ = self.to_minions.send(ToMinionMessage {

View File

@ -1,4 +1,4 @@
use crate::db::DbPerson;
use crate::db::{DbPerson, DbPersonRelay};
use crate::error::Error;
use crate::globals::GLOBALS;
use crate::AVATAR_SIZE;
@ -6,7 +6,7 @@ use dashmap::{DashMap, DashSet};
use eframe::egui::ColorImage;
use egui_extras::image::FitTo;
use image::imageops::FilterType;
use nostr_types::{Metadata, PublicKeyHex, Unixtime, Url};
use nostr_types::{Event, EventKind, Metadata, PreEvent, PublicKeyHex, Tag, Unixtime, Url};
use std::cmp::Ordering;
use std::time::Duration;
use tokio::task;
@ -438,6 +438,43 @@ impl People {
Ok(())
}
#[allow(dead_code)]
pub async fn generate_contact_list_event(&self) -> Result<Event, Error> {
let mut p_tags: Vec<Tag> = Vec::new();
let pubkeys = self.get_followed_pubkeys();
for pubkey in &pubkeys {
// Get their best relay
let maybeurl = DbPersonRelay::get_best_relay(pubkey.clone()).await?;
p_tags.push(Tag::Pubkey {
pubkey: pubkey.clone(),
recommended_relay_url: maybeurl,
petname: None,
});
}
let public_key = match GLOBALS.signer.read().await.public_key() {
Some(pk) => pk,
None => return Err(Error::NoPrivateKey), // not even a public key
};
// NOTICE - some clients are stuffing relay following data into the content
// of `ContactList`s. We don't have a set of relays that we read from, so
// we could only do half of that even if we wanted to, and I'm not sure only
// putting in write relays is of any use.
let pre_event = PreEvent {
pubkey: public_key,
created_at: Unixtime::now().unwrap(),
kind: EventKind::ContactList,
tags: p_tags,
content: "".to_owned(),
ots: None,
};
GLOBALS.signer.read().await.sign_preevent(pre_event, None)
}
pub fn follow(&self, pubkeyhex: &PublicKeyHex, follow: bool) {
// We can't do it now, but we spawn a task to do it soon
let pubkeyhex = pubkeyhex.to_owned();

View File

@ -44,11 +44,10 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra
if ui.button("↓ PULL ↓\nMerge (Add)").clicked() {
let _ = GLOBALS.to_overlord.send(ToOverlordMessage::PullFollowMerge);
}
/* not yet implemented
if ui.button("↑ PUSH ↑\n").clicked() {
let _ = GLOBALS.to_overlord.send(ToOverlordMessage::PushFollow);
}
*/
});
ui.add_space(10.0);