Files
soulseek-rs-modded/soulseek-rs-lib
michel ea25325e68 fix: reap failed outbound peer actors and bound the brokered connect
Two related lifecycle defects in the direct/firewalled download path:

- On a failed direct connect, ClientOperation::PeerConnectFailed left the dead
  outbound actor registered and running. The actor pinned a thread-pool worker
  forever (its loop only exits on Stop), so a handful of unreachable-peer
  downloads could exhaust the fixed pool and wedge the whole client; and a
  later download() to the same peer saw registry.contains()==true and queued
  into the dead, streamless actor, hanging silently. The arm now removes and
  stops the dead actor before brokering, mirroring PeerDisconnected.

- The server-brokered fallback had no timeout, so a peer that never connects
  back (offline / double-firewalled / unroutable address) left the download
  Queued forever and its Receiver blocked. Arm a bounded timeout: if no
  PierceFirewall consumes the correlation token within BROKER_CONNECT_TIMEOUT,
  fail the peer's queued downloads (on the channel and in the store) and
  reclaim the token. A successful pierce consumes the token first, so the
  timeout is a no-op on the happy path.

Add a unit test for the queued-download failure helper; the direct and
firewalled e2e tests still pass (pierce arrives well within the timeout).
2026-07-19 17:47:45 +02:00
..
2025-11-11 22:22:21 +01:00

soulseek-rs-lib

A Rust library for implementing the Soulseek peer-to-peer protocol.

About

This library provides the core functionality for interacting with the Soulseek network. It can be used to build custom Soulseek clients or bots.

Usage

Add this to your Cargo.toml:

[dependencies]
soulseek-rs-lib = "0.1.0"

Example

Simple Usage

use soulseek_rs::Client;
use std::time::Duration;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create and connect to Soulseek server
    let mut client = Client::new("username", "password");

    client.connect();
    client.login()?;

    // Search for files
    let results = client.search("Alex Kassian lifestream", Duration::from_secs(10))?;

    // Download first available file
    if let Some(result) = results.iter().find(|r| !r.files.is_empty()) {
        let file = &result.files[0];
        client.download(
            file.name.clone(),
            file.username.clone(),
            file.size,
            "~/Downloads".to_string(),
        )?;
        println!("Downloaded: {}", file.name);
    }

    Ok(())
}

Advanced Configuration

use soulseek_rs::{Client, ClientSettings, PeerAddress};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create client with custom settings
    let settings = ClientSettings {
        server_address: PeerAddress::new("server.slsknet.org".to_string(), 2242),
        enable_listen: true,
        listen_port: 3000,
        ..ClientSettings::new("username", "password")
    };

    let mut client = Client::with_settings(settings);
    client.connect();
    client.login()?;

    Ok(())
}