michel b82b03a143 feat: firewalled peer connections via server-brokered connect
Implement the FIREWALLED connection mode: when a direct outbound connection to
a peer fails (peer unreachable), fall back to asking the server to broker it.

- Add MessageFactory::build_connect_to_peer (server code 18).
- A pre-established outbound failure now emits ClientOperation::PeerConnectFailed
  instead of a normal disconnect; the client registers a correlation token and
  sends ConnectToPeer so the peer connects back.
- The listener accepts the peer's PierceFirewall (peer code 0) connect-back,
  matches the pending token, registers it as the P control connection, and
  fires PeerConnected to flush the queued download.

Fix a latent aliasing bug this surfaced: a peer actor could emit two terminal
notifications (a connect-failure, then a disconnect when later replaced and
stopped), and the second removed the *newer* actor registered under the same
username, killing the brokered connection mid-transfer. An actor now reports a
terminal outcome at most once (disconnect_reported guard).

Verified end to end against soulfind: the mock advertises an unlistened port so
the direct connect is refused, the server brokers the connection, the mock
pierces back, and the file transfers — bytes match. A companion test
(soulfind_brokers_connect_to_peer_between_users) pins the server behaviour the
mode relies on.
2026-07-19 17:26:52 +02:00
2025-11-12 15:38:29 +01:00
2024-09-09 08:32:51 +02:00
2026-04-26 12:00:24 +02:00
2025-07-31 20:06:41 +02:00

Soulseek-rs 🦀

⚠️WARNING THIS IS UNDER DEVELOPMENT AND NOT READY FOR USE ⚠️

Souleek-rs is an experimental Soulseek library and client built in Rust. It's under development and not yet ready for use. Soulseek is a closed-source P2P file-sharing network from the 2000s. It's still used by music enthusiasts around the world to share niche music.

🎥 Demo

CLI Demo

Project Goals

This project is a learning exercise to explore Rust. I've been using Soulseek since the early 2000s, so it's close to my heart, and the Soulseek protocol is a closed-source network protocol that provides a great opportunity to learn about asynchronous and concurrent network programming and reverse engineering

It's not intended to be a production-ready client (yet).

Since it's a learning project, I have a self-imposed restriction not to use external dependencies in the library. This means I can't use any external crates that are not part of the Rust standard library. This is a good challenge to learn how to build complex systems with only the standard library.

In the client crate, external dependencies are allowed for building a rich experience. For me, this is a good balance between learning and practicality.

Planned Features

  • Search for files
  • Download files
  • Configure credentials
  • TUI for searching and downloading files
  • Configure download & upload directories
  • Share files
  • Browse user(s) files
  • Chat in chatrooms
  • Private messaging
  • Headless mode daemon mode with remote control

Project Structure

This project is organized as a Cargo workspace with two crates:

  • soulseek-rs-lib - The core library implementing the Soulseek protocol
  • soulseek-rs - A CLI client built on top of the library

This structure allows:

  • Other developers to build custom Soulseek clients using soulseek-rs-lib
  • Users to install the ready-made client via cargo install soulseek-rs
  • Clean separation of concerns between protocol implementation and user interface

Installation

For Users

cargo install soulseek-rs

For Developers

Clone and build from source:

git clone git@github.com:michel/soulseek-rs.git
cd soulseek-rs
cargo build --release

The binary will be available at target/release/soulseek-rs.

For Library Users

To build your own Soulseek client, add to your Cargo.toml:

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

Usage

./target/release/soulseek-rs "the weeknd Blinding Lights"

Private messages

Send a private message to another user from the command line:

soulseek-rs message <username> "hello there"

In the interactive TUI:

  • press m to compose — type <recipient> <message> and Enter to send;
  • press i to open the inbox popup listing sent and received messages (incoming messages arrive automatically while the TUI is open).

Development

To run the project in development mode with debug output and trace output:

RUST_LOG=trace cargo run

Development

To run the tests:

cargo test

To run the linter:

cargo clippy

To run the formatter:

cargo fmt

End-to-end tests

The soulseek-rs-lib/tests/e2e.rs suite exercises the client against a real Soulseek server using soulfind, a local server implementation. The tests are server-optional: they run when a server is available and otherwise skip (so cargo test stays green everywhere).

They locate a server in this order:

  1. SOULSEEK_TEST_SERVER=host:port — connect to an already-running server, or
  2. SOULFIND_BIN=/path/to/soulfind (or a soulfind/bin/soulfind checkout in a parent directory) — spawn soulfind on an ephemeral port with a throwaway database.
# Build soulfind once (see its BUILDING.md), then:
SOULFIND_BIN=/path/to/soulfind/bin/soulfind \
  cargo test -p soulseek-rs-lib --test e2e -- --nocapture

On macOS, soulfind's SQLITE_CONFIG_SINGLETHREAD optimization is rejected by the system SQLite; building soulfind with that call made non-fatal lets it run locally. It is only a mutex optimization and does not affect the server.

Set SOULSEEK_E2E_REQUIRED=1 to turn a missing server into a hard failure instead of a skip. Continuous integration sets it so the e2e suite genuinely runs against a freshly built soulfind rather than silently skipping.

Continuous integration

.github/workflows/ci.yml runs on every push and pull request:

  • Format & Clippy — cargo fmt --all --check and cargo clippy --workspace --all-targets -- -D warnings.
  • Test — builds soulfind from source (LDC + dub build :server), points SOULFIND_BIN at it, and runs cargo test --workspace with SOULSEEK_E2E_REQUIRED=1, so unit and end-to-end tests both run.

License

This project is licensed under the MIT License — see the LICENSE file for details.

S
Description
repo for improving soulseek-rs with qol features.
Readme MIT
5.2 MiB
Languages
Rust 92.5%
TypeScript 6%
Shell 1.1%
CSS 0.2%