Skip to content

Releases: MochengCK/XferRust

v0.3.2

Choose a tag to compare

@github-actions github-actions released this 20 Sep 10:02

XferRust v0.3.2 Release Notes

English | 简体中文

Summary

  • Fixed HTTP segmented downloads stalling for over ten seconds at 99%: when the last segment's connection went silent, the whole task sat at 99% with zero speed until the regular read-idle timeout (10s) fired, and the tail now uses a shorter timeout

Bug Fixes

  • Fixed HTTP segmented downloads stalling for over ten seconds at 99%: the read-idle timeout was a flat 10s, so once the last segment's connection went silently dead (no data and no FIN), every other worker was already parked and the task sat at 99% with zero speed until the 10s timeout fired and the segment was reconnected from its received watermark — with backoff and reconnect, users saw the progress freeze for over ten seconds (most visible near the end, when no other worker is pulling data). The tail now switches to a 3s read-idle timeout once the remaining bytes drop below the end-game threshold (8MiB), so a dead connection is dropped and reconnected much sooner and the final pause drops from over ten seconds to a few

Behavior Changes

  • The read-idle timeout during the end game (8MiB or less remaining) is tightened from 10s to 3s: slow servers that deliver the tail in bursts may now be disconnected and reconnected a few extra times (a short read does not consume the fatal failure budget, and the segment resumes from the bytes already received, so the task does not fail). Behavior in the middle of a download is unchanged

XferRust v0.3.2 发布说明

English | 简体中文

摘要

  • 修复 HTTP 分片下载收尾阶段「卡在 99% 十几秒」:最后一个分片的连接僵死时,整条任务停在 99% 零速直到常规读空闲超时(10s)才断开重连,现尾声改用更短的超时

问题修复

  • 修复 HTTP 分片下载收尾阶段「卡在 99% 十几秒」:分片下载的读空闲超时统一为 10s,而收尾时最后一个分片的连接一旦静默僵死(对端无数据也无 FIN),其余协程早已全部停靠,整条任务就停在 99% 零速,直到 10s 超时触发才断开、从已收水位重连续传——加上退避与重连,使用者看到的就是十几秒不动(剩余越少越明显,因为此时没有任何其他协程在拉数据);现剩余待下字节进入尾声门槛(≤ 8MiB)后改用 3s 读空闲超时,僵死连接更早被断开重连,收尾停顿由十几秒降到数秒

行为变更

  • 尾声(剩余 ≤ 8MiB)的读空闲超时由 10s 收紧到 3s:尾部「突发式发数据」的慢服务器可能被多断开几次重连(短读不消耗致命失败预算,断开后从已收水位续传,不会导致任务失败),下载中段的行为不变

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 19 Sep 23:55

XferRust v0.3.1 Release Notes

English | 简体中文

Summary

  • Fixed BT public-swarm downloads being far slower than other clients (same public torrent: <1 MB/s → 17.1 MB/s peak): three root causes — IPv6 peers dropped by trackers, DHT dual-stack binding always failing, and DHT queries always timing out
  • IPv6 coverage completed: bare IPv6 literals in non-compact tracker peer lists and the BEP 32 peers6 field, IPv4 + IPv6 announces per tracker merged and deduplicated, and dual-stack uTP / UDP tracker / BT listening (none of which could even start on IPv6 hosts)
  • HTTPS now also trusts the local system root store (corporate proxies and private CAs no longer fail across the board) and no-proxy really takes effect
  • Fixed HTTP split downloads reporting success without downloading a single byte when the control file's segment table is unusable (leaving a truncated file behind while showing as complete); the resume bitfield no longer runs ahead of disk, so a crash recovery with disk-cache no longer reproduces "completed holes"
  • Fixed three DHT protocol errors: responses not validated against the source address (guessing a 16-bit transaction id was enough to inject a forged one), announce_peer always sent with implied_port=1 (making the remote node record our DHT port as our BT port), and get_peers encoding IPv6 peers as 0.0.0.0
  • Fixed the on-disk layout of multi-file torrents with exactly one file (the file was written as <name>, occupying what should be the directory name; data downloaded by older versions migrates automatically) and the files[].path / task.verifyFiles path for single-file torrents (<name>/<name><name>)
  • Fixed NAT-PMP TCP port mapping never working (opcode 6 → 2 per RFC 6886), DHT routing-table persistence always panicking, and peer-id generation panicking whenever a version component has two digits
  • Faster cold start and lower idle cost: DHT query timeout 10s → 3s with bootstrap and one iteration of find_node running concurrently, and release builds optimized for speed (see "Build & Release")

