Fixes and improvements to alias handling
* Return the correct alias from a node announcement, stripping '\0' bytes. * Accept `AliasStore` types as references and as owned. * Store a `null` in the database if the alias received is empty.
This commit is contained in:
parent
50a97d9add
commit
5502676aa7
|
|
@ -457,7 +457,7 @@ async fn issues_handler(
|
||||||
let aliases = &ctx.profile.aliases()?;
|
let aliases = &ctx.profile.aliases()?;
|
||||||
let issues = issues
|
let issues = issues
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, issue, _)| api::json::issue(id, issue, &aliases))
|
.map(|(id, issue, _)| api::json::issue(id, issue, aliases))
|
||||||
.skip(page * per_page)
|
.skip(page * per_page)
|
||||||
.take(per_page)
|
.take(per_page)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -568,7 +568,7 @@ async fn issue_handler(
|
||||||
let issue = issue::Issues::open(&repo)?
|
let issue = issue::Issues::open(&repo)?
|
||||||
.get(&issue_id.into())?
|
.get(&issue_id.into())?
|
||||||
.ok_or(Error::NotFound)?;
|
.ok_or(Error::NotFound)?;
|
||||||
let aliases = &ctx.profile.aliases()?;
|
let aliases = ctx.profile.aliases()?;
|
||||||
|
|
||||||
Ok::<_, Error>(Json(api::json::issue(issue_id.into(), issue, &aliases)))
|
Ok::<_, Error>(Json(api::json::issue(issue_id.into(), issue, &aliases)))
|
||||||
}
|
}
|
||||||
|
|
@ -720,7 +720,7 @@ async fn patches_handler(
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
patches.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp()));
|
patches.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp()));
|
||||||
let aliases = &ctx.profile.aliases()?;
|
let aliases = ctx.profile.aliases()?;
|
||||||
let patches = patches
|
let patches = patches
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, patch, _)| api::json::patch(id, patch, &repo, &aliases))
|
.map(|(id, patch, _)| api::json::patch(id, patch, &repo, &aliases))
|
||||||
|
|
@ -742,7 +742,7 @@ async fn patch_handler(
|
||||||
let patch = patch::Patches::open(&repo)?
|
let patch = patch::Patches::open(&repo)?
|
||||||
.get(&patch_id.into())?
|
.get(&patch_id.into())?
|
||||||
.ok_or(Error::NotFound)?;
|
.ok_or(Error::NotFound)?;
|
||||||
let aliases = &ctx.profile.aliases()?;
|
let aliases = ctx.profile.aliases()?;
|
||||||
|
|
||||||
Ok::<_, Error>(Json(api::json::patch(
|
Ok::<_, Error>(Json(api::json::patch(
|
||||||
patch_id.into(),
|
patch_id.into(),
|
||||||
|
|
|
||||||
|
|
@ -131,3 +131,17 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_node_announcement() {
|
||||||
|
let cfg = Config {
|
||||||
|
alias: Some(String::from("cloudhead")),
|
||||||
|
..Config::default()
|
||||||
|
};
|
||||||
|
assert_eq!("cloudhead", cfg.node(0).alias().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,12 @@ impl NodeAnnouncement {
|
||||||
|
|
||||||
/// Get the alias as a UTF-8 string.
|
/// Get the alias as a UTF-8 string.
|
||||||
pub fn alias(&self) -> Result<&str, std::str::Utf8Error> {
|
pub fn alias(&self) -> Result<&str, std::str::Utf8Error> {
|
||||||
str::from_utf8(&self.alias)
|
let length = self
|
||||||
|
.alias
|
||||||
|
.iter()
|
||||||
|
.position(|&b| b == 0)
|
||||||
|
.unwrap_or(self.alias.len());
|
||||||
|
str::from_utf8(&self.alias[..length])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ pub mod events;
|
||||||
pub mod routing;
|
pub mod routing;
|
||||||
pub mod tracking;
|
pub mod tracking;
|
||||||
|
|
||||||
use std::collections::{BTreeSet, HashSet};
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
|
|
@ -707,6 +707,24 @@ pub trait AliasStore {
|
||||||
fn alias(&self, nid: &NodeId) -> Option<String>;
|
fn alias(&self, nid: &NodeId) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: AliasStore + ?Sized> AliasStore for &T {
|
||||||
|
fn alias(&self, nid: &NodeId) -> Option<String> {
|
||||||
|
dbg!((*self).alias(nid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AliasStore + ?Sized> AliasStore for Box<T> {
|
||||||
|
fn alias(&self, nid: &NodeId) -> Option<String> {
|
||||||
|
self.deref().alias(nid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AliasStore for HashMap<NodeId, String> {
|
||||||
|
fn alias(&self, nid: &NodeId) -> Option<String> {
|
||||||
|
dbg!(self.get(nid).map(ToOwned::to_owned))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ impl Store for Book {
|
||||||
|
|
||||||
if let Some(Ok(row)) = stmt.into_iter().next() {
|
if let Some(Ok(row)) = stmt.into_iter().next() {
|
||||||
let features = row.read::<node::Features, _>("features");
|
let features = row.read::<node::Features, _>("features");
|
||||||
let alias = row.read::<&str, _>("alias").to_owned();
|
let alias = row.read::<Option<&str>, _>("alias").map(ToOwned::to_owned);
|
||||||
let timestamp = row.read::<i64, _>("timestamp") as Timestamp;
|
let timestamp = row.read::<i64, _>("timestamp") as Timestamp;
|
||||||
let pow = row.read::<i64, _>("pow") as u32;
|
let pow = row.read::<i64, _>("pow") as u32;
|
||||||
let mut addrs = Vec::new();
|
let mut addrs = Vec::new();
|
||||||
|
|
@ -143,6 +143,11 @@ impl Store for Book {
|
||||||
SET features = ?2, alias = ?3, pow = ?4, timestamp = ?5
|
SET features = ?2, alias = ?3, pow = ?4, timestamp = ?5
|
||||||
WHERE timestamp < ?5",
|
WHERE timestamp < ?5",
|
||||||
)?;
|
)?;
|
||||||
|
let alias = if alias.is_empty() {
|
||||||
|
sql::Value::Null
|
||||||
|
} else {
|
||||||
|
sql::Value::String(alias.to_owned())
|
||||||
|
};
|
||||||
|
|
||||||
stmt.bind((1, node))?;
|
stmt.bind((1, node))?;
|
||||||
stmt.bind((2, features))?;
|
stmt.bind((2, features))?;
|
||||||
|
|
@ -260,7 +265,7 @@ impl AliasStore for Book {
|
||||||
/// Calls `Self::get` under the hood.
|
/// Calls `Self::get` under the hood.
|
||||||
fn alias(&self, nid: &NodeId) -> Option<String> {
|
fn alias(&self, nid: &NodeId) -> Option<String> {
|
||||||
self.get(nid)
|
self.get(nid)
|
||||||
.map(|node| node.map(|n| n.alias))
|
.map(|node| node.and_then(|n| n.alias))
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -396,6 +401,26 @@ mod test {
|
||||||
assert!(!removed);
|
assert!(!removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_alias() {
|
||||||
|
let alice = arbitrary::gen::<NodeId>(1);
|
||||||
|
let mut cache = Book::memory().unwrap();
|
||||||
|
let features = node::Features::SEED;
|
||||||
|
let timestamp = LocalTime::now().as_millis();
|
||||||
|
|
||||||
|
cache
|
||||||
|
.insert(&alice, features, "alice", 16, timestamp, [])
|
||||||
|
.unwrap();
|
||||||
|
let node = cache.get(&alice).unwrap().unwrap();
|
||||||
|
assert_eq!(node.alias.as_deref(), Some("alice"));
|
||||||
|
|
||||||
|
cache
|
||||||
|
.insert(&alice, features, "", 16, timestamp + 1, [])
|
||||||
|
.unwrap();
|
||||||
|
let node = cache.get(&alice).unwrap().unwrap();
|
||||||
|
assert_eq!(node.alias.as_deref(), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_insert_and_get() {
|
fn test_insert_and_get() {
|
||||||
let alice = arbitrary::gen::<NodeId>(1);
|
let alice = arbitrary::gen::<NodeId>(1);
|
||||||
|
|
@ -419,7 +444,7 @@ mod test {
|
||||||
assert_eq!(node.features, features);
|
assert_eq!(node.features, features);
|
||||||
assert_eq!(node.pow, 16);
|
assert_eq!(node.pow, 16);
|
||||||
assert_eq!(node.timestamp, timestamp);
|
assert_eq!(node.timestamp, timestamp);
|
||||||
assert_eq!(node.alias.as_str(), "alice");
|
assert_eq!(node.alias.as_deref(), Some("alice"));
|
||||||
assert_eq!(node.addrs, vec![ka]);
|
assert_eq!(node.addrs, vec![ka]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,7 +503,7 @@ mod test {
|
||||||
assert!(!updated, "Can't update using a smaller timestamp");
|
assert!(!updated, "Can't update using a smaller timestamp");
|
||||||
|
|
||||||
let node = cache.get(&alice).unwrap().unwrap();
|
let node = cache.get(&alice).unwrap().unwrap();
|
||||||
assert_eq!(node.alias, "alice");
|
assert_eq!(node.alias.as_deref(), Some("alice"));
|
||||||
assert_eq!(node.timestamp, timestamp);
|
assert_eq!(node.timestamp, timestamp);
|
||||||
assert_eq!(node.pow, 0);
|
assert_eq!(node.pow, 0);
|
||||||
|
|
||||||
|
|
@ -501,7 +526,7 @@ mod test {
|
||||||
|
|
||||||
let node = cache.get(&alice).unwrap().unwrap();
|
let node = cache.get(&alice).unwrap().unwrap();
|
||||||
assert_eq!(node.features, node::Features::NONE);
|
assert_eq!(node.features, node::Features::NONE);
|
||||||
assert_eq!(node.alias, "~alice~");
|
assert_eq!(node.alias.as_deref(), Some("~alice~"));
|
||||||
assert_eq!(node.timestamp, timestamp + 2);
|
assert_eq!(node.timestamp, timestamp + 2);
|
||||||
assert_eq!(node.pow, 1);
|
assert_eq!(node.pow, 1);
|
||||||
assert_eq!(node.addrs, vec![ka]);
|
assert_eq!(node.addrs, vec![ka]);
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ impl<K, V> DerefMut for AddressBook<K, V> {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
/// Advertized alias.
|
/// Advertized alias.
|
||||||
pub alias: String,
|
pub alias: Option<String>,
|
||||||
/// Advertized features.
|
/// Advertized features.
|
||||||
pub features: node::Features,
|
pub features: node::Features,
|
||||||
/// Advertized addresses
|
/// Advertized addresses
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AliasStore for &Config {
|
impl AliasStore for Config {
|
||||||
/// Retrieve `alias` of given node.
|
/// Retrieve `alias` of given node.
|
||||||
/// Calls `Self::node_policy` under the hood.
|
/// Calls `Self::node_policy` under the hood.
|
||||||
fn alias(&self, nid: &NodeId) -> Option<String> {
|
fn alias(&self, nid: &NodeId) -> Option<String> {
|
||||||
|
|
|
||||||
|
|
@ -191,13 +191,13 @@ pub struct Aliases {
|
||||||
addresses: address::Book,
|
addresses: address::Book,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AliasStore for &Aliases {
|
impl AliasStore for Aliases {
|
||||||
/// Retrieve `alias` of given node.
|
/// Retrieve `alias` of given node.
|
||||||
/// First looks in `tracking.db` and then `address.db`,
|
/// First looks in `tracking.db` and then `address.db`.
|
||||||
fn alias(&self, nid: &NodeId) -> Option<String> {
|
fn alias(&self, nid: &NodeId) -> Option<String> {
|
||||||
(&&self.tracking as &dyn AliasStore)
|
self.tracking
|
||||||
.alias(nid)
|
.alias(nid)
|
||||||
.or_else(|| (&self.addresses as &dyn AliasStore).alias(nid))
|
.or_else(|| self.addresses.alias(nid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue