Fixed DHT republish after TTL
This commit is contained in:
Generated
+190
-182
File diff suppressed because it is too large
Load Diff
@@ -84,7 +84,7 @@ pub trait MusicDhtStorage: std::fmt::Debug + Send + Sync {
|
||||
}
|
||||
|
||||
/// Searches locally owned active items: exact normalized match, or all
|
||||
/// query tokens present in the item's token set.
|
||||
/// query tokens present in the item's token set, including artist names.
|
||||
async fn search_local(&self, normalized_query: String) -> Result<Vec<LibraryItem>> {
|
||||
let all = self.list_local_items(false).await?;
|
||||
let query_tokens = tokenize(&normalized_query);
|
||||
@@ -97,7 +97,7 @@ pub trait MusicDhtStorage: std::fmt::Debug + Send + Sync {
|
||||
if query_tokens.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let artist_tokens = tokenize(&item.normalized_name);
|
||||
let artist_tokens = item.search_tokens();
|
||||
query_tokens
|
||||
.iter()
|
||||
.all(|token| artist_tokens.iter().any(|t| t == token))
|
||||
@@ -237,7 +237,7 @@ impl Database {
|
||||
}
|
||||
|
||||
/// Searches locally owned active items: exact normalized match, or all
|
||||
/// query tokens present in the item's token set.
|
||||
/// query tokens present in the item's token set, including artist names.
|
||||
pub async fn search_local(&self, normalized_query: String) -> Result<Vec<LibraryItem>> {
|
||||
let all = self.list_local_items(false).await?;
|
||||
let query_tokens = tokenize(&normalized_query);
|
||||
@@ -250,7 +250,7 @@ impl Database {
|
||||
if query_tokens.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let artist_tokens = tokenize(&item.normalized_name);
|
||||
let artist_tokens = item.search_tokens();
|
||||
query_tokens
|
||||
.iter()
|
||||
.all(|token| artist_tokens.iter().any(|t| t == token))
|
||||
@@ -522,6 +522,22 @@ mod tests {
|
||||
assert!(none.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn local_search_uses_artist_names() {
|
||||
let (_dir, db) = open_temp().await;
|
||||
let owner = test_peer(1);
|
||||
let mut track = item(owner, "Teardrop", 1, false);
|
||||
track.kind = ItemKind::Track;
|
||||
track.artist_names = vec!["Massive Attack".into()];
|
||||
db.upsert_local_item(&track).await.expect("upsert");
|
||||
|
||||
let found = db
|
||||
.search_local("massive attack".into())
|
||||
.await
|
||||
.expect("search");
|
||||
assert_eq!(found, vec![track]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn expired_dht_record_is_not_returned() {
|
||||
let (_dir, db) = open_temp().await;
|
||||
|
||||
@@ -5,8 +5,8 @@ use federation_net::NetworkId;
|
||||
use crate::message::StoreRecordRequest;
|
||||
use crate::normalization::{normalize_name, tokenize};
|
||||
use crate::record::{
|
||||
ACTIVE_RECORD_TTL, DhtKey, MAX_ITEM_NAME_BYTES, MAX_TOKENS_PER_ITEM, StoredRecord,
|
||||
TOMBSTONE_TTL,
|
||||
ACTIVE_RECORD_TTL, DhtKey, MAX_ARTISTS_PER_ITEM, MAX_ITEM_NAME_BYTES, MAX_TOKENS_PER_ITEM,
|
||||
StoredRecord, TOMBSTONE_TTL,
|
||||
};
|
||||
|
||||
/// Outcome of comparing an incoming record with the stored one.
|
||||
@@ -59,9 +59,9 @@ pub fn decide_store(existing: Option<(u64, bool, u64)>, incoming: &StoredRecord)
|
||||
/// Validates an incoming `StoreRecord` request.
|
||||
///
|
||||
/// Checks the size limits, that the record is internally consistent, that the
|
||||
/// key actually corresponds to the record's name or one of its tokens, and
|
||||
/// clamps the expiry to the maximum TTL allowed for the record type. Returns
|
||||
/// the record with a possibly clamped `expires_at_ms`.
|
||||
/// key actually corresponds to the record's name, or one of the item's/artist's
|
||||
/// search tokens, and clamps the expiry to the maximum TTL allowed for the
|
||||
/// record type. Returns the record with a possibly clamped `expires_at_ms`.
|
||||
pub(crate) fn validate_store(
|
||||
request: StoreRecordRequest,
|
||||
network_id: &NetworkId,
|
||||
@@ -83,9 +83,21 @@ pub(crate) fn validate_store(
|
||||
if tokens.len() > MAX_TOKENS_PER_ITEM {
|
||||
return Err("too many tokens".into());
|
||||
}
|
||||
if item.artist_names.len() > MAX_ARTISTS_PER_ITEM {
|
||||
return Err("too many artists".into());
|
||||
}
|
||||
for artist in &item.artist_names {
|
||||
if artist.len() > MAX_ITEM_NAME_BYTES {
|
||||
return Err("artist name too long".into());
|
||||
}
|
||||
if tokenize(&normalize_name(artist)).len() > MAX_TOKENS_PER_ITEM {
|
||||
return Err("artist name has too many tokens".into());
|
||||
}
|
||||
}
|
||||
|
||||
let key_matches = request.key == DhtKey::exact(network_id, &item.normalized_name)
|
||||
|| tokens
|
||||
|| item
|
||||
.search_tokens()
|
||||
.iter()
|
||||
.any(|token| request.key == DhtKey::token(network_id, token));
|
||||
if !key_matches {
|
||||
@@ -138,6 +150,28 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn track_with_artist(expires_at_ms: u64) -> StoredRecord {
|
||||
let owner = test_peer(1);
|
||||
StoredRecord {
|
||||
item: LibraryItem {
|
||||
id: ItemId::from_bytes([8u8; 32]),
|
||||
owner,
|
||||
kind: crate::record::ItemKind::Track,
|
||||
name: "Teardrop".into(),
|
||||
normalized_name: "teardrop".into(),
|
||||
artist_names: vec!["Massive Attack".into()],
|
||||
year: Some(1998),
|
||||
release_type: None,
|
||||
duration_seconds: Some(330.0),
|
||||
revision: 1,
|
||||
deleted: false,
|
||||
updated_at_ms: 0,
|
||||
},
|
||||
publisher: owner,
|
||||
expires_at_ms,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newer_revision_replaces_older() {
|
||||
let incoming = record(2, false, 1000);
|
||||
@@ -273,4 +307,34 @@ mod tests {
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_accepts_artist_token_keys() {
|
||||
let net = NetworkId::from_name("test");
|
||||
let now = 1_000_000;
|
||||
let rec = track_with_artist(now + ACTIVE_RECORD_TTL.as_millis() as u64);
|
||||
|
||||
assert!(
|
||||
validate_store(
|
||||
StoreRecordRequest {
|
||||
key: DhtKey::token(&net, "massive"),
|
||||
record: rec.clone(),
|
||||
},
|
||||
&net,
|
||||
now,
|
||||
)
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
validate_store(
|
||||
StoreRecordRequest {
|
||||
key: DhtKey::token(&net, "attack"),
|
||||
record: rec,
|
||||
},
|
||||
&net,
|
||||
now,
|
||||
)
|
||||
.is_ok()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user