feat(protocol): away status, excluded phrases, queue-place requests
Three features the client half-had. SetStatus (28) was only ever sent as "online" at login, so there was no way to go away; excluded search phrases (160) were parsed and logged into nowhere, so every client kept spending searches on queries the server was never going to answer; and a queued download could answer a peer asking about its place but could never ask about its own. Each is now driven end to end: the away status seen by another user, a refused query on a stub server that announces phrases (soulfind keeps its filters in a database the suite cannot seed), and a peer's answer landing on the download as its queue position.
This commit is contained in:
@@ -62,6 +62,9 @@ impl Client {
|
||||
let Some(handle) = &self.server_handle else {
|
||||
return Err(SoulseekRs::NotConnected);
|
||||
};
|
||||
if let Some(phrase) = self.excluded_phrase_in(query) {
|
||||
return Err(SoulseekRs::SearchPhraseExcluded(phrase));
|
||||
}
|
||||
let token = next_search_token();
|
||||
|
||||
self.context.write_safe()?.searches.insert(
|
||||
@@ -119,6 +122,9 @@ impl Client {
|
||||
if self.server_handle.is_none() {
|
||||
return Err(SoulseekRs::NotConnected);
|
||||
}
|
||||
if let Some(phrase) = self.excluded_phrase_in(query) {
|
||||
return Err(SoulseekRs::SearchPhraseExcluded(phrase));
|
||||
}
|
||||
let token = next_search_token();
|
||||
self.context.write_safe()?.searches.insert(
|
||||
query.to_string(),
|
||||
@@ -130,6 +136,26 @@ impl Client {
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
/// The phrases the server refuses to search for (code 160), as last
|
||||
/// announced. Empty until the server has said.
|
||||
#[must_use]
|
||||
pub fn excluded_search_phrases(&self) -> Vec<String> {
|
||||
self.context
|
||||
.read_safe()
|
||||
.map(|ctx| ctx.excluded_search_phrases())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// The excluded phrase `query` carries, if any — what a search would be
|
||||
/// refused for.
|
||||
#[must_use]
|
||||
pub fn excluded_phrase_in(&self, query: &str) -> Option<String> {
|
||||
self.context
|
||||
.read_safe()
|
||||
.ok()
|
||||
.and_then(|ctx| ctx.excluded_phrase_in(query))
|
||||
}
|
||||
|
||||
/// Let responses accumulate for `timeout`, or until cancelled.
|
||||
///
|
||||
/// Peers answer a search over their own connections whenever they get round
|
||||
|
||||
Reference in New Issue
Block a user