New Features

  • Per-task custom request headers are now actually sent: the header option (an array like ["Referer: https://…", "Cookie: a=b"], or a single CRLF/LF-separated string) and the referer / user-agent convenience keys are applied to real HTTP requests — previously they were collected into the task's options and never used when downloading (callers believed they were sent, but they were silently dropped), so every URL that requires Referer / Cookie failed with 403. The probe, single-connection and multi-connection split paths all use the same set (sending them on the download but not on the probe makes the probe 403 and misjudge the total length and Range support); Range / Host / Content-Length / Connection / Accept-Encoding are always ignored (overriding them breaks segmenting, resume and virtual-host routing), and Origin is never injected

Bug Fixes

  • Fixed IPv6 addresses in non-compact peer lists being dropped: the address and port were concatenated into ip:port and re-parsed, which always fails for bare IPv6 literals (the port gets swallowed into the address) and discarded the whole peer; peers are now parsed from the IP literal with the port assembled afterwards, so a single invalid entry only skips that entry
  • Fixed the tracker peers6 field being ignored: added BEP 32 compact parsing (18 bytes per entry = 16-byte IPv6 + 2-byte port, port 0 dropped), with a ragged tail truncated and warned about
  • Fixed never obtaining IPv6 seeders: hostnames resolve to IPv4 first, so announces were always sent over IPv4 while trackers only return IPv6 peers to IPv6 sources (BEP 7); every tracker is now announced to over both IPv4 and IPv6 concurrently with the results merged and deduplicated — skipped automatically when the host has no IPv6 address or is a bare IP, and the IPv6 result is used as a fallback when the IPv4 announce fails
  • Fixed DHT dual-stack nodes always failing to start on macOS: the [::] bind address was handed to the resolver as a hostname (and then fell back to IPv4-only); it is now parsed as an IP literal (brackets stripped)
  • Fixed address-family mismatch when sending from / receiving on a dual-stack DHT socket: IPv4 destinations are converted to v4-mapped before sending and v4-mapped sources are normalized back to IPv4, keeping the routing table, known_peers and peer addresses handed to BT as IPv4
  • Fixed every DHT KRPC query timing out: callers raced the resident receive loop for the same socket, and responses picked up by the loop were parsed as queries, failed, and silently discarded, leaving callers to time out; pending queries are now registered as "transaction id → channel" and the receive loop dispatches responses by tid (the entry is removed on send failure or timeout)
  • Fixed slow DHT cold start: find_node queries for all bootstrap nodes and one iteration now run concurrently
  • Fixed uTP being unable to talk to IPv6 peers: the uTP socket was bound to IPv4 only, and on a dual-stack listener every send to an IPv6 / IPv4 peer needs an address-family conversion — without it sendto fails with Invalid argument (os error 22) and the uTP dial to an IPv6 peer can never succeed (each peer wastes a full handshake timeout, measured at 3s per peer, before falling back to TCP); the socket is now bound dual-stack to [::] with v4-mapped conversion on both send and receive
  • Fixed BT being unable to listen on IPv6-only hosts (or without IPv6): the TCP listener was bound to 0.0.0.0 (tasks failed to start at all on IPv6-only hosts, and dual-stack hosts never received IPv6 inbound connections); it now prefers the dual-stack [::] and adds a plain IPv4 listener on systems with IPV6_V6ONLY=1 (e.g. the Windows default); the conflict from that extra bind is ignored when the dual-stack socket already covers IPv4
  • Fixed UDP trackers being IPv4-only: the socket was bound to 0.0.0.0, so on IPv6-only hosts every udp:// tracker was unusable and IPv6 trackers failed to send; it is now dual-stack with the same send-side conversion
  • Fixed v4-mapped peer addresses not being normalized: some trackers / PEX implementations send IPv4 addresses as ::ffff:a.b.c.d, which used to create a second peer record alongside the IPv4 literal and could never be dialed on hosts without an IPv6 route; addresses are now normalized to IPv4 before being stored
  • Fixed HTTPS failing across the board with private CAs / corporate proxies (TLS interception): TLS only trusted the Mozilla roots compiled into the binary and the local OS certificate store (corporate CAs, user-imported certificates) took no part in verification; system roots are now loaded as well (a union with the built-in roots, leaving public-site verification results unchanged)
  • Fixed the no-proxy option having no effect: it was stored but never used to build the HTTP client, so in proxied environments LAN / loopback addresses listed in no-proxy were still pushed through the proxy and hosts that were directly reachable failed instead; it now really acts as the proxy's direct-connection exception (when using environment-variable proxies, the NO_PROXY environment variable applies)
  • Fixed HTTP split downloads being reported as finished when the control file's segment table is unusable: when the table was not a strict tiling (gap / overlap / empty) the writer neither fell back nor rebuilt it, so todo came out as 0 and the download was marked finishedsuccess without a single byte downloaded, and the target file was not even resized to the correct length; an invalid control file is now treated exactly like "no control file" (the existing file is taken as a contiguous prefix and the remainder is split again)
  • Fixed the resume bitfield running ahead of disk: with disk-cache enabled, piece data lands in an in-memory write-back buffer first while the resume control file is written as soon as a piece completes — so the bitfield could declare pieces complete that had not written a single byte, and after a crash / power loss recovery skipped them, producing "completed holes" (silent corruption). The persisted bitfield now excludes pieces still in the write-back buffer (the only cost is re-downloading those few pieces after a crash), and a clean pause flushes to disk before writing the bitfield
  • Fixed DHT KRPC responses not being validated against the source address: the pending-query table was keyed by the 16-bit transaction id alone, so with hundreds of concurrent queries in one round (bootstrap + iterative find_node) the birthday bound gives a noticeable chance of a collision delivering a response to the wrong node's waiter, and any host guessing a tid could inject a forged response (peers go straight into the BT dial queue); the key is now "source address + tid" and responses with no waiter no longer enter the query-handling path
  • Fixed NAT-PMP TCP port mapping never working: the opcode was written as 6 (neither 1 nor 2), so gateways always answered unsupported and TCP mapping depended entirely on the UPnP fallback; it is now 2 per RFC 6886 §3.3
  • Fixed DHT announce_peer always being sent with implied_port=1: BEP 5 says that when the bit is 1 the remote node ignores the port argument and uses the UDP source port, and announces leave through the DHT socket (a different port from the BT listen port) — so the remote node recorded our DHT port as our BT port, spreading a dead address; announces now declare implied_port=0 with the real BT listen port, and the self-address recorded in known_peers uses that port too
  • Fixed DHT get_peers replies encoding IPv6 peers as 0.0.0.0: every peer was encoded as a 6-byte IPv4 compact entry, so the 4 IP bytes of an IPv6 address were filled with zeros (a non-zero port still passed the receiver-side filter) and clients receiving it would try to ...
