A caller that gives up on a login had no way to reach the client: the thread that owns it sits in login() for up to 45 seconds, and disconnect() needs the client to itself. Until that thread returned, the abandoned client kept connecting and still wrote its login frame the moment the server finished the TCP handshake. When that happened after a replacement had logged in under the same name, the server kicked the replacement. Client::cancel_handle() hands out a CancelHandle that can be moved to any thread. After cancel(): - the server actor writes nothing more. The check and the write share a lock with cancel(), so once cancel() returns no frame leaves, whether it was waiting in the queue, in the dispatcher channel, or mid-flush; - login() returns NotConnected within 100 ms, and hands no login to the actor at all when the client was already cancelled; - connect() refuses before binding the listener when the client was already cancelled. A cancel that lands during that check can still let the bind through. Either way the owner drops the client as before, which disconnects it and gives its port back. A frame already written before cancel() returned cannot be recalled. The API is additive, and login() on a client nobody cancels behaves as before. Soulseek.NET tears the whole connection down when ConnectAsync is cancelled, and Nicotine+ drops outgoing messages for a socket it closed; this gives soulseek-rs the same end state from another thread.
45 lines
1.7 KiB
Rust
45 lines
1.7 KiB
Rust
// The README is the crate's front page, and `cargo test --doc` compiles every
|
|
// example in it, so a signature change cannot leave the advertised usage stale.
|
|
#![doc = include_str!("../README.md")]
|
|
|
|
// The public surface is the client, its types, the wire codec and the share
|
|
// index. The actors, dispatcher, peer plumbing and download store are how the
|
|
// client is built, not what a host programs against, so they stay inside the
|
|
// crate and a change to them is not a change to the library's API.
|
|
pub(crate) mod actor;
|
|
pub mod client;
|
|
pub(crate) mod dispatcher;
|
|
pub(crate) mod download_store;
|
|
pub mod error;
|
|
pub mod message;
|
|
pub(crate) mod peer;
|
|
pub mod shares;
|
|
pub mod types;
|
|
#[macro_use]
|
|
pub mod utils;
|
|
|
|
// Prelude module for commonly used items
|
|
pub mod prelude {
|
|
pub use crate::actor::server_actor::PeerAddress;
|
|
pub use crate::types::{
|
|
ClientVersion, DownloadStatus, File, Recommendation, RoomEvent,
|
|
RoomInfo, RoomTicker, Search, SearchResult, SimilarUser, Transfer,
|
|
UploadInfo, UploadStatus, UserInfo, UserInterests, UserPresence,
|
|
UserStats, UserStatus,
|
|
};
|
|
pub use crate::{debug, error, info, trace, warn};
|
|
}
|
|
|
|
// Re-export commonly used types
|
|
pub use actor::server_actor::{PeerAddress, UserMessage};
|
|
pub use client::{CancelHandle, Client, ClientSettings};
|
|
pub use error::{Result, SoulseekRs};
|
|
pub use message::peer::{SharedDirectory, SharedFileEntry};
|
|
pub use peer::{ConnectionType, ParseConnectionTypeError};
|
|
pub use types::{
|
|
ClientVersion, DownloadStatus, File, Recommendation, RoomEvent, RoomInfo,
|
|
RoomTicker, Search, SearchResult, SessionLoss, SimilarUser, Transfer,
|
|
UploadInfo, UploadStatus, UserInfo, UserInterests, UserPresence, UserStats,
|
|
UserStatus,
|
|
};
|