Windows Updater Architecture & Release Guide
To solve Windows file-locking issues, anti-virus alerts, and package size overhead, the auto-update pipeline uses a dedicated, lightweight console-based updater separate from the main application.
1. How the Updater Works (Architecture)
The update flow is split into a two-step bootstrap process to cleanly replace locked files:
sequenceDiagram
participant App as Main App (vpn-share-tool)
participant Server as Discovery Server
participant Updater as Updater (updater.exe)
App->>Server: 1. Check updates (/latest-app-version)
Server-->>App: New version available (e.g., v40b)
App->>Server: 2. Download updater (/latest-version)
Server-->>App: Returns updater.exe
App->>Updater: 3. Launch updater.exe & self-terminate
Note over Updater: 4. Wait for main app to exit
Updater->>Server: 5. Download app ZIP (/latest-app-version?format=zip)
Server-->>Updater: Returns vpn-share-tool-app_v40b.zip
Updater->>Updater: 6. Unzip & overwrite vpn-share-tool.exe
Updater->>App: 7. Launch updated vpn-share-tool.exe
Note over Updater: 8. Exit
Modes of Operation
- Bootstrap Mode: When the updater is executed with the name
vpn-share-tool.exe(such as when legacy clients directly replace their main executable with the updater file), it copies itself toupdater.exe, spawnsupdater.exe --source vpn-share-tool.exe, and exits immediately. - Upgrade Mode: Running as
updater.exewith a--sourceflag, it waits for the main application process to exit and release file locks, downloads the zip release of the actual application, extracts/overwrites the target binary, and restarts the application.
2. Updater vs. Main App Differences
| Feature | Main Application (vpn-share-tool) | Updater (updater.exe) |
|---|---|---|
| Role | GUI proxy sharing & client dashboard | Lightweight binary replacement agent |
| Interface | Fyne Desktop GUI (Interactive) | Console (CLI outputs, progress bars) |
| Size | ~64 MB | ~6.5 MB |
| Go Version | go >= 1.25 (Required by Sentry) | go 1.24 / pure Go |
| CGO | Enabled (OpenGL / graphics drivers) | Disabled (CGO_ENABLED=0) |
| Release File | vpn-share-tool-app_vXX.zip | vpn-share-tool_vXX.exe, vpn-share-tool_vXX.zip |
3. Build & Release Commands
All compilation and publishing tasks are managed by the custom development CLI (go run ./dev).
A. The Updater Binary
To build and release updates to the updater binary itself (e.g., when improving the updater's unzip logic):
-
Build:
go run ./dev build updaterThis reads the current version from
Release.tomland compilesdist/updater.exe(~6.5MB) using compile-time optimization and version injection flags (-trimpathand-ldflags="-s -w -X main.UpdaterVersion=vXX"). This ensures the updater knows its own version and avoids infinite update loops. -
Release:
go run ./dev release-windows --updaterCopies the updater executable and its ZIP package (renamed to
vpn-share-tool_vXX.exeandvpn-share-tool_vXX.zip) to the Samba share path. No hash (.sha256) files are uploaded to maintain backwards compatibility with legacy client versions (e.g.,37b).
B. The Main Application
To build and release updates to the main application:
-
Build:
- Local build (using local mingw-w64 toolchain):
go run ./dev build windows --local - Container build (using
fyne-crossDocker image):go run ./dev build windows
This bumps the version count, embeds frontend assets, and generates the application executable.
- Local build (using local mingw-w64 toolchain):
-
Release:
go run ./dev release-windowsCompresses the application into
vpn-share-tool-app_vXX.zipand uploads it to the Samba share alongside its.sha256integrity verification file. Only the.ziparchive is uploaded for the app to optimize network traffic and disk usage on the share.
4. Client Transition & Backwards Compatibility Guide
With the removal of the separate updater.exe from the new client updating flow, we transition clients in two steps to maintain compatibility with all client eras (Extremely Old e.g. v37b, Medium-Old e.g. v38 - v40c, and New client versions):
Era 1: Extremely Old Clients (e.g., v37b)
- Behavior: These clients check
/latest-version?format=zipdirectly for the main application update. - Transition: When we serve
vpn-share-tool_vXX.zip(containing the updater compiled asvpn-share-tool.exe), these clients download it and overwrite themselves. On startup, the updater detects it is namedvpn-share-tool.exeand enters Bootstrap Mode, copying itself toupdater.exe, spawning it, and exiting. The spawnedupdater.exethen downloads and installsvpn-share-tool-app_vXX.zip(the new app).
Era 2: Medium-Old Clients (e.g., v38 - v40c)
- Behavior: These clients query
/latest-app-versionfor the app update, but downloadupdater.exefrom/latest-versionto apply it. - Transition Step 1 (Upgrade Clients): Publish the new client version using the
vpn-share-tool-app_vXX.zipnaming pattern (e.g.,vpn-share-tool-app_v40d.zip). Medium-old clients'updater.exewill download, extract, and successfully upgrade them tov40d. Once upgraded, no active clients useupdater.exeanymore; they all update directly viaupdate.bat. - Transition Step 2 (Stop Using
-appSuffix): Once all clients runv40dor newer, subsequent versions (e.g.,v41a) can be published directly as the base packagevpn-share-tool_v41a.zip. The discovery server will fall back to match both-appand base package patterns for/latest-app-version, updating the clients successfully.