fix(messages): acknowledge stored private messages, and disconnect cleanly
Two bugs an e2e test found the moment one existed for this path. A private message the server held while we were offline arrives with new_message false, and the handler only acknowledged the ones flagged new — so exactly the messages that need an ack never got one and the server re-delivered them at every login, forever. Every delivery is now acknowledged. A dropped Client also left its server connection open, so the session lived on: mail addressed to us went to a socket nobody was reading and a later login collided with our own ghost. Client::disconnect closes the server and peer connections, and Drop calls it. Also covers two features that were never driven end to end: an offline message delivered once and not again, and a wishlist search answered like any other.
This commit is contained in:
@@ -133,6 +133,30 @@ impl Client {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close the server connection and every peer connection.
|
||||
///
|
||||
/// The server sees the socket close and marks us offline, which is what
|
||||
/// releases the username: a client that simply goes out of scope without
|
||||
/// this leaves a session the server still believes in, so mail addressed
|
||||
/// to us is delivered to a connection nobody is reading and later logins
|
||||
/// collide with our own ghost.
|
||||
///
|
||||
/// Called automatically when the client is dropped. The peer listener's
|
||||
/// bound port, if one was opened, is released with the process.
|
||||
pub fn disconnect(&mut self) {
|
||||
if let Some(handle) = self.server_handle.take() {
|
||||
let _ = handle.stop();
|
||||
}
|
||||
let registry = self
|
||||
.context
|
||||
.read_safe()
|
||||
.ok()
|
||||
.and_then(|ctx| ctx.peer_registry.clone());
|
||||
if let Some(registry) = registry {
|
||||
registry.stop_all();
|
||||
}
|
||||
}
|
||||
|
||||
/// Log in and wait for the server's verdict.
|
||||
///
|
||||
/// The wait is bounded: the actor only answers once it has a working
|
||||
|
||||
@@ -1163,6 +1163,12 @@ pub struct Client {
|
||||
session: SessionWatch,
|
||||
}
|
||||
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
self.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(
|
||||
username: impl Into<String>,
|
||||
|
||||
@@ -551,7 +551,7 @@ fn an_expired_broker_connect_fails_the_queued_downloads() {
|
||||
let (_ops_tx, ops_rx) = mpsc::channel();
|
||||
Client::listen_to_client_operations(
|
||||
ops_rx,
|
||||
client.context,
|
||||
client.context.clone(),
|
||||
"u".to_string(),
|
||||
);
|
||||
|
||||
@@ -582,7 +582,7 @@ fn a_replayed_transfer_response_does_not_start_a_second_transfer() {
|
||||
let (ops_tx, ops_rx) = mpsc::channel();
|
||||
Client::listen_to_client_operations(
|
||||
ops_rx,
|
||||
client.context,
|
||||
client.context.clone(),
|
||||
"u".to_string(),
|
||||
);
|
||||
|
||||
@@ -648,7 +648,7 @@ fn a_cancelled_download_is_not_started_when_the_peer_allows_it() {
|
||||
let (ops_tx, ops_rx) = mpsc::channel();
|
||||
Client::listen_to_client_operations(
|
||||
ops_rx,
|
||||
client.context,
|
||||
client.context.clone(),
|
||||
"u".to_string(),
|
||||
);
|
||||
let peer = Peer::new(
|
||||
|
||||
Reference in New Issue
Block a user