fix: review findings on the protocol work
Correctness: - A child that stopped reading could freeze the whole client: the relay writes under the context lock and the socket was blocking, so one stalled peer took every download, upload and API call with it. Child writes now have a deadline, and a child that hits it loses its slot. - Relaying searches to children was gated by the leaf's answer budget, so a parent forwarded a fraction of the stream while advertising itself as healthy. The budget bounds our own share scan, which is what it was for; the tree's stream goes down whole. - A dropped client kept its listener port for the life of the process, so a retried login advertised an ephemeral port nobody was told about. The listener is now stopped and the operations thread let go. - Excluded phrases were compared against a lowercased path without being lowercased themselves, so a capitalised phrase never matched. They are normalised where they arrive. - Losing our own operatorship wiped the room's whole operator roster, though we are still a member who can see it. - A brokered ConnectToPeer of type D was logged and dropped; the peer is now told, since we never dial out to adopt a child. - A peer request made with no server connection returned Ok and parked forever; it says NotConnected, as its docs always claimed. - An empty interest was refused locally but still sent, leaving the server's list and ours permanently apart. Simplification: - Deleted the excluded-phrase helper nothing called, and the field doc that promised behaviour it never had. - The four roster handlers and four standing handlers were eight constructors carrying constants their own message code already implies: one newtype each, 100 lines less. - One place registers a search; the phrase list is borrowed, not cloned per relayed search.
This commit is contained in:
@@ -301,7 +301,11 @@ impl Client {
|
||||
/// # Errors
|
||||
/// [`crate::SoulseekRs::NotConnected`] when there is no server connection.
|
||||
pub fn add_interest(&self, item: &str) -> Result<()> {
|
||||
let item = self.context.write_safe()?.add_own_interest(item, true);
|
||||
let Some(item) =
|
||||
self.context.write_safe()?.add_own_interest(item, true)
|
||||
else {
|
||||
return Ok(()); // nothing to like or unlike
|
||||
};
|
||||
self.send_server_message(MessageFactory::build_add_thing_i_like(&item))
|
||||
}
|
||||
|
||||
@@ -310,7 +314,11 @@ impl Client {
|
||||
/// # Errors
|
||||
/// [`crate::SoulseekRs::NotConnected`] when there is no server connection.
|
||||
pub fn remove_interest(&self, item: &str) -> Result<()> {
|
||||
let item = self.context.write_safe()?.remove_own_interest(item, true);
|
||||
let Some(item) =
|
||||
self.context.write_safe()?.remove_own_interest(item, true)
|
||||
else {
|
||||
return Ok(()); // nothing to like or unlike
|
||||
};
|
||||
self.send_server_message(MessageFactory::build_remove_thing_i_like(
|
||||
&item,
|
||||
))
|
||||
@@ -321,7 +329,11 @@ impl Client {
|
||||
/// # Errors
|
||||
/// [`crate::SoulseekRs::NotConnected`] when there is no server connection.
|
||||
pub fn add_dislike(&self, item: &str) -> Result<()> {
|
||||
let item = self.context.write_safe()?.add_own_interest(item, false);
|
||||
let Some(item) =
|
||||
self.context.write_safe()?.add_own_interest(item, false)
|
||||
else {
|
||||
return Ok(()); // nothing to like or unlike
|
||||
};
|
||||
self.send_server_message(MessageFactory::build_add_thing_i_hate(&item))
|
||||
}
|
||||
|
||||
@@ -330,7 +342,11 @@ impl Client {
|
||||
/// # Errors
|
||||
/// [`crate::SoulseekRs::NotConnected`] when there is no server connection.
|
||||
pub fn remove_dislike(&self, item: &str) -> Result<()> {
|
||||
let item = self.context.write_safe()?.remove_own_interest(item, false);
|
||||
let Some(item) =
|
||||
self.context.write_safe()?.remove_own_interest(item, false)
|
||||
else {
|
||||
return Ok(()); // nothing to like or unlike
|
||||
};
|
||||
self.send_server_message(MessageFactory::build_remove_thing_i_hate(
|
||||
&item,
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user