Read more

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 01:49

XferRust v0.3.0 Release Notes

English | 简体中文

Summary

  • New disk cache disk-cache (piece-level write-back buffering), magnet save/load as torrent (bt-save-metadata / bt-load-saved-metadata)
  • Peer-discovery switches now really take effect: enable-dht / enable-dht6 (BEP 32, DHT over IPv6 dual-stack) / enable-peer-exchange (BEP 11)
  • HTTP client configuration takes effect: continue resume switch, user-agent, all-proxy / no-proxy proxy (client rebuilt on change)
  • New task file-verification RPC task.verifyFiles (existence / size / streaming hash, executed natively by the engine)
  • UDP hole punching (ut_holepunch) aligned with the libtorrent standard — relays through double NATs with standard clients such as qBittorrent
  • HTTP piece bitmaps, global & per-task rate limiting, per-task average speed, command-line option passthrough
  • File selection (select-file) works end-to-end; .torrent additions support the bt-file-selection flow
  • Piece display upgrades: persisted tri-state bitmap (partialBitfield), wanted-piece bitmap wantedBitfield, seed duration bt-seed-time that stops seeding automatically when reached; BT peer IP banning and task.getPeers per-peer stats / banned group
  • Fixed phantom progress on unselected files and task progress above 100%: per-file and task progress now share one piece-segment accounting
  • Fixed magnet/torrent tasks skipping "awaiting file selection" and downloading directly, garbled Chinese task names, inaccurate average speed
  • All non-terminal tasks are restored as paused after restart; per-task rate limits now override the global one

