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
4 changes: 4 additions & 0 deletions .github/workflows/release-tauri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ jobs:
OPENLESS_UPDATE_TARGET: ${{ matrix.updater-target }}
OPENLESS_UPDATE_ARCH: ${{ matrix.updater-arch }}
OPENLESS_UPDATE_REPO: appergb/openless
OPENLESS_UPDATE_MIRROR_BASE_URL: https://fastgit.cc/https://github.com
run: node scripts/write-updater-manifest.mjs

# ── 收集产物 ──
Expand Down Expand Up @@ -266,6 +267,7 @@ jobs:
openless-all/app/src-tauri/target/release/bundle/macos/*.app.tar.gz
openless-all/app/src-tauri/target/release/bundle/macos/*.app.tar.gz.sig
openless-all/app/src-tauri/target/release/bundle/latest-darwin-aarch64.json
openless-all/app/src-tauri/target/release/bundle/latest-darwin-aarch64-mirror.json
if-no-files-found: error

- name: Upload Windows artifacts
Expand All @@ -287,6 +289,7 @@ jobs:
openless-all/app/src-tauri/target/release/bundle/nsis/*.exe.sig
openless-all/app/src-tauri/target/release/bundle/msi/*.msi.sig
openless-all/app/src-tauri/target/release/bundle/latest-windows-x86_64.json
openless-all/app/src-tauri/target/release/bundle/latest-windows-x86_64-mirror.json
if-no-files-found: error

- name: Upload Linux artifacts
Expand All @@ -308,6 +311,7 @@ jobs:
path: |
openless-all/app/src-tauri/target/release/bundle/appimage/*.AppImage.sig
openless-all/app/src-tauri/target/release/bundle/latest-linux-x86_64.json
openless-all/app/src-tauri/target/release/bundle/latest-linux-x86_64-mirror.json
if-no-files-found: error

# ── tag 推送时,同步上传到 GitHub Release ──
Expand Down
63 changes: 63 additions & 0 deletions docs/auto-update-download-acceleration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Auto Update Download Acceleration

## Problem

OpenLess used a single Tauri updater endpoint on GitHub Releases:

```text
https://github.com/appergb/openless/releases/latest/download/latest-{{target}}-{{arch}}.json
```

The manifest also pointed installer downloads back to GitHub Releases. On networks where GitHub release assets are slow, a small updater package can take minutes to download.

Desktop apps do not reliably inherit a user's shell proxy environment. Instead of making updater correctness depend on whether a proxy is visible to the app process, the updater should use a GitHub release acceleration URL directly.

## Runtime Behavior

The app does not manually probe local proxy ports. It lets the OS/process network stack do whatever it normally does, while the updater endpoint itself points at `fastgit.cc` first. This keeps the rule simple: proxy or no proxy, updater traffic should prefer the fastgit transport.

## Fastgit Acceleration

Release builds now publish two updater manifests per target:

```text
latest-<target>-<arch>.json
latest-<target>-<arch>-mirror.json
```

The client checks the mirror manifest first, then GitHub. The mirror manifest points its installer URL at:

```text
https://fastgit.cc/https://github.com/<repo>/releases/latest/download/<asset>
```

The updater signature still protects the downloaded package. The mirror only changes transport; it cannot replace the signed payload without verification failing.

## Maintainer Notes

Set `OPENLESS_UPDATE_MIRROR_BASE_URL` in CI to change the mirror host. Keep it formatted as a prefix for GitHub URLs, for example:

```text
https://fastgit.cc/https://github.com
```

If a mirror becomes unreliable, replace that environment value and the mirror endpoint in `openless-all/app/src-tauri/tauri.conf.json`.

## Evidence

Measured from Windows on 2026-05-01. Direct GitHub release downloads were tested with local proxy disabled to reproduce the slow path. `fastgit.cc` was tested both through the normal local proxy environment and with local proxy disabled; results vary by route, so do not treat one machine's no-proxy number as a CDN SLA.

```text
Direct GitHub installer asset, 4.78 MB, proxy disabled:
run 1: timed out after 90.75s, 1.73 MB received
run 2: timed out after 90.06s, 2.44 MB received

fastgit.cc installer asset, 4.78 MB, normal local proxy environment:
with protocol prefix: 3.12s / 3.63s / 3.39s
without protocol prefix: 2.92s / 2.45s / 2.87s

fastgit.cc target-user signal:
manual browser/download usage reported completing in under 1s without enabling a proxy.
```

This is enough to justify a `fastgit.cc` mirror path, but not enough to treat a public mirror as permanently trusted infrastructure. `fastgit.cc` explicitly documents support for GitHub release/archive acceleration and accepts GitHub links with or without the protocol prefix. Keep the mirror configurable and re-test before each release if download performance is a release blocker.
13 changes: 11 additions & 2 deletions openless-all/app/scripts/write-updater-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { fileURLToPath } from 'node:url';
const target = process.env.OPENLESS_UPDATE_TARGET;
const arch = process.env.OPENLESS_UPDATE_ARCH;
const repo = process.env.OPENLESS_UPDATE_REPO || 'appergb/openless';
const mirrorBaseUrl = process.env.OPENLESS_UPDATE_MIRROR_BASE_URL || 'https://fastgit.cc/https://github.com';

if (!target || !arch) {
throw new Error('OPENLESS_UPDATE_TARGET and OPENLESS_UPDATE_ARCH are required');
Expand Down Expand Up @@ -52,12 +53,20 @@ if (!existsSync(signaturePath)) {

const assetName = basename(artifact);
const manifestName = `latest-${target}-${arch}.json`;
const mirrorManifestName = `latest-${target}-${arch}-mirror.json`;
const githubAssetUrl = `https://github.com/${repo}/releases/latest/download/${assetName}`;
const mirrorAssetUrl = `${mirrorBaseUrl.replace(/\/$/, '')}/${repo}/releases/latest/download/${assetName}`;
const manifest = {
version: packageJson.version,
pub_date: new Date().toISOString(),
url: `https://github.com/${repo}/releases/latest/download/${assetName}`,
url: githubAssetUrl,
signature: readFileSync(signaturePath, 'utf8').trim(),
};
const mirrorManifest = {
...manifest,
url: mirrorAssetUrl,
};

writeFileSync(join(bundleDir, manifestName), `${JSON.stringify(manifest, null, 2)}\n`);
console.log(`Wrote ${manifestName} for ${assetName}`);
writeFileSync(join(bundleDir, mirrorManifestName), `${JSON.stringify(mirrorManifest, null, 2)}\n`);
console.log(`Wrote ${manifestName} and ${mirrorManifestName} for ${assetName}`);
1 change: 1 addition & 0 deletions openless-all/app/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDFERUFBODAzNTY0QzMyM0YKUldRL01reFdBNmpxSGE1K0JadlpONXNWTzhJcGZCRGxjUVdIWExNNFJpeUNsSGZwazdlQThhemkK",
"endpoints": [
"https://fastgit.cc/https://github.com/appergb/openless/releases/latest/download/latest-{{target}}-{{arch}}-mirror.json",
"https://github.com/appergb/openless/releases/latest/download/latest-{{target}}-{{arch}}.json"
]
}
Expand Down
4 changes: 3 additions & 1 deletion openless-all/app/src/components/AutoUpdate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { useTranslation } from 'react-i18next';
import { isTauri, restartApp } from '../lib/ipc';
import { Btn } from '../pages/_atoms';

const UPDATE_CHECK_TIMEOUT_MS = 15_000;

export type UpdateStatus =
| 'idle'
| 'checking'
Expand Down Expand Up @@ -78,7 +80,7 @@ export function useAutoUpdate(): UseAutoUpdate {
return;
}
const { check } = await import('@tauri-apps/plugin-updater');
const next = await check();
const next = await check({ timeout: UPDATE_CHECK_TIMEOUT_MS });
updateRef.current = next;
setVersion(next?.version ?? '');
setStatus(next ? 'available' : 'none');
Expand Down
Loading