Commit Graph
15 Commits
Author SHA1 Message Date
Michel de Graaf 2918b0ce75 refactor: resolve all lint findings
- remove 34 trivial restating comments (auto-fix)
- replace all 20 production .unwrap() calls with graceful handling:
  ?-propagation via LockPoisoned, unwrap_or_default on infallible
  conversions, let _ = on actor-channel sends, and a downloads_sender()
  helper in the TUI that also dedupes three channel-init blocks
- collapse nested if into match guard (clippy::collapsible_match)
- split client.rs (2275 lines) into a client/ module: connection,
  search, downloads, uploads, rooms, operations
- split ui/main_tui.rs (2027 lines) into a main_tui/ module: render,
  input, browse, rooms, downloads, search
- extract oversized functions: peer_actor/server_actor handle_message
  into per-message helpers, main() into init_logging/run_default_tui,
  download_selector and main_tui render into per-section helpers

Mechanical only, zero behavior change. Verified: clippy clean
(pedantic+nursery), fmt clean, 143 unit tests + 16 e2e tests against
soulfind pass, lint clean.
2026-07-20 10:53:57 +02:00
michel 9794fe0786 feat(shares): add a std-only zlib stored-block encoder
Soulseek peer messages (SharedFileListResponse, FileSearchResponse) are
zlib-compressed on the wire, but the library only had a decoder. Add
compress_stored(): a valid zlib stream built entirely from uncompressed
DEFLATE 'stored' blocks (0x78 0x01 header, blocks of <= 0xFFFF bytes, adler32),
which needs no real compressor and is accepted by standard decoders and by the
existing inflate path. Roundtrip-tested through the decoder at block
boundaries, plus header/adler32 vectors.
2026-07-19 18:28:56 +02:00
michel e72c8a5c07 style: crank clippy to pedantic+nursery and fix all lints
Enable the full clippy all + pedantic + nursery groups as workspace warnings,
with a small documented allow-list for the pedantic/nursery lints this project
intentionally does not follow (rustdoc-style requirements, deliberate numeric
casts in the protocol/UI layers, and a few noisy nursery lints). Also enable
the rust unused_lifetimes and unsafe_op_in_unsafe_fn lints.

Fixed every resulting warning (527 -> 0) mechanically per clippy's suggestions:
inline format args, const fns, item ordering, let-else, redundant clones,
map_or, cast_lossless, Eq derives, associated-fn conversions for methods that
never used self, and removing unnecessary Result wrappers whose call sites could
never propagate an error. No runtime behavior changed; cargo fmt applied.

cargo clippy --workspace --all-targets: 0 warnings. All tests pass.
2026-07-19 00:09:17 +02:00
michel 846d9750b4 fix: stop duplicating every log line to the file
When log buffering and a LOG_FILE were both active, log() wrote each line to
the file immediately and also pushed it to the buffer, which flush_buffered_logs
then wrote to the file a second time. Each line now routes to exactly one sink
(file / buffer / stderr) via a small tested decision function; a configured
file always bypasses buffering, so nothing is written twice.
2026-07-18 14:33:39 +02:00
michel ce244e4e91 fix: contain panicking jobs so a thread-pool worker is never lost
A job that panicked unwound out of the worker's run loop and permanently
killed that worker; the pool has a fixed worker count and never respawns, so
repeated panics (e.g. from malformed network messages) would exhaust the pool
and wedge the whole actor system — a DoS. The worker now runs each job under
catch_unwind (the shared receiver lock is already released, so a panic cannot
poison it) and survives to process the next job. Drop and execute no longer
unwrap their channel/join results, so shutdown can never itself panic.
2026-07-18 14:33:39 +02:00
michel 16af88eb9d fix: error on degenerate Huffman code in zlib inflate instead of panicking
decode_symbol walked the Huffman tree while either child existed, then
unwrapped the child selected by the current bit. A malformed/incomplete code
table (fully attacker-controlled, since search results arrive zlib-compressed
from peers) can leave a node with only one child; reading the opposite bit
unwrapped None and panicked, unwinding out of the actor job. It now returns a
decode error, which propagates as a CompressionError and is handled gracefully.
2026-07-18 14:23:40 +02:00
michel 44846cdfa8 chore: remove dead code and stale comments
- Drop dead Rooms/Room infrastructure and the rooms field on Context.
- Remove unused ActorMessage::Tick variant and the now-empty handler arm.
- Strip dead active-thread tracking machinery from ThreadPool (unused
  getters, _id/_active_threads/_total_threads parameters).
- Flatten ServerActor::initiate_connection: the duplicated retry block
  was a copy-paste retry against the same address with the same args
  and could never succeed where the first attempt failed.
- Delete commented-out print_hex2/decode debug stubs, dead test
  fixtures in login.rs and message_user.rs, the 47-line commented body
  of RoomListHandler, and assorted // TODO theater.
2026-04-26 17:20:45 +02:00
michel 574833bf61 feat: add download info pane to TUI
Splits the downloads area 60/40 with a new info pane that adapts to the
selected download's status: header (filename, user, size, status, save
path, bitrate, length) plus queued-specific fields (queue position, peer
slots, peer upload speed) or live progress/speed/ETA when transferring.

Plumbs queue position via a new ClientOperation::PlaceInQueueUpdate so
PlaceInQueueResponse messages from peers reach DownloadStore, and threads
search-time metadata (bitrate, length, peer slots/speed) onto Download
through a new download_with_metadata entry point.
2026-04-26 17:19:26 +02:00
michel 2722552e35 refactor: replace lock unwraps with poison-aware helpers
Add SoulseekRs::LockPoisoned variant and a small RwLockExt/MutexExt
helper module exposing read_safe/write_safe/lock_safe that map
PoisonError to that variant. Walk every non-test lock acquisition
across client, peer/server actors, peer registry, listener and the
thread pool: propagate via ? where the function returns Result, log
and degrade to a sensible default (return early, false, None, empty)
where it does not. Client::connect now returns Result so the CLI can
surface the failure instead of panicking.
2026-04-26 12:32:46 +02:00
Michel de Graaf dfe6f532fa chore: formatting 2026-01-04 20:37:03 +01:00
mayor 16c8a4bde9 chore: update to Rust 2024 edition 2026-01-04 20:08:16 +01:00
Michel de Graaf 9f174c4c5e fix: linting 2025-11-19 08:40:41 +01:00
Michel de Graaf 2ba48663e4 feat: logging to log file 2025-11-18 15:49:53 +01:00
Michel de Graaf 98a8f53094 feat: improved cli 2025-11-11 23:38:59 +01:00
Michel de Graaf 7bf2748e1f feat: seperate into lib and cli packages 2025-11-11 21:55:53 +01:00