New Features

Disk Cache (disk-cache)

  • New global option disk-cache (bytes or K/M/G suffix such as 128M; 0 = write-through off): BT piece data is first buffered in a memory write-back queue and flushed to disk in FIFO order, reducing small random writes
  • Read paths serve cached pieces directly from memory without touching disk; flush_all flushes the cache before syncing files, so the resume bitmap is only persisted after its data is on disk
  • Pieces larger than the cache limit degrade to direct writes; rewriting the same piece replaces the old entry without double counting; invalid values degrade to a warning without aborting the batch

Magnet Save / Load as Torrent (bt-save-metadata / bt-load-saved-metadata)

  • New global option bt-save-metadata: when magnet metadata arrives it is written to <download-dir>/<hex-infohash>.torrent (top-level dictionary hand-encoded with the original info bytes so the info_hash never shifts; atomic write via temp file + rename)
  • New global option bt-load-saved-metadata: on magnet task start, if a same-named .torrent exists in the download dir with a matching info_hash, the metadata is installed directly, skipping the peer fetch (magnet becomes a torrent task instantly)
  • Tasks created from a .torrent file are not re-saved (the original file already exists)

Peer-Discovery Switches (enable-dht / enable-dht6 / enable-peer-exchange)

  • New global option enable-dht (DHT, BEP 5): on by default; when off, BT tasks no longer join the DHT; private torrents never use DHT (the constraint wins)
  • New global option enable-dht6 (DHT over IPv6, BEP 32): when on, DHT binds a dual-stack socket ([::]), bootstraps IPv6 nodes, replies to IPv6 requesters with nodes6 / peers6 and parses remote v6 nodes; if the machine has no IPv6 stack and binding fails, it automatically falls back to IPv4
  • New global option enable-peer-exchange (PEX, BEP 11): on by default; when off the extension handshake does not advertise ut_pex and PEX messages are neither sent nor received

HTTP Client Configuration (continue / user-agent / all-proxy / no-proxy)

  • New global option continue (HTTP resume switch, default on): when off, downloads always start from scratch even if the server supports Range; an existing file is kept and a new name is used (aria2 semantics)
  • New global options user-agent / all-proxy / no-proxy: the HTTP client is built from them (UA overrides the engine default, proxy is direct or via all-proxy); changing them rebuilds the client so new connections pick it up immediately
  • Desktop proxy settings (system / custom) and UA settings now really apply to download traffic

Task BT Identity (bittorrent / infoHash)

  • Task status responses (task.tell / task.list, both the aria2-style and native numeric encodings) now carry a bittorrent object and an infoHash field
  • Non-BT tasks report bittorrent as null; when metadata is ready it is {"info": {"name", "hash"}}; while magnet metadata is being fetched it is {} (the frontend shows "fetching metadata")
  • infoHash is the hex encoding of the info dictionary hash: .torrent tasks report the hash computed at parse time, magnet tasks report the bt_info_hash from the handshake / metadata exchange

Global Tracker List & Subscription Switch Passthrough

  • engine.changeOptions gains bt-trackers: a string array or newline/comma-separated string with full-replacement semantics, synchronized to all active BT tasks with the same delta semantics as manual add/remove
  • New switch auto-update-trackers controls tracker subscription auto-update ("false" / "0" both mean off)

Command-Line Runtime Option Passthrough

  • The engine command line accepts --key=value runtime global options injected into the same store as engine.changeOptions (CLI values override session-restored ones): split, max-connection-per-server, min-split-size, overall rate limits, bt-max-peers, bt-adaptive, bt-seed-mode, bt-seed-ratio, bt-encryption, bt-protocol, bt-listen-port, dht-listen-port, bt-enable-lpd, bt-port-mapping
  • App-side toggles are auto-mapped: --enable-upnp / --enable-nat-pmpbt-port-mapping, --enable-utpbt-protocol
  • Any unknown --key=value is accepted as a global default (see Behavior Changes), so host applications can pass their entire configuration through the command line

