Skip to content

Commit 13190ea

Browse files
committed
feat: new update function
1 parent b68dc00 commit 13190ea

24 files changed

Lines changed: 1716 additions & 12 deletions

.github/workflows/release.yml

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,22 @@ jobs:
7777
shell: pwsh
7878
env:
7979
SUBSCRIPTION_ENCRYPT_KEY: ${{ secrets.SUBSCRIPTION_ENCRYPT_KEY }}
80+
# For pre-release tags (containing '-') point the updater at the dev branch
81+
# so test builds don't check the production manifest.
82+
MANIFEST_URL_OVERRIDE: ${{ contains(github.ref_name, '-') && 'https://raw.githubusercontent.com/AandStep/ResultV/dev/update.json' || '' }}
8083
run: |
8184
$key = $env:SUBSCRIPTION_ENCRYPT_KEY
85+
$ldflags = ""
8286
if ($key) {
83-
wails build -clean -nsis -platform windows/amd64 -ldflags "-X resultproxy-wails/internal/proxy.subscriptionEncryptKey=$key"
87+
$ldflags = "-X resultproxy-wails/internal/proxy.subscriptionEncryptKey=$key"
88+
}
89+
$manifestOverride = $env:MANIFEST_URL_OVERRIDE
90+
if ($manifestOverride) {
91+
$ldflags = "$ldflags -X resultproxy-wails/internal/updater.ManifestURLOverride=$manifestOverride".Trim()
92+
}
93+
if ($ldflags) {
94+
wails build -clean -nsis -platform windows/amd64 -ldflags $ldflags
8495
} else {
85-
Write-Warning "Secret SUBSCRIPTION_ENCRYPT_KEY not set — building without decryption key"
8696
wails build -clean -nsis -platform windows/amd64
8797
}
8898
@@ -157,6 +167,7 @@ jobs:
157167
APPLE_NOTARY_APPLE_ID: ${{ secrets.APPLE_NOTARY_APPLE_ID }}
158168
APPLE_NOTARY_TEAM_ID: ${{ secrets.APPLE_NOTARY_TEAM_ID }}
159169
APPLE_NOTARY_PASSWORD: ${{ secrets.APPLE_NOTARY_PASSWORD }}
170+
MANIFEST_URL_OVERRIDE: ${{ contains(github.ref_name, '-') && 'https://raw.githubusercontent.com/AandStep/ResultV/dev/update.json' || '' }}
160171
run: |
161172
chmod +x build-macos.sh
162173
./build-macos.sh
@@ -215,6 +226,7 @@ jobs:
215226
- name: Build Linux artifacts
216227
env:
217228
SUBSCRIPTION_ENCRYPT_KEY: ${{ secrets.SUBSCRIPTION_ENCRYPT_KEY }}
229+
MANIFEST_URL_OVERRIDE: ${{ contains(github.ref_name, '-') && 'https://raw.githubusercontent.com/AandStep/ResultV/dev/update.json' || '' }}
218230
run: |
219231
chmod +x build-linux.sh
220232
./build-linux.sh
@@ -301,6 +313,84 @@ jobs:
301313
body_path: RELEASE_BODY.txt
302314
files: release-assets/*
303315
draft: false
304-
prerelease: false
316+
# Tags with a hyphen (e.g. v3.2.0-dev.1) are pre-releases.
317+
# Pre-releases are visible on GitHub but not shown as "Latest release",
318+
# so production auto-update is unaffected.
319+
prerelease: ${{ contains(github.ref_name, '-') }}
320+
env:
321+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
322+
323+
- name: Compute sha256 and update update.json platforms
324+
run: |
325+
cat > update_manifest.cjs <<'NODE_EOF'
326+
const fs = require('fs');
327+
const path = require('path');
328+
const crypto = require('crypto');
329+
330+
const tag = process.env.GITHUB_REF_NAME; // e.g. "v3.2.0"
331+
const version = tag.replace(/^v/, '');
332+
const repo = process.env.GITHUB_REPOSITORY; // "AandStep/ResultV"
333+
const baseURL = `https://github.com/${repo}/releases/download/${tag}`;
334+
const dir = 'release-assets';
335+
336+
function sha256File(p) {
337+
return crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex');
338+
}
339+
340+
const files = fs.readdirSync(dir);
341+
342+
const portableFile = files.find(f => /^ResultV.*\.exe$/i.test(f) && !/installer/i.test(f) && !/setup/i.test(f));
343+
const installerFile = files.find(f => /installer.*\.exe$/i.test(f) || /setup.*\.exe$/i.test(f));
344+
const dmgFile = files.find(f => /\.dmg$/i.test(f));
345+
const appimageFile = files.find(f => /\.AppImage$/i.test(f));
346+
const debFile = files.find(f => /\.deb$/i.test(f));
347+
348+
const update = JSON.parse(fs.readFileSync('update.json', 'utf8'));
349+
update.version = version;
350+
update.platforms = {};
351+
352+
function addPlatform(key, filename) {
353+
if (!filename) return;
354+
const p = path.join(dir, filename);
355+
if (!fs.existsSync(p)) return;
356+
const stat = fs.statSync(p);
357+
update.platforms[key] = {
358+
url: `${baseURL}/${filename}`,
359+
sha256: sha256File(p),
360+
size: stat.size,
361+
};
362+
console.log(`[${key}] ${filename} sha256=${update.platforms[key].sha256} size=${stat.size}`);
363+
}
364+
365+
addPlatform('windows-amd64-portable', portableFile);
366+
addPlatform('windows-amd64-installer', installerFile);
367+
addPlatform('darwin-universal', dmgFile);
368+
addPlatform('linux-amd64-appimage', appimageFile);
369+
addPlatform('linux-amd64-deb', debFile);
370+
371+
fs.writeFileSync('update.json', JSON.stringify(update, null, 2) + '\n');
372+
console.log('update.json written with platforms:', Object.keys(update.platforms).join(', ') || '(none)');
373+
NODE_EOF
374+
node update_manifest.cjs
375+
376+
# For stable releases (no hyphen): commit update.json to main so all users
377+
# receive the update notification. For pre-releases (e.g. v3.2.0-dev.1):
378+
# commit to dev branch only — production users are unaffected.
379+
- name: Commit updated update.json
380+
run: |
381+
# Choose target branch based on whether this is a pre-release tag.
382+
if [[ "${{ github.ref_name }}" == *"-"* ]]; then
383+
TARGET_BRANCH="dev"
384+
else
385+
TARGET_BRANCH="main"
386+
fi
387+
git config user.name "github-actions[bot]"
388+
git config user.email "github-actions[bot]@users.noreply.github.com"
389+
git fetch origin "$TARGET_BRANCH"
390+
git checkout "$TARGET_BRANCH"
391+
git add update.json
392+
git diff --cached --quiet || \
393+
git commit -m "chore: update update.json platforms for ${{ github.ref_name }} [skip ci]"
394+
git push origin "$TARGET_BRANCH"
305395
env:
306396
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

app.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
"resultproxy-wails/internal/logger"
4949
"resultproxy-wails/internal/proxy"
5050
"resultproxy-wails/internal/system"
51+
"resultproxy-wails/internal/updater"
5152
)
5253

5354
var stableHWIDProvider = config.StableHardwareID
@@ -101,6 +102,9 @@ type App struct {
101102

102103
deepLinkMu sync.Mutex
103104
pendingDeepLink string
105+
106+
updateMu sync.Mutex
107+
updateCancel context.CancelFunc
104108
}
105109

106110
func NewApp() *App {
@@ -2164,3 +2168,100 @@ func (a *App) startSmartBlockedRefresh(cachePath string) {
21642168
}
21652169
}()
21662170
}
2171+
2172+
// StartUpdate begins the in-app update: check manifest → download → verify → install.
2173+
// Progress and status are emitted as Wails events:
2174+
// - update:progress { downloaded, total, speedBps }
2175+
// - update:verifying (no payload)
2176+
// - update:verified (no payload)
2177+
// - update:installing (no payload)
2178+
// - update:failed { stage, message }
2179+
//
2180+
// If another update is already in progress this call is a no-op.
2181+
func (a *App) StartUpdate() {
2182+
a.updateMu.Lock()
2183+
if a.updateCancel != nil {
2184+
a.updateMu.Unlock()
2185+
return
2186+
}
2187+
ctx, cancel := context.WithCancel(a.ctx)
2188+
a.updateCancel = cancel
2189+
a.updateMu.Unlock()
2190+
2191+
go func() {
2192+
defer func() {
2193+
a.updateMu.Lock()
2194+
a.updateCancel = nil
2195+
a.updateMu.Unlock()
2196+
}()
2197+
2198+
emit := func(event string, payload interface{}) {
2199+
if a.ctx != nil {
2200+
wailsRuntime.EventsEmit(a.ctx, event, payload)
2201+
}
2202+
}
2203+
failEvent := func(stage, message string) {
2204+
emit("update:failed", map[string]interface{}{
2205+
"stage": stage, "message": message,
2206+
})
2207+
}
2208+
2209+
u := updater.New()
2210+
2211+
manifest, err := u.Check(ctx)
2212+
if err != nil {
2213+
if ctx.Err() != nil {
2214+
return
2215+
}
2216+
failEvent("check", err.Error())
2217+
return
2218+
}
2219+
2220+
asset := manifest.ResolveAsset()
2221+
if asset == nil {
2222+
failEvent("check", "no in-app update available for this platform")
2223+
return
2224+
}
2225+
2226+
path, err := u.Download(ctx, asset, func(downloaded, total int64, speedBps float64) {
2227+
emit("update:progress", map[string]interface{}{
2228+
"downloaded": downloaded,
2229+
"total": total,
2230+
"speedBps": speedBps,
2231+
})
2232+
})
2233+
if err != nil {
2234+
if ctx.Err() != nil {
2235+
failEvent("download", "download cancelled")
2236+
return
2237+
}
2238+
failEvent("download", err.Error())
2239+
return
2240+
}
2241+
2242+
emit("update:verifying", nil)
2243+
2244+
if err := u.Verify(path, asset.SHA256); err != nil {
2245+
failEvent("verify", err.Error())
2246+
return
2247+
}
2248+
2249+
emit("update:verified", nil)
2250+
emit("update:installing", nil)
2251+
2252+
if err := u.Install(path); err != nil {
2253+
failEvent("install", err.Error())
2254+
}
2255+
// Install calls os.Exit on success — execution never reaches here.
2256+
}()
2257+
}
2258+
2259+
// CancelUpdate cancels an in-progress update download.
2260+
// Has no effect if no update is running.
2261+
func (a *App) CancelUpdate() {
2262+
a.updateMu.Lock()
2263+
defer a.updateMu.Unlock()
2264+
if a.updateCancel != nil {
2265+
a.updateCancel()
2266+
}
2267+
}

build-linux.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ LDFLAGS=""
2121
if [ -n "${SUBSCRIPTION_ENCRYPT_KEY:-}" ]; then
2222
LDFLAGS="-X resultproxy-wails/internal/proxy.subscriptionEncryptKey=${SUBSCRIPTION_ENCRYPT_KEY}"
2323
fi
24+
if [ -n "${MANIFEST_URL_OVERRIDE:-}" ]; then
25+
LDFLAGS="${LDFLAGS} -X resultproxy-wails/internal/updater.ManifestURLOverride=${MANIFEST_URL_OVERRIDE}"
26+
fi
2427

2528
echo "==> wails build (linux/amd64) version=$VERSION"
2629
# webkit2_41 selects libwebkit2gtk-4.1 (Ubuntu 22.04+/24.04, Debian 12+).

build-macos.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ LDFLAGS=""
2929
if [ -n "${SUBSCRIPTION_ENCRYPT_KEY:-}" ]; then
3030
LDFLAGS="-X resultproxy-wails/internal/proxy.subscriptionEncryptKey=${SUBSCRIPTION_ENCRYPT_KEY}"
3131
fi
32+
if [ -n "${MANIFEST_URL_OVERRIDE:-}" ]; then
33+
LDFLAGS="${LDFLAGS} -X resultproxy-wails/internal/updater.ManifestURLOverride=${MANIFEST_URL_OVERRIDE}"
34+
fi
3235

3336
echo "==> wails build (darwin/universal)"
3437
if [ -n "$LDFLAGS" ]; then

0 commit comments

Comments
 (0)