upgrade url string to RelaySpec for [read|write] markers
I think RelaySpec wants to move to enostr so the RelayPool can support read and write relays ...
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
KeyStorageResponse, KeyStorageType, MuteFun, Muted, SingleUnkIdAction, UnknownIds, UserAccount,
|
KeyStorageResponse, KeyStorageType, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds,
|
||||||
|
UserAccount,
|
||||||
};
|
};
|
||||||
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
|
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
|
||||||
use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction};
|
use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction};
|
||||||
@@ -38,8 +39,8 @@ pub struct AccountRelayData {
|
|||||||
filter: Filter,
|
filter: Filter,
|
||||||
subid: String,
|
subid: String,
|
||||||
sub: Option<Subscription>,
|
sub: Option<Subscription>,
|
||||||
local: BTreeSet<String>, // used locally but not advertised
|
local: BTreeSet<RelaySpec>, // used locally but not advertised
|
||||||
advertised: BTreeSet<String>, // advertised via NIP-65
|
advertised: BTreeSet<RelaySpec>, // advertised via NIP-65
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -107,7 +108,7 @@ impl AccountRelayData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn harvest_nip65_relays(ndb: &Ndb, txn: &Transaction, nks: &[NoteKey]) -> Vec<String> {
|
fn harvest_nip65_relays(ndb: &Ndb, txn: &Transaction, nks: &[NoteKey]) -> Vec<RelaySpec> {
|
||||||
let mut relays = Vec::new();
|
let mut relays = Vec::new();
|
||||||
for nk in nks.iter() {
|
for nk in nks.iter() {
|
||||||
if let Ok(note) = ndb.get_note_by_key(txn, *nk) {
|
if let Ok(note) = ndb.get_note_by_key(txn, *nk) {
|
||||||
@@ -115,7 +116,17 @@ impl AccountRelayData {
|
|||||||
match tag.get(0).and_then(|t| t.variant().str()) {
|
match tag.get(0).and_then(|t| t.variant().str()) {
|
||||||
Some("r") => {
|
Some("r") => {
|
||||||
if let Some(url) = tag.get(1).and_then(|f| f.variant().str()) {
|
if let Some(url) = tag.get(1).and_then(|f| f.variant().str()) {
|
||||||
relays.push(Self::canonicalize_url(url));
|
let has_read_marker = tag
|
||||||
|
.get(2)
|
||||||
|
.map_or(false, |m| m.variant().str() == Some("read"));
|
||||||
|
let has_write_marker = tag
|
||||||
|
.get(2)
|
||||||
|
.map_or(false, |m| m.variant().str() == Some("write"));
|
||||||
|
relays.push(RelaySpec::new(
|
||||||
|
Self::canonicalize_url(url),
|
||||||
|
has_read_marker,
|
||||||
|
has_write_marker,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some("alt") => {
|
Some("alt") => {
|
||||||
@@ -236,8 +247,8 @@ pub struct Accounts {
|
|||||||
accounts: Vec<UserAccount>,
|
accounts: Vec<UserAccount>,
|
||||||
key_store: KeyStorageType,
|
key_store: KeyStorageType,
|
||||||
account_data: BTreeMap<[u8; 32], AccountData>,
|
account_data: BTreeMap<[u8; 32], AccountData>,
|
||||||
forced_relays: BTreeSet<String>,
|
forced_relays: BTreeSet<RelaySpec>,
|
||||||
bootstrap_relays: BTreeSet<String>,
|
bootstrap_relays: BTreeSet<RelaySpec>,
|
||||||
needs_relay_config: bool,
|
needs_relay_config: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,9 +262,9 @@ impl Accounts {
|
|||||||
|
|
||||||
let currently_selected_account = get_selected_index(&accounts, &key_store);
|
let currently_selected_account = get_selected_index(&accounts, &key_store);
|
||||||
let account_data = BTreeMap::new();
|
let account_data = BTreeMap::new();
|
||||||
let forced_relays: BTreeSet<String> = forced_relays
|
let forced_relays: BTreeSet<RelaySpec> = forced_relays
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|u| AccountRelayData::canonicalize_url(&u))
|
.map(|u| RelaySpec::new(AccountRelayData::canonicalize_url(&u), false, false))
|
||||||
.collect();
|
.collect();
|
||||||
let bootstrap_relays = [
|
let bootstrap_relays = [
|
||||||
"wss://relay.damus.io",
|
"wss://relay.damus.io",
|
||||||
@@ -264,7 +275,7 @@ impl Accounts {
|
|||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&url| url.to_string())
|
.map(|&url| url.to_string())
|
||||||
.map(|u| AccountRelayData::canonicalize_url(&u))
|
.map(|u| RelaySpec::new(AccountRelayData::canonicalize_url(&u), false, false))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Accounts {
|
Accounts {
|
||||||
@@ -526,20 +537,26 @@ impl Accounts {
|
|||||||
debug!("current relays: {:?}", pool.urls());
|
debug!("current relays: {:?}", pool.urls());
|
||||||
debug!("desired relays: {:?}", desired_relays);
|
debug!("desired relays: {:?}", desired_relays);
|
||||||
|
|
||||||
let add: BTreeSet<String> = desired_relays.difference(&pool.urls()).cloned().collect();
|
let pool_specs = pool
|
||||||
let mut sub: BTreeSet<String> = pool.urls().difference(&desired_relays).cloned().collect();
|
.urls()
|
||||||
|
.iter()
|
||||||
|
.map(|url| RelaySpec::new(url.clone(), false, false))
|
||||||
|
.collect();
|
||||||
|
let add: BTreeSet<RelaySpec> = desired_relays.difference(&pool_specs).cloned().collect();
|
||||||
|
let mut sub: BTreeSet<RelaySpec> =
|
||||||
|
pool_specs.difference(&desired_relays).cloned().collect();
|
||||||
if !add.is_empty() {
|
if !add.is_empty() {
|
||||||
debug!("configuring added relays: {:?}", add);
|
debug!("configuring added relays: {:?}", add);
|
||||||
let _ = pool.add_urls(add, wakeup);
|
let _ = pool.add_urls(add.iter().map(|r| r.url.clone()).collect(), wakeup);
|
||||||
}
|
}
|
||||||
if !sub.is_empty() {
|
if !sub.is_empty() {
|
||||||
debug!("removing unwanted relays: {:?}", sub);
|
|
||||||
|
|
||||||
// certain relays are persistent like the multicast relay,
|
// certain relays are persistent like the multicast relay,
|
||||||
// although we should probably have a way to explicitly
|
// although we should probably have a way to explicitly
|
||||||
// disable it
|
// disable it
|
||||||
sub.remove("multicast");
|
sub.remove(&RelaySpec::new("multicast", false, false));
|
||||||
pool.remove_urls(&sub);
|
|
||||||
|
debug!("removing unwanted relays: {:?}", sub);
|
||||||
|
pool.remove_urls(&sub.iter().map(|r| r.url.clone()).collect());
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("current relays: {:?}", pool.urls());
|
debug!("current relays: {:?}", pool.urls());
|
||||||
@@ -591,6 +608,7 @@ impl Accounts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_advertised_relay(&mut self, relay_to_add: &str) {
|
pub fn add_advertised_relay(&mut self, relay_to_add: &str) {
|
||||||
|
let relay_to_add = AccountRelayData::canonicalize_url(relay_to_add);
|
||||||
info!("add advertised relay \"{}\"", relay_to_add);
|
info!("add advertised relay \"{}\"", relay_to_add);
|
||||||
match self.currently_selected_account {
|
match self.currently_selected_account {
|
||||||
None => error!("no account is currently selected."),
|
None => error!("no account is currently selected."),
|
||||||
@@ -607,7 +625,7 @@ impl Accounts {
|
|||||||
// iniitialize with the bootstrapping set.
|
// iniitialize with the bootstrapping set.
|
||||||
advertised.extend(self.bootstrap_relays.iter().cloned());
|
advertised.extend(self.bootstrap_relays.iter().cloned());
|
||||||
}
|
}
|
||||||
advertised.insert(relay_to_add.to_string());
|
advertised.insert(RelaySpec::new(relay_to_add, false, false));
|
||||||
self.needs_relay_config = true;
|
self.needs_relay_config = true;
|
||||||
// FIXME - need to publish the advertised set
|
// FIXME - need to publish the advertised set
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ mod muted;
|
|||||||
pub mod note;
|
pub mod note;
|
||||||
mod notecache;
|
mod notecache;
|
||||||
mod persist;
|
mod persist;
|
||||||
|
pub mod relayspec;
|
||||||
mod result;
|
mod result;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
mod style;
|
mod style;
|
||||||
@@ -33,6 +34,7 @@ pub use muted::{MuteFun, Muted};
|
|||||||
pub use note::{NoteRef, RootIdError, RootNoteId, RootNoteIdBuf};
|
pub use note::{NoteRef, RootIdError, RootNoteId, RootNoteIdBuf};
|
||||||
pub use notecache::{CachedNote, NoteCache};
|
pub use notecache::{CachedNote, NoteCache};
|
||||||
pub use persist::*;
|
pub use persist::*;
|
||||||
|
pub use relayspec::RelaySpec;
|
||||||
pub use result::Result;
|
pub use result::Result;
|
||||||
pub use storage::{
|
pub use storage::{
|
||||||
DataPath, DataPathType, Directory, FileKeyStorage, KeyStorageResponse, KeyStorageType,
|
DataPath, DataPathType, Directory, FileKeyStorage, KeyStorageResponse, KeyStorageType,
|
||||||
|
|||||||
90
crates/notedeck/src/relayspec.rs
Normal file
90
crates/notedeck/src/relayspec.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
// A Relay specification includes NIP-65 defined "markers" which
|
||||||
|
// indicate if the relay should be used for reading or writing (or
|
||||||
|
// both).
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RelaySpec {
|
||||||
|
pub url: String,
|
||||||
|
pub has_read_marker: bool,
|
||||||
|
pub has_write_marker: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelaySpec {
|
||||||
|
pub fn new(
|
||||||
|
url: impl Into<String>,
|
||||||
|
mut has_read_marker: bool,
|
||||||
|
mut has_write_marker: bool,
|
||||||
|
) -> Self {
|
||||||
|
// if both markers are set turn both off ...
|
||||||
|
if has_read_marker && has_write_marker {
|
||||||
|
has_read_marker = false;
|
||||||
|
has_write_marker = false;
|
||||||
|
}
|
||||||
|
RelaySpec {
|
||||||
|
url: url.into(),
|
||||||
|
has_read_marker,
|
||||||
|
has_write_marker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "marker" fields are a little counter-intuitive ... from NIP-65:
|
||||||
|
//
|
||||||
|
// "The event MUST include a list of r tags with relay URIs and a read
|
||||||
|
// or write marker. Relays marked as read / write are called READ /
|
||||||
|
// WRITE relays, respectively. If the marker is omitted, the relay is
|
||||||
|
// used for both purposes."
|
||||||
|
//
|
||||||
|
pub fn is_readable(&self) -> bool {
|
||||||
|
!self.has_write_marker // only "write" relays are not readable
|
||||||
|
}
|
||||||
|
pub fn is_writable(&self) -> bool {
|
||||||
|
!self.has_read_marker // only "read" relays are not writable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just the url part
|
||||||
|
impl fmt::Display for RelaySpec {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the read and write markers if present
|
||||||
|
impl fmt::Debug for RelaySpec {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "\"{}\"", self)?;
|
||||||
|
if self.has_read_marker {
|
||||||
|
write!(f, " [r]")?;
|
||||||
|
}
|
||||||
|
if self.has_write_marker {
|
||||||
|
write!(f, " [w]")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For purposes of set arithmetic only the url is considered, two
|
||||||
|
// RelaySpec which differ only in markers are the same ...
|
||||||
|
|
||||||
|
impl PartialEq for RelaySpec {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.url == other.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for RelaySpec {}
|
||||||
|
|
||||||
|
impl PartialOrd for RelaySpec {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.url.cmp(&other.url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for RelaySpec {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.url.cmp(&other.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user