Piece Display, Real-Time Speed & Peer Management

  • Download speed now uses a 3-second sliding window refreshed every second: the window average smooths piece-level write jitter while the value updates every second
  • BT piece bitfield exposure: bitfield reports the real "downloaded pieces" bitmap (aria2-compatible hex encoding), synced at 1 Hz, preserving the last known state while paused
  • Per-peer bitfield: each peer in task.getPeers gains a bitfield field (pieces the peer owns, all ones for seeds)
  • BT peer IP banning: task.banPeer (auto-unbans after duration seconds, <= 0 permanent; immediately disconnects existing connections) / task.unbanPeer; the ban list persists across sessions
  • Global ban-list option: engine.changeOptions gains bt-ip-ban-list (IP array or newline/comma-separated string, full replacement of permanent bans)
  • New task.changeUri (aria2-compatible: removes delUris / appends addUris per fileIndex for waiting/paused tasks, rejected when active) and task.getServers (HTTP tasks return server entries, BT returns an empty array)

Per-Task Average Speed (averageSpeed)

  • Task status responses gain an averageSpeed field (bytes/sec): accumulated every second during active download phases; seeding and paused phases neither accumulate nor dilute it
  • The accumulated data persists across sessions, so the average does not drift after restart-and-resume; the app reads this field directly instead of sampling

File Selection (select-file) End-to-End

  • task.changeOption now actually applies select-file (aria2 semantics: comma-separated 1-based file indices, empty = select all): running BT tasks hot-apply it, paused/waiting tasks pick it up on their next start
  • files[].selected reports the real selection: the native encoding previously hardcoded true; the aria2 encoding now outputs "true" / "false"
  • File selection extends to HTTP/HTTPS tasks: single-file layout, persisted and applied on the next start
  • task.add accepts select-file for pre-selection; invalid/out-of-range values degrade to a warning without aborting the addition
  • .torrent additions support the bt-file-selection flow: the same state machine as magnets — auto-pause once metadata is ready, resume via select-file after the client confirms the selection
  • Single-file magnets auto-resume: when the layout is a single file, the engine resumes at full selection without user action

HTTP Piece Bitmap & Global Rate Limiting

  • HTTP tasks report real piece data: numPieces / pieceLength / bitfield (aria2-compatible hex encoding)
  • Piece length is a display granularity decoupled from the segment granularity: min(min-split-size, max(total/2048, 64KB)) — even a few-MB file lights up pieces promptly, large files keep the min-split-size granularity
  • The write side accounts bytes incrementally per landed range on both multi-connection and single-connection paths; the bitmap is rebuilt when a server ignores Range and resends the full body; control-file watermarks pre-fill the bitmap on resume so it stays consistent with disk; omitted when total length is unknown or Range is unsupported
  • HTTP global rate limiting: an asynchronous token bucket is injected into every download connection, letting TCP backpressure converge naturally. Previously HTTP downloads were entirely unthrottled
  • Speed-limit value parsing upgraded: overall limits accept aria2-style units (1M / 500K / plain bytes), previously only plain integers
  • One invalid key no longer aborts the whole settings batch: illegal values in changeOptions degrade to a warning and skip that key

