Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 92 additions & 0 deletions RELEASE_NOTES_v0.1.0-beta.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# rustTorrent v0.1.0-beta.3

## Summary

rustTorrent 0.1.0-beta.3 improves migration safety, torrent recovery, and
qBittorrent compatibility. It adds fail-closed read-only payload access,
restores tracker lists that are missing from imported metainfo, supports force
rechecks, and corrects save-path handling for multi-file torrents.

This remains beta software. Back up the persistent session directory before
upgrading and avoid using it for data that cannot be downloaded again.

## Torrent recovery and verification

- Tracker URLs can be added to existing torrents at runtime and are retained
across JSON and PostgreSQL session reloads.
- Restored trackers start announcing immediately for live torrents. This
recovers qBittorrent imports whose effective tracker lists existed only in
`.fastresume` data rather than the exported `.torrent` file.
- Native and qBittorrent-compatible force-recheck endpoints verify payloads
while preserving whether a torrent was paused or live.
- The Web UI exposes **Force Recheck** in the torrent context menu with
appropriate disabled-state handling.

## Read-only payload migration

- `--storage-read-only` and `RTBIT_STORAGE_READ_ONLY` opt into filesystem
storage that refuses payload writes, creation, resizing, deletion, and
directory removal.
- Existing payloads can be verified without modification, and missing payload
paths remain absent instead of being created implicitly.
- qBittorrent `savepath` values are now treated as payload roots for multi-file
torrents, including the single-entry multi-file metainfo edge case.
- Corrected output-folder roots persist through both JSON and PostgreSQL
session backends and are reflected by qBittorrent-compatible API responses.

## SwarmForge library family

- The reusable BitTorrent engine and protocol packages are now published as
the coordinated `swarmforge` / `swarmforge-*` 0.1.0 family on crates.io.
- Cargo package identities changed, while compatible Rust library and import
names such as `librtbit::Session` and `librtbit_core::Id20` remain available
through dependency aliases.
- All 12 family members must be migrated atomically in a consumer dependency
graph. Mixing historical and SwarmForge package identities can duplicate
shared types.
- The historical repositories and packages remain available as rollback
sources. NGMS independently verified consumption of the complete public
SwarmForge family before this release.

## Web UI and deployment

- Production `/web/` routes now use the same-origin API instead of incorrectly
redirecting requests to the Vite development port.
- Source, CI, binary releases, containers, and website delivery now use the
canonical GitHub repository and GitHub Actions workflows.
- Main builds publish immutable commit images and release tags publish public
multi-architecture `linux/amd64` and `linux/arm64` images to GHCR.

## Upgrade notes

- No intentional destructive session or RSS database migration is included.
- Keep `/home/rtbit/db` and `/home/rtbit/cache` persistent and back them up
before upgrading.
- For qBittorrent migrations, use read-only storage for the first verification
pass and confirm the payload root expected by each imported torrent.
- Consumers of the reusable libraries should follow the atomic migration and
rollback guidance in `docs/SWARMFORGE-0.1.0-RELEASE.md`.
- `latest` and `beta` move to this release after publication. Pin
`v0.1.0-beta.3` when reproducibility matters.

## Validation

- `cargo fmt --all -- --check`
- `cargo check --workspace --exclude rtbit-desktop --no-default-features --features default-tls`
- `cargo test --workspace --exclude rtbit-desktop --no-default-features --features default-tls`
- `cargo clippy --workspace --exclude rtbit-desktop --no-default-features --features default-tls -- -D warnings`
- Web UI unit tests, lint, production build, and Playwright browser tests
- Website structural validation
- GitHub release binary build and multi-architecture container publication

## Downloads

- Linux x86_64: `rtbit-v0.1.0-beta.3-linux-x86_64`
- Windows x86_64: `rtbit-v0.1.0-beta.3-windows-x86_64.exe`
- Debian/Ubuntu amd64: `rtbit-v0.1.0-beta.3-amd64.deb`
- Checksums: `SHA256SUMS-v0.1.0-beta.3.txt`
- Docker: `ghcr.io/thedancingdeveloper-org/rusttorrent:v0.1.0-beta.3`
- Source: automatic `.zip` and `.tar.gz` archives on the GitHub release tag