Per-Task Rate Limiting (max-download-limit / max-upload-limit)

  • task.changeOption accepts max-download-limit / max-upload-limit (aria2 ...
Read more

v0.2.0

Choose a tag to compare

@MochengCK MochengCK released this 07 Sep 14:44

XferRust v0.2.0 Release Notes

English | 简体中文

Summary: A magnet-experience and BT-stability release — pick which files to download from a table after a magnet link is parsed (download starts only after confirmation), plus fixes for a peer session leak, rate-limiter deadlock and uTP stream corruption, hardening against path traversal and metadata poisoning, and completed ut_metadata serving, tracker reporting and choking behavior. The TUI is fully redesigned as well — the add-task dialog supports a per-task download directory (with a native system folder picker), magnet links start parsing immediately and expand the dialog in place into a file-selection table once metadata is ready, the main layout is rebuilt into a modern flat design, and the global info bar stays visible on task detail pages. Additionally, this release adds full BT seeding lifecycle management (configurable share-ratio auto-stop, continuous seeding until manual stop) and Android platform engine-core cross-compilation support; it also completes BT network discoverability — local peer discovery (LPD), automatic UPnP/NAT-PMP port mapping and configurable BT/DHT listen ports — and fixes the tail-end stall that left HTTP/HTTPS downloads hanging at 99%.

New Features

  • Magnet file selection: the engine starts parsing metadata as soon as a magnet link is added; once parsed, the task pauses and a file table is shown (checkbox, file size, selection summary), and only the checked files are downloaded. Pieces spanning the selected/unselected boundary are downloaded whole, as BitTorrent requires
  • Magnet tasks are resumable: a task still waiting for file selection reopens the file table after a restart instead of silently downloading everything
  • Serve ut_metadata (BEP 9) requests: magnet peers get proper DATA/REJECT responses instead of being ignored
  • seed_duration is now honored: seeding exits cleanly with a stopped announce when the configured time is up

BT Seeding Lifecycle Management

  • BT tasks can be configured to enter a seeding state after download completion (instead of finishing immediately), controlled by the global option bt-seed-mode (true/false)
  • Seeding tasks display a live share ratio (uploaded / downloaded); a target share ratio bt-seed-ratio (e.g. 1.5, 2.0) can be set — seeding auto-stops when the ratio is reached
  • Seeding tasks can be paused/resumed, and seeding can be manually stopped (RPC task.stopSeed / TUI S key)
  • Continuous seeding until manual stop is supported (bt-seed-ratio of 0 disables auto-stop)
  • TUI settings page adds seeding mode and target share ratio options; task list/detail views show upload speed and share ratio for seeding tasks

BT Network Discovery & Port Configuration

  • Local peer discovery (LPD / BEP 14): each BT task joins the LSD multicast group, periodically announces to and listens on the LAN, so peers on the same network can find each other without trackers; discovered peers enter scheduling with an lpd source
  • Automatic UPnP / NAT-PMP port mapping: when a BT task starts, the engine sets up a TCP + UDP dual mapping on the router (2-hour lease, renewed every 1/3 of the lease, automatic retry next cycle after a single failure) and best-effort removes the mapping on shutdown — better connectability, no more manual router port forwarding
  • Configurable BT / DHT listen ports: new global options bt-listen-port / dht-listen-port (0 = random port), applied when a BT task is created; if the listen port or DHT port is taken, the engine falls back to an ephemeral port with a warning instead of disabling listening entirely
  • New switches bt-enable-lpd / bt-port-mapping (both on by default) to disable either feature independently; engine.getOptions exposes the new options and changeGlobalOption validates port values (0–65535)
  • The TUI settings page gains the four matching rows: BT / DHT listen port (Enter to edit, validated 0–65535, 0 shown as "random") plus Local discovery and Port mapping toggles (←/→ to switch); conns-per-server, min split size and language shift below them

Android Engine-Core Build

  • Added Android (aarch64-linux-android / arm64-v8a) cross-compilation support — builds only the engine core (xferrust), no TUI
  • Cargo.toml makes TUI dependencies (crossterm, ratatui, etc.) optional under a tui feature; default = ["tui"]; the xfer binary is marked required-features = ["tui"]
  • CI adds a build-android job: cross-compiles with NDK r27c + API 24 (Android 7.0+); artifact xferrust-android-arm64-v8a.tar.gz is included in releases
  • New local build script scripts/build-android.sh: auto-detects NDK host-tag (macOS / Linux), sets CC/CXX/AR/Linker env vars and invokes cargo build --no-default-features --bin xferrust

TUI Redesign

  • Redesigned add-task dialog: URL + directory fields; an empty directory falls back to the global download directory (per task only). The directory can be typed manually or picked with the native system folder dialog by pressing Enter (macOS / Windows / Linux)
  • Magnet links start parsing metadata immediately, no extra confirmation step; the dialog shows live parsing progress (connections / waiting / elapsed). Once metadata is ready, the dialog expands downward into a file-selection table: Space to toggle, A to select all/none, Enter to start downloading the selected files
  • The download directory in Settings is also picked with the native system folder dialog
  • Task detail pages (BT / non-BT) keep the global info bar at the top (brand logo + global speed / task counters) instead of hiding it

Bug Fixes

  • Fix magnet tasks reporting an empty file list while downloading: metadata is back-filled as soon as it is ready, so files and numPieces are no longer zero
  • Fix magnet metadata being lost across restarts: the session persists the info dictionary and rebuilds the metadata from it, no need to re-fetch from peers
  • Fix inbound peer session leak: passive connections were never unregistered, stalling their assigned pieces for up to 180 s
  • Fix rate-limiter deadlock: token bucket guarantees at least one max-size block, limits below 16 KiB/s no longer freeze the connection
  • Fix uTP stream corruption: read path applies back-pressure via channel capacity; write path buffers partially accepted bytes instead of dropping them
  • Sanitize torrent paths (name / path segments) to prevent path-traversal writes outside the download directory
  • Fix scheduler treating 0→0 throughput as a 100% decline — target connection count no longer collapses during cold start
  • Fix choking algorithm: wall-clock rounds shared by all sessions, engine-level optimistic unchoke that actually reaches the lucky peer, round-robin uploads while seeding
  • Fix tracker announces always reporting zero uploaded bytes (private-tracker ratio tracking works now)
  • Fix UDP trackers never receiving stopped/completed events
  • Fix HTTP/HTTPS downloads hanging at 99% for over ten seconds before finishing:
    • Tail short reads (response body shorter than the requested range) now use a dedicated backoff curve (from 250 ms, capped at 1 s) instead of sharing the 0.5–2 s hard-failure backoff — short reads always make progress when retried from the watermark, and the old backoff accumulated into a long tail under retry storms
    • New 10-second read-idle watchdog: a silently stalled connection (dead peer / half-open socket) resumes from the watermark immediately instead of waiting out the 30-second read timeout
    • Read timeouts are now classified as renewable transients: they no longer consume the 4-strike failure budget, so tail retries are no longer killed prematurely

UI Redesign

  • Flat top bar: a single row with the brand logo on the left and ↓/↑ global speed plus active/waiting/stopped counters on the right, separated by a vertical bar
  • Square task-area borders: top/bottom lines start aligned with the logo, end in rounded corners joined to the right vertical line, all four corners left open; the sidebar/content divider leaves headroom above and below
  • Sidebar: removed the category heading, selection is now highlighted with a background (no more pointer)
  • Task table: a separator line between the header and rows (same color as the border, same width as the columns, symmetric on both sides); header and rows keep one column of padding on each side, symmetric left/right
  • Size column is now a compact "completed / total" format, the speed column is narrower, and task names no longer push later columns out of alignment

Other Changes

  • New file-selection API: select_files(gid, file_indices) / get_selected_files(gid), applied live on running tasks; add_uri accepts a bt-file-selection option to pause a magnet task after parsing and wait for a selection
  • Task status exposes a new awaitingSelection field, and files[].selected now reflects the real selection
  • New seeding status seeding and seedRatio field; RPC adds task.stopSeed method; session save/restore handles seeding tasks correctly (serialized as waiting so they re-download on restart)
  • Failed dial / session addresses are re-queued for a bounded number of retries instead of waiting for the next announce
  • A short-read storm exceeding 8 consecutive retries folds into one regular failure under the normal failure budget — the relaxed backoff does not slow down error reporting for permanently broken servers
  • Added HTTP tail-truncation + pause/resume regression tests (short-read storms, silent stalls, cancel & resume scenarios)
  • DHT hardening: known-peer table capped with FIFO eviction, inbound datagram processing concurrency limited
  • Added 27 TUI rendering regression tests (border geometry, column alignment, dialog flow, detail top bar, etc.)

XferRust v0.2.0 发布说明

English | 简体中文

摘要:本...

Read more

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 20:50

XferRust v0.1.0

首个公开版本

一个使用 Rust 构建的现代化、高性能下载引擎。

Important

🎉 XferRust v0.1.0 是本项目的首个公开版本。

此版本标志着 XferRust 正式开始公开开发。

XferRust 是一个使用 Rust 构建的新一代下载引擎,致力于提供出色的 性能(Performance)可靠性(Reliability)可扩展性(Extensibility)

The First Public Release

A modern, high-performance download engine built with Rust.

Important

🎉 XferRust v0.1.0 is the first public release of the project.

This release marks the beginning of XferRust — a new generation download engine designed with performance, reliability, and extensibility in mind.

🔗 完整更新记录 / Full Changelog

Full Changelog: https://github.com/MochengCK/XferRust/commits/v0.1.0