Release files are attached to the canonical GitHub release and are also
published at `https://dl.rusttorrent.dev/v0.1.0-beta.3/`.
2 changes: 1 addition & 1 deletion crates/librtbit-dht/src/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl PersistentDht {

if let Some(parent) = config_filename.parent() {
std::fs::create_dir_all(parent)
.with_context(|| format!("error creating dir {:?}", &parent))?;
.with_context(|| format!("error creating dir {:?}", parent))?;
}

let de = match OpenOptions::new().read(true).open(&config_filename) {
Expand Down
4 changes: 2 additions & 2 deletions crates/librtbit/src/http_api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl HttpApiClient {
if root.server == "rtbit" {
return Ok(());
}
anyhow::bail!("not an rtbit server at {}", &self.base_url)
anyhow::bail!("not an rtbit server at {}", self.base_url)
}
.boxed()
}
Expand All @@ -103,7 +103,7 @@ impl HttpApiClient {
..Default::default()
};
let qs = serde_urlencoded::to_string(&params).unwrap();
let url = format!("{}torrents?{}", &self.base_url, qs);
let url = format!("{}torrents?{}", self.base_url, qs);
let response = check_response(
self.client
.post(&url)
Expand Down
2 changes: 1 addition & 1 deletion crates/librtbit/src/storage/filesystem/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ impl TorrentStorage for FilesystemStorage {
.with_context(|| {
format!(
"error creating a new file (because allow_overwrite = false) {:?}",
&full_path
full_path
)
})?;
OpenOptions::new().read(true).write(true).open(&full_path)?
Expand Down
8 changes: 4 additions & 4 deletions crates/librtbit/src/torrent_state/live/peer_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ impl PeerHandler {
{
anyhow::bail!(
"got request for a chunk that is not ready to upload. chunk {:?}",
&chunk_info
chunk_info
);
}

Expand Down Expand Up @@ -866,7 +866,7 @@ impl PeerHandler {
) {
Some(i) => i,
None => {
anyhow::bail!("peer sent us an invalid piece {:?}", &piece,);
anyhow::bail!("peer sent us an invalid piece {:?}", piece,);
}
};

Expand All @@ -884,8 +884,8 @@ impl PeerHandler {
if !h.inflight_requests.remove(&chunk_info) {
anyhow::bail!(
"peer sent us a piece we did not ask. Requested pieces: {:?}. Got: {:?}",
&h.inflight_requests,
&piece,
h.inflight_requests,
piece,
);
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/librtbit/webui/src/main-mock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Object.assign(RssAPI, MockRssAPI);
const RootWithMockAPI = () => {
return (
<APIContext.Provider value={MockAPI}>
<RtbitWebUI title="RustTorrent Demo" version="v0.1.0-beta.2" />
<RtbitWebUI title="RustTorrent Demo" version="v0.1.0-beta.3" />
</APIContext.Provider>
);
};
Expand Down
2 changes: 1 addition & 1 deletion crates/rtbit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rtbit"
version = "0.1.0-beta.2"
version = "0.1.0-beta.3"
authors = ["AusAgentSmith <admin@rusttorrent.dev>"]
edition = "2024"
description = "A bittorrent command line client and server."
Expand Down
29 changes: 14 additions & 15 deletions documentation/ReleaseProcess.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ rusttorrent.dev website. The historical Forgejo/Woodpecker path is retired.

## Versioning

The current beta release is `0.1.0-beta.2`.
The current beta release is `0.1.0-beta.3`.

- Crate version: `crates/rtbit/Cargo.toml`
- Release tag: `v0.1.0-beta.2`
- Docker tag: `ghcr.io/thedancingdeveloper-org/rusttorrent:v0.1.0-beta.2`
- Release tag: `v0.1.0-beta.3`
- Docker tag: `ghcr.io/thedancingdeveloper-org/rusttorrent:v0.1.0-beta.3`

## CI Flow

Expand Down Expand Up @@ -53,15 +53,16 @@ Known permission failure modes:
MyDevEnv2 container has not picked up the Komodo stack env values. Redeploy
`prod-mydevenv2` from outside the active session; restarting the current
container terminates the agent session.
- Woodpecker API calls must use numeric repo IDs. Owner/name pipeline endpoints
can return the frontend HTML with HTTP 200 and do no useful work.
- GHCR copy and GitHub release steps use the Woodpecker `gh_release_token`
secret. If GitHub validation returns `401` or GHCR returns `403`, rotate
`GITHUB_PAT` / `GH_RELEASE_TOKEN` in Infisical `cicd`, then refresh the
Woodpecker `gh_release_token` secret before tagging a release. The token
needs repository release access and GHCR package write access.
- Binary releases use the workflow-scoped `GITHUB_TOKEN` with `contents: write`.
- Container publication uses the repository `GHCR_TOKEN` secret and requires
`packages: write`. If GHCR login or publication fails, validate or rotate that
repository secret with the destination-organization credential documented in
the workspace guidance.
- Download-host publication uses the repository `DEPLOY_SSH_KEY` secret.
- Do not restore the retired Woodpecker release path or the revoked
`GITHUB_PAT` / `GH_RELEASE_TOKEN` credentials.

## v0.1.0-beta.1 Outcome
## Historical v0.1.0-beta.1 Outcome

Woodpecker pipeline 71 published the Forgejo release and download artifacts on
2026-06-12. The initial GHCR and GitHub release stages failed because the
Expand All @@ -82,9 +83,7 @@ updated with `manual`, `push`, and `tag` event access.
- GitHub issues `#11` through `#15`: closed with direct links to the `librtbit`
implementation commit and the rustTorrent release-integration commit

The PAT used for the repair was provided in chat. Rotate it again after the
release repair is complete, then update Infisical `GITHUB_PAT` /
`GH_RELEASE_TOKEN` and the Woodpecker `gh_release_token` secret with the
replacement value.
This section records the retired Forgejo/Woodpecker release outcome only. The
credentials and repair procedure used for beta.1 must not be reused.

Do not print tokens, use `set -x`, or write credentials to repo files.
15 changes: 15 additions & 0 deletions website/demo/assets/mock-5UlMa0Nf.js

Large diffs are not rendered by default.

15 changes: 0 additions & 15 deletions website/demo/assets/mock-Fgd9Vka6.js

This file was deleted.

2 changes: 1 addition & 1 deletion website/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RustTorrent Live Demo</title>
<link rel="icon" type="image/svg+xml" href="./assets/logo-C8iy-M8G.svg" />
<script type="module" crossorigin src="./assets/mock-Fgd9Vka6.js"></script>
<script type="module" crossorigin src="./assets/mock-5UlMa0Nf.js"></script>
<link rel="stylesheet" crossorigin href="./assets/mock-PY8lo5Ey.css">
</head>

Expand Down
Loading