diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-01 21:35:30 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-01 21:38:36 +0100 |
| commit | 7830b3c5e89f0339949940b8986bf4849ad7f223 (patch) | |
| tree | d4ebb4f10583cef1da3b181e093dd5d65ac8a0bb | |
| parent | v4.2.1: plain-language game copy and a balance fetch on login (diff) | |
| download | zagan-bet-7830b3c5e89f0339949940b8986bf4849ad7f223.tar.gz zagan-bet-7830b3c5e89f0339949940b8986bf4849ad7f223.zip | |
v4.3.0: package the desktop app with verifiable installers
publish.sh builds the GUI with the gui-release profile, names it zagan-bet-gui-<version>-<platform>-<arch>, and renders a bash and a PowerShell installer next to each app. Both embed the app's SHA-256, verify the file (or fetch it), install per-user and add a launcher: a desktop entry plus an SVG icon on Linux, a Start-menu shortcut on Windows.
The download page gains a Desktop app section with the apps and installers, keeps the terminal client and server, links the public git repository for the GPL source, and lists every file in the sha256sum block. deploy.sh verifies all four artifact kinds. Publishing refuses a dirty tree so the linked history matches the binaries.
| -rw-r--r-- | AGENTS.md | 6 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | docs/GUI-PLAN.md | 31 | ||||
| -rw-r--r-- | docs/TESTING.md | 17 | ||||
| -rw-r--r-- | gui/Cargo.toml | 2 | ||||
| -rw-r--r-- | gui/assets/zagan-bet.svg | 6 | ||||
| -rwxr-xr-x | scripts/deploy.sh | 9 | ||||
| -rw-r--r-- | scripts/installers/linux.sh.in | 78 | ||||
| -rw-r--r-- | scripts/installers/windows.ps1.in | 75 | ||||
| -rwxr-xr-x | scripts/publish.sh | 66 | ||||
| -rw-r--r-- | scripts/render-installer.py | 49 | ||||
| -rw-r--r-- | web/README.md | 43 | ||||
| -rw-r--r-- | web/index.php | 78 |
13 files changed, 416 insertions, 46 deletions
| @@ -85,6 +85,12 @@ | |||
| 85 | - The embedded fonts have no suit or arrow glyphs. Draw card suits as shapes | 85 | - The embedded fonts have no suit or arrow glyphs. Draw card suits as shapes |
| 86 | and use plain words for navigation; a glyph that is not in Open Sans or Hack | 86 | and use plain words for navigation; a glyph that is not in Open Sans or Hack |
| 87 | renders as tofu. | 87 | renders as tofu. |
| 88 | - `scripts/publish.sh` builds the GUI with `gui-release` and renders the | ||
| 89 | installers with the published SHA-256. Installers verify the hash and install | ||
| 90 | per-user; never install system-wide or skip the check. | ||
| 91 | - The download page links the public git repository | ||
| 92 | (https://git.2137697.xyz/zagan-bet.git) for the GPL corresponding source. | ||
| 93 | Run publish from a clean tree so the linked history matches the binaries. | ||
| 88 | 94 | ||
| 89 | ## Client TUI | 95 | ## Client TUI |
| 90 | - `render_lines()` and `render()` must agree. If `render()` uses `\r\n`, | 96 | - `render_lines()` and `render()` must agree. If `render()` uses `\r\n`, |
| @@ -3,7 +3,7 @@ members = ["gui"] | |||
| 3 | 3 | ||
| 4 | [package] | 4 | [package] |
| 5 | name = "zagan-bet" | 5 | name = "zagan-bet" |
| 6 | version = "4.2.1" | 6 | version = "4.3.0" |
| 7 | edition = "2024" | 7 | edition = "2024" |
| 8 | license = "GPL-3.0-or-later" | 8 | license = "GPL-3.0-or-later" |
| 9 | 9 | ||
diff --git a/docs/GUI-PLAN.md b/docs/GUI-PLAN.md index 89cf495..f058e41 100644 --- a/docs/GUI-PLAN.md +++ b/docs/GUI-PLAN.md | |||
| @@ -162,18 +162,29 @@ Measured on Linux at 1080p with llvmpipe software GL: | |||
| 162 | **Gate:** the screenshot set is ready for review. Remaining for the gate: | 162 | **Gate:** the screenshot set is ready for review. Remaining for the gate: |
| 163 | frame rate on integrated graphics and the Windows interactive pass. | 163 | frame rate on integrated graphics and the Windows interactive pass. |
| 164 | 164 | ||
| 165 | ## Phase 5 — packaging | 165 | ## Phase 5 — packaging (code complete, v4.3.0) |
| 166 | ## Phase 5 — packaging | 166 | |
| 167 | 167 | - `publish.sh` builds the GUI with the `gui-release` profile for Linux and | |
| 168 | - `publish.sh` emits `zagan-bet-gui-<version>-<platform>-<arch>[.exe]`. | 168 | Windows and names the app `zagan-bet-gui-<version>-<platform>-<arch>[.exe]`. |
| 169 | - Bash and PowerShell installers that verify the SHA-256, install to the user | 169 | - It renders a bash installer and a PowerShell installer next to each app. |
| 170 | directory, and create `.desktop`/Start-menu entries. | 170 | Both embed the app's SHA-256, verify the file (or download it), install |
| 171 | - Download page lists raw binaries and installers; add the source-code link. | 171 | per-user and add a launcher: `.desktop` plus an SVG icon on Linux, a |
| 172 | 172 | Start-menu shortcut on Windows. Templates live in `scripts/installers/`; | |
| 173 | **Gate:** `deploy.sh` verifies both artifact kinds; a clean machine installs | 173 | `render-installer.py` fills them in. |
| 174 | from the page and launches. | 174 | - The download page scans `bin/gui`, `bin/client` and `bin/server`, lists |
| 175 | apps, installers, clients and servers, and includes every file in the | ||
| 176 | `sha256sum` block. A Source section links the public git repository | ||
| 177 | (<https://git.2137697.xyz/zagan-bet.git>) for the GPL corresponding source. | ||
| 178 | `deploy.sh` verifies every artifact kind over the public URL. | ||
| 179 | - `publish.sh` refuses to run from a dirty tree so the linked history matches | ||
| 180 | the binaries. | ||
| 181 | |||
| 182 | **Gate:** deploy verification passes for apps, installers, clients and | ||
| 183 | servers; the Linux installer is exercised in a clean HOME. The Windows | ||
| 184 | installer needs a Windows machine before the gate closes. | ||
| 175 | 185 | ||
| 176 | ## Testing split | 186 | ## Testing split |
| 187 | ## Testing split | ||
| 177 | 188 | ||
| 178 | - `View`/`Command` tests in the core: flows, gating, state. Always. | 189 | - `View`/`Command` tests in the core: flows, gating, state. Always. |
| 179 | - The TUI adapter remains the regression net through Phases 1–2. | 190 | - The TUI adapter remains the regression net through Phases 1–2. |
diff --git a/docs/TESTING.md b/docs/TESTING.md index 613cd08..c32ac22 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md | |||
| @@ -266,3 +266,20 @@ terminal client; a saved login from one signs in the other. | |||
| 266 | the row is upgraded to bcrypt. | 266 | the row is upgraded to bcrypt. |
| 267 | - Spin several times and confirm `plays` grows by one row per spin while | 267 | - Spin several times and confirm `plays` grows by one row per spin while |
| 268 | `users.balance` changes by `winnings - bet`. | 268 | `users.balance` changes by `winnings - bet`. |
| 269 | |||
| 270 | ## Packaging checklist | ||
| 271 | |||
| 272 | 1. Set the version in `Cargo.toml` and `gui/Cargo.toml` (same MAJOR.MINOR), | ||
| 273 | run `cargo test --workspace`, and commit. `publish.sh` refuses a dirty tree | ||
| 274 | because the site links the committed git history as the GPL source. | ||
| 275 | 2. `./scripts/publish.sh` (add `DEST=` and `URL_BASE=` to stage elsewhere). It | ||
| 276 | builds the GUI with `gui-release`, the terminal clients and servers, and | ||
| 277 | renders the bash/PowerShell installers with each app's SHA-256. | ||
| 278 | 3. `php -S 127.0.0.1:8899 -t <staging>` and | ||
| 279 | `./scripts/deploy.sh <staging> http://127.0.0.1:8899/` to upload and verify | ||
| 280 | every app, installer, client and server against the page's checksums. | ||
| 281 | 4. On a clean user account: download an app with its installer, run the | ||
| 282 | installer, and launch the new menu entry. The installer must refuse a | ||
| 283 | corrupted download. | ||
| 284 | 5. Repeat on Windows for the `.ps1` installer and the Start-menu shortcut. | ||
| 285 | |||
diff --git a/gui/Cargo.toml b/gui/Cargo.toml index 5418794..8bcbda0 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "zagan-bet-gui" | 2 | name = "zagan-bet-gui" |
| 3 | version = "4.2.1" | 3 | version = "4.3.0" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | license = "GPL-3.0-or-later" | 5 | license = "GPL-3.0-or-later" |
| 6 | description = "Desktop frontend for zagan-bet" | 6 | description = "Desktop frontend for zagan-bet" |
diff --git a/gui/assets/zagan-bet.svg b/gui/assets/zagan-bet.svg new file mode 100644 index 0000000..74e5a3a --- /dev/null +++ b/gui/assets/zagan-bet.svg | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64"> | ||
| 2 | <rect width="64" height="64" rx="14" fill="#0a0e12"/> | ||
| 3 | <rect x="9" y="9" width="46" height="46" rx="10" fill="#0f1a14" stroke="#1f7d52" stroke-width="2"/> | ||
| 4 | <path d="M22 20h20L22 44h20" fill="none" stroke="#4ec27b" stroke-width="6" | ||
| 5 | stroke-linecap="round" stroke-linejoin="round"/> | ||
| 6 | </svg> | ||
diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 99129ad..b18d462 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #!/usr/bin/env bash | 1 | #!/usr/bin/env bash |
| 2 | # Upload web/ and verify every published artifact over the public URL. | 2 | # Upload web/ and verify every published artifact (GUI app and installers, |
| 3 | # terminal client and server) over the public URL. | ||
| 3 | # | 4 | # |
| 4 | # Usage: | 5 | # Usage: |
| 5 | # ./scripts/deploy.sh user@host:/srv/zagan.bet https://zagan.bet/ | 6 | # ./scripts/deploy.sh user@host:/srv/zagan.bet https://zagan.bet/ |
| @@ -50,7 +51,11 @@ done | |||
| 50 | [ -f web/index.php ] || die "web/index.php is missing" | 51 | [ -f web/index.php ] || die "web/index.php is missing" |
| 51 | 52 | ||
| 52 | shopt -s nullglob | 53 | shopt -s nullglob |
| 53 | artifacts=(web/bin/client/zagan-bet-* web/bin/server/zagan-bet-*) | 54 | artifacts=( |
| 55 | web/bin/gui/zagan-bet-* | ||
| 56 | web/bin/client/zagan-bet-* | ||
| 57 | web/bin/server/zagan-bet-* | ||
| 58 | ) | ||
| 54 | shopt -u nullglob | 59 | shopt -u nullglob |
| 55 | [ ${#artifacts[@]} -gt 0 ] || die "no artifacts in web/bin; run scripts/publish.sh first" | 60 | [ ${#artifacts[@]} -gt 0 ] || die "no artifacts in web/bin; run scripts/publish.sh first" |
| 56 | 61 | ||
diff --git a/scripts/installers/linux.sh.in b/scripts/installers/linux.sh.in new file mode 100644 index 0000000..5b53c02 --- /dev/null +++ b/scripts/installers/linux.sh.in | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # Zagan-Bet desktop installer for Linux. | ||
| 3 | # | ||
| 4 | # Verifies the app against its published SHA-256, installs it for the current | ||
| 5 | # user and adds a launcher. Put the downloaded app next to this script, or run | ||
| 6 | # the script on its own and it will fetch the matching binary. | ||
| 7 | set -euo pipefail | ||
| 8 | |||
| 9 | VERSION="__VERSION__" | ||
| 10 | BINARY="__BINARY__" | ||
| 11 | SHA256="__SHA256__" | ||
| 12 | URL="__URL__" | ||
| 13 | |||
| 14 | say() { printf '%s\n' "$*"; } | ||
| 15 | die() { printf 'install: %s\n' "$*" >&2; exit 1; } | ||
| 16 | |||
| 17 | command -v sha256sum >/dev/null 2>&1 || die "sha256sum is required" | ||
| 18 | |||
| 19 | here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) | ||
| 20 | source_file="" | ||
| 21 | for candidate in "$here/$BINARY" "./$BINARY" "$HOME/Downloads/$BINARY"; do | ||
| 22 | if [ -f "$candidate" ]; then | ||
| 23 | source_file=$candidate | ||
| 24 | break | ||
| 25 | fi | ||
| 26 | done | ||
| 27 | |||
| 28 | cleanup="" | ||
| 29 | if [ -z "$source_file" ]; then | ||
| 30 | command -v curl >/dev/null 2>&1 || die "put $BINARY next to this installer, or install curl" | ||
| 31 | cleanup=$(mktemp) || die "cannot create a temporary file" | ||
| 32 | say "Downloading $BINARY..." | ||
| 33 | curl -fsSL --max-time 300 "$URL" -o "$cleanup" || die "download failed" | ||
| 34 | source_file=$cleanup | ||
| 35 | fi | ||
| 36 | trap 'if [ -n "$cleanup" ]; then rm -f "$cleanup"; fi' EXIT | ||
| 37 | |||
| 38 | actual=$(sha256sum "$source_file" | awk '{print $1}') | ||
| 39 | [ "$actual" = "$SHA256" ] || die "checksum mismatch: expected $SHA256, got $actual" | ||
| 40 | |||
| 41 | bin_dir="${XDG_BIN_HOME:-$HOME/.local/bin}" | ||
| 42 | data_dir="${XDG_DATA_HOME:-$HOME/.local/share}" | ||
| 43 | app="$bin_dir/zagan-bet-gui" | ||
| 44 | desktop_dir="$data_dir/applications" | ||
| 45 | icon_dir="$data_dir/icons/hicolor/scalable/apps" | ||
| 46 | |||
| 47 | mkdir -p "$bin_dir" "$desktop_dir" "$icon_dir" | ||
| 48 | install -m 0755 "$source_file" "$app" | ||
| 49 | |||
| 50 | cat > "$icon_dir/zagan-bet.svg" <<'ICON' | ||
| 51 | __ICON__ | ||
| 52 | ICON | ||
| 53 | |||
| 54 | cat > "$desktop_dir/zagan-bet.desktop" <<DESKTOP | ||
| 55 | [Desktop Entry] | ||
| 56 | Type=Application | ||
| 57 | Name=Zagan-Bet | ||
| 58 | Comment=Slots, roulette, blackjack and crash | ||
| 59 | Exec=$app | ||
| 60 | Icon=zagan-bet | ||
| 61 | Terminal=false | ||
| 62 | Categories=Game; | ||
| 63 | DESKTOP | ||
| 64 | chmod 0644 "$desktop_dir/zagan-bet.desktop" "$icon_dir/zagan-bet.svg" | ||
| 65 | |||
| 66 | if command -v update-desktop-database >/dev/null 2>&1; then | ||
| 67 | update-desktop-database "$desktop_dir" >/dev/null 2>&1 || true | ||
| 68 | fi | ||
| 69 | if command -v gtk-update-icon-cache >/dev/null 2>&1; then | ||
| 70 | gtk-update-icon-cache -q "$data_dir/icons/hicolor" >/dev/null 2>&1 || true | ||
| 71 | fi | ||
| 72 | |||
| 73 | say "Installed Zagan-Bet $VERSION to $app" | ||
| 74 | say "A launcher was added to your applications menu." | ||
| 75 | case ":$PATH:" in | ||
| 76 | *":$bin_dir:"*) ;; | ||
| 77 | *) say "Add $bin_dir to PATH to start it as 'zagan-bet-gui'." ;; | ||
| 78 | esac | ||
diff --git a/scripts/installers/windows.ps1.in b/scripts/installers/windows.ps1.in new file mode 100644 index 0000000..fd2b8b3 --- /dev/null +++ b/scripts/installers/windows.ps1.in | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | # Zagan-Bet desktop installer for Windows. | ||
| 2 | # | ||
| 3 | # Verifies the app against its published SHA-256, installs it for the current | ||
| 4 | # user and adds a Start-menu shortcut. Put the downloaded app next to this | ||
| 5 | # script, or run the script on its own and it will fetch the matching binary. | ||
| 6 | # | ||
| 7 | # Run it with: | ||
| 8 | # powershell -ExecutionPolicy Bypass -File .\zagan-bet-gui-*-install.ps1 | ||
| 9 | $ErrorActionPreference = "Stop" | ||
| 10 | |||
| 11 | $Version = "__VERSION__" | ||
| 12 | $Binary = "__BINARY__" | ||
| 13 | $Sha256 = "__SHA256__" | ||
| 14 | $Url = "__URL__" | ||
| 15 | |||
| 16 | function Stop-Install([string]$Message) { | ||
| 17 | Write-Host "install: $Message" -ForegroundColor Red | ||
| 18 | exit 1 | ||
| 19 | } | ||
| 20 | |||
| 21 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path | ||
| 22 | $candidates = @( | ||
| 23 | (Join-Path $here $Binary), | ||
| 24 | (Join-Path (Get-Location) $Binary), | ||
| 25 | (Join-Path $env:USERPROFILE "Downloads\$Binary") | ||
| 26 | ) | ||
| 27 | $sourceFile = $null | ||
| 28 | foreach ($candidate in $candidates) { | ||
| 29 | if (Test-Path -LiteralPath $candidate) { | ||
| 30 | $sourceFile = $candidate | ||
| 31 | break | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | $temporary = $null | ||
| 36 | if (-not $sourceFile) { | ||
| 37 | $temporary = Join-Path ([System.IO.Path]::GetTempPath()) $Binary | ||
| 38 | Write-Host "Downloading $Binary..." | ||
| 39 | try { | ||
| 40 | Invoke-WebRequest -Uri $Url -OutFile $temporary -UseBasicParsing | ||
| 41 | } catch { | ||
| 42 | Stop-Install "download failed: $_" | ||
| 43 | } | ||
| 44 | $sourceFile = $temporary | ||
| 45 | } | ||
| 46 | |||
| 47 | try { | ||
| 48 | $actual = (Get-FileHash -LiteralPath $sourceFile -Algorithm SHA256).Hash.ToLowerInvariant() | ||
| 49 | if ($actual -ne $Sha256.ToLowerInvariant()) { | ||
| 50 | Stop-Install "checksum mismatch: expected $Sha256, got $actual" | ||
| 51 | } | ||
| 52 | |||
| 53 | $installDir = Join-Path $env:LOCALAPPDATA "Programs\Zagan-Bet" | ||
| 54 | New-Item -ItemType Directory -Force -Path $installDir | Out-Null | ||
| 55 | $target = Join-Path $installDir "zagan-bet-gui.exe" | ||
| 56 | Copy-Item -LiteralPath $sourceFile -Destination $target -Force | ||
| 57 | |||
| 58 | $startMenu = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs" | ||
| 59 | New-Item -ItemType Directory -Force -Path $startMenu | Out-Null | ||
| 60 | $shortcutPath = Join-Path $startMenu "Zagan-Bet.lnk" | ||
| 61 | $shell = New-Object -ComObject WScript.Shell | ||
| 62 | $shortcut = $shell.CreateShortcut($shortcutPath) | ||
| 63 | $shortcut.TargetPath = $target | ||
| 64 | $shortcut.WorkingDirectory = $installDir | ||
| 65 | $shortcut.IconLocation = "$target,0" | ||
| 66 | $shortcut.Description = "Slots, roulette, blackjack and crash" | ||
| 67 | $shortcut.Save() | ||
| 68 | |||
| 69 | Write-Host "Installed Zagan-Bet $Version to $target" | ||
| 70 | Write-Host "A Start-menu shortcut was created." | ||
| 71 | } finally { | ||
| 72 | if ($temporary -and (Test-Path -LiteralPath $temporary)) { | ||
| 73 | Remove-Item -LiteralPath $temporary -Force | ||
| 74 | } | ||
| 75 | } | ||
diff --git a/scripts/publish.sh b/scripts/publish.sh index 8240859..3a04631 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh | |||
| @@ -3,14 +3,22 @@ | |||
| 3 | # download page expects: | 3 | # download page expects: |
| 4 | # | 4 | # |
| 5 | # zagan-bet-client-<version>-<platform>-<arch>[.exe] | 5 | # zagan-bet-client-<version>-<platform>-<arch>[.exe] |
| 6 | # zagan-bet-server-<version>-<platform>-<arch> | 6 | # zagan-bet-server-<version>-<platform>-<arch>[.exe] |
| 7 | # zagan-bet-gui-<version>-<platform>-<arch>[.exe] | ||
| 8 | # zagan-bet-gui-<version>-<platform>-<arch>-install.sh | ||
| 9 | # zagan-bet-gui-<version>-<platform>-<arch>-install.ps1 | ||
| 7 | # | 10 | # |
| 8 | # Cargo always writes target/<triple>/release/<bin>, so the rename happens here | 11 | # Cargo always writes target/<triple>/<profile>/<bin>, so the rename happens |
| 9 | # after each build. The version comes from Cargo.toml. | 12 | # here after each build. The version comes from Cargo.toml. |
| 13 | # | ||
| 14 | # The GUI uses the workspace's `gui-release` profile (small, stripped, LTO). | ||
| 15 | # The public git repository is the GPL source for these binaries, so publish | ||
| 16 | # from a clean tree (or set ALLOW_DIRTY=1 for a preview). | ||
| 10 | # | 17 | # |
| 11 | # Usage: | 18 | # Usage: |
| 12 | # ./scripts/publish.sh | 19 | # ./scripts/publish.sh |
| 13 | # DEST=/srv/www/bin ./scripts/publish.sh | 20 | # DEST=/srv/www/bin ./scripts/publish.sh |
| 21 | # URL_BASE=https://staging.example/ ./scripts/publish.sh | ||
| 14 | set -euo pipefail | 22 | set -euo pipefail |
| 15 | 23 | ||
| 16 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) | 24 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) |
| @@ -23,6 +31,21 @@ if [ -z "${VERSION:-}" ]; then | |||
| 23 | fi | 31 | fi |
| 24 | 32 | ||
| 25 | DEST=${DEST:-web/bin} | 33 | DEST=${DEST:-web/bin} |
| 34 | URL_BASE=${URL_BASE:-https://zagan.2137697.xyz} | ||
| 35 | |||
| 36 | if [ "${ALLOW_DIRTY:-0}" != "1" ] && [ -n "$(git status --porcelain)" ]; then | ||
| 37 | echo "the working tree is dirty; commit the release first (or ALLOW_DIRTY=1)" >&2 | ||
| 38 | exit 1 | ||
| 39 | fi | ||
| 40 | |||
| 41 | command -v python3 >/dev/null || { | ||
| 42 | echo "python3 is required to render the installers" >&2 | ||
| 43 | exit 1 | ||
| 44 | } | ||
| 45 | |||
| 46 | hash_of() { | ||
| 47 | sha256sum "$1" | awk '{print $1}' | ||
| 48 | } | ||
| 26 | 49 | ||
| 27 | publish() { | 50 | publish() { |
| 28 | local triple=$1 kind=$2 platform=$3 arch=$4 | 51 | local triple=$1 kind=$2 platform=$3 arch=$4 |
| @@ -47,11 +70,46 @@ publish() { | |||
| 47 | echo " $DEST/$kind/$artifact ($(du -h "$DEST/$kind/$artifact" | cut -f1))" | 70 | echo " $DEST/$kind/$artifact ($(du -h "$DEST/$kind/$artifact" | cut -f1))" |
| 48 | } | 71 | } |
| 49 | 72 | ||
| 73 | publish_gui() { | ||
| 74 | local triple=$1 platform=$2 arch=$3 | ||
| 75 | local ext="" | ||
| 76 | if [ "$platform" = windows ]; then | ||
| 77 | ext=".exe" | ||
| 78 | fi | ||
| 79 | |||
| 80 | local artifact="zagan-bet-gui-$VERSION-$platform-$arch$ext" | ||
| 81 | local source="target/$triple/gui-release/zagan-bet-gui$ext" | ||
| 82 | |||
| 83 | echo "==> $artifact" | ||
| 84 | cargo build -p zagan-bet-gui --profile gui-release --quiet --target "$triple" | ||
| 85 | |||
| 86 | mkdir -p "$DEST/gui" | ||
| 87 | install -m 0755 "$source" "$DEST/gui/$artifact" | ||
| 88 | local sha | ||
| 89 | sha=$(hash_of "$DEST/gui/$artifact") | ||
| 90 | echo " $DEST/gui/$artifact ($(du -h "$DEST/gui/$artifact" | cut -f1))" | ||
| 91 | |||
| 92 | if [ "$platform" = linux ]; then | ||
| 93 | python3 scripts/render-installer.py \ | ||
| 94 | scripts/installers/linux.sh.in \ | ||
| 95 | "$DEST/gui/zagan-bet-gui-$VERSION-linux-$arch-install.sh" \ | ||
| 96 | "$VERSION" "$artifact" "$sha" "$URL_BASE/bin/gui/$artifact" | ||
| 97 | elif [ "$platform" = windows ]; then | ||
| 98 | python3 scripts/render-installer.py \ | ||
| 99 | scripts/installers/windows.ps1.in \ | ||
| 100 | "$DEST/gui/zagan-bet-gui-$VERSION-windows-$arch-install.ps1" \ | ||
| 101 | "$VERSION" "$artifact" "$sha" "$URL_BASE/bin/gui/$artifact" | ||
| 102 | fi | ||
| 103 | } | ||
| 104 | |||
| 105 | publish_gui x86_64-unknown-linux-gnu linux x86_64 | ||
| 106 | publish_gui x86_64-pc-windows-gnu windows x86_64 | ||
| 107 | |||
| 50 | publish x86_64-unknown-linux-gnu client linux x86_64 | 108 | publish x86_64-unknown-linux-gnu client linux x86_64 |
| 51 | publish i686-unknown-linux-gnu client linux i686 | 109 | publish i686-unknown-linux-gnu client linux i686 |
| 52 | publish x86_64-pc-windows-gnu client windows x86_64 | 110 | publish x86_64-pc-windows-gnu client windows x86_64 |
| 53 | publish x86_64-unknown-linux-gnu server linux x86_64 | 111 | publish x86_64-unknown-linux-gnu server linux x86_64 |
| 54 | publish x86_64-pc-windows-gnu server windows x86_64 | 112 | publish x86_64-pc-windows-gnu server windows x86_64 |
| 55 | 113 | ||
| 56 | echo | 114 | echo |
| 57 | echo "published $VERSION to $DEST" | 115 | echo "published $VERSION to $DEST" |
diff --git a/scripts/render-installer.py b/scripts/render-installer.py new file mode 100644 index 0000000..1a00551 --- /dev/null +++ b/scripts/render-installer.py | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | """Fill an installer template with one published artifact's details. | ||
| 3 | |||
| 4 | Usage: render-installer.py <template> <output> <version> <binary> <sha256> <url> | ||
| 5 | |||
| 6 | The Linux template embeds the application icon so the installer works offline. | ||
| 7 | """ | ||
| 8 | |||
| 9 | from __future__ import annotations | ||
| 10 | |||
| 11 | import pathlib | ||
| 12 | import sys | ||
| 13 | |||
| 14 | |||
| 15 | def main(argv: list[str]) -> int: | ||
| 16 | if len(argv) != 7: | ||
| 17 | print( | ||
| 18 | "usage: render-installer.py <template> <output> <version> " | ||
| 19 | "<binary> <sha256> <url>", | ||
| 20 | file=sys.stderr, | ||
| 21 | ) | ||
| 22 | return 2 | ||
| 23 | |||
| 24 | template, output, version, binary, sha256, url = argv[1:] | ||
| 25 | root = pathlib.Path(__file__).resolve().parent.parent | ||
| 26 | icon = (root / "gui" / "assets" / "zagan-bet.svg").read_text() | ||
| 27 | |||
| 28 | text = pathlib.Path(template).read_text() | ||
| 29 | replacements = { | ||
| 30 | "__VERSION__": version, | ||
| 31 | "__BINARY__": binary, | ||
| 32 | "__SHA256__": sha256, | ||
| 33 | "__URL__": url, | ||
| 34 | "__ICON__": icon.rstrip("\n"), | ||
| 35 | } | ||
| 36 | for placeholder, value in replacements.items(): | ||
| 37 | text = text.replace(placeholder, value) | ||
| 38 | |||
| 39 | destination = pathlib.Path(output) | ||
| 40 | destination.write_text(text) | ||
| 41 | if destination.suffix == ".sh": | ||
| 42 | destination.chmod(0o755) | ||
| 43 | |||
| 44 | print(f" {destination} ({destination.stat().st_size} bytes)") | ||
| 45 | return 0 | ||
| 46 | |||
| 47 | |||
| 48 | if __name__ == "__main__": | ||
| 49 | raise SystemExit(main(sys.argv)) | ||
diff --git a/web/README.md b/web/README.md index e79abd4..bd87e11 100644 --- a/web/README.md +++ b/web/README.md | |||
| @@ -1,15 +1,15 @@ | |||
| 1 | # Download page | 1 | # Download page |
| 2 | 2 | ||
| 3 | `index.php` scans `bin/client` and `bin/server` on every request and renders | 3 | `index.php` scans `bin/gui`, `bin/client` and `bin/server` on every request and |
| 4 | whatever builds it finds, with version, size and SHA-256. No database, no | 4 | renders whatever builds it finds, with version, size and SHA-256. No database, no JavaScript, no CSS, no dependencies. The page is plain |
| 5 | JavaScript, no CSS, no dependencies. The page is plain browser defaults: | 5 | browser defaults: black text, blue links, monospace checksums. PHP 8.0+. |
| 6 | black text, blue links, monospace checksums. PHP 8.0+. | ||
| 7 | 6 | ||
| 8 | ## Layout | 7 | ## Layout |
| 9 | 8 | ||
| 10 | ``` | 9 | ``` |
| 11 | web/ | 10 | web/ |
| 12 | index.php | 11 | index.php |
| 12 | bin/gui/ served at /bin/gui/... (app and installers) | ||
| 13 | bin/client/ served at /bin/client/... | 13 | bin/client/ served at /bin/client/... |
| 14 | bin/server/ served at /bin/server/... | 14 | bin/server/ served at /bin/server/... |
| 15 | ``` | 15 | ``` |
| @@ -22,13 +22,22 @@ The page only lists files that match the release pattern; anything else in | |||
| 22 | those directories is ignored. | 22 | those directories is ignored. |
| 23 | 23 | ||
| 24 | ``` | 24 | ``` |
| 25 | zagan-bet-client-<version>-<platform>-<arch>[.exe] | 25 | bin/gui/zagan-bet-gui-<version>-<platform>-<arch>[.exe] |
| 26 | zagan-bet-server-<version>-<platform>-<arch> | 26 | bin/gui/zagan-bet-gui-<version>-<platform>-<arch>-install.sh |
| 27 | bin/gui/zagan-bet-gui-<version>-<platform>-<arch>-install.ps1 | ||
| 28 | bin/client/zagan-bet-client-<version>-<platform>-<arch>[.exe] | ||
| 29 | bin/server/zagan-bet-server-<version>-<platform>-<arch>[.exe] | ||
| 27 | ``` | 30 | ``` |
| 28 | 31 | ||
| 29 | `<version>` is `MAJOR.MINOR.PATCH`, `<platform>` is `linux`, `windows` or | 32 | `<version>` is `MAJOR.MINOR.PATCH`, `<platform>` is `linux`, `windows` or |
| 30 | `macos`, `<arch>` is `x86_64`, `i686` or `aarch64`. | 33 | `macos`, `<arch>` is `x86_64`, `i686` or `aarch64`. |
| 31 | 34 | ||
| 35 | The installers are generated next to their app. They embed the app's SHA-256, | ||
| 36 | check the file (or download it) and install it for the current user: Linux | ||
| 37 | writes `~/.local/bin/zagan-bet-gui` plus a `.desktop` launcher, Windows writes | ||
| 38 | `%LOCALAPPDATA%\Programs\Zagan-Bet` plus a Start-menu shortcut. The source | ||
| 39 | archives satisfy the GPL's corresponding-source requirement. | ||
| 40 | |||
| 32 | ## Publishing a build | 41 | ## Publishing a build |
| 33 | 42 | ||
| 34 | From the repository root: | 43 | From the repository root: |
| @@ -37,15 +46,21 @@ From the repository root: | |||
| 37 | ./scripts/publish.sh | 46 | ./scripts/publish.sh |
| 38 | ``` | 47 | ``` |
| 39 | 48 | ||
| 40 | It reads the version from `Cargo.toml`, builds all four artifacts and installs | 49 | It reads the version from `Cargo.toml`, builds every artifact and installs |
| 41 | them under `web/bin` with the names above. Override the destination with | 50 | them under `web/bin` with the names above. The GUI is built with the |
| 42 | `DEST=/srv/www/bin ./scripts/publish.sh`. | 51 | workspace's `gui-release` profile (LTO, stripped) and the installers are |
| 52 | rendered with Python 3 and the published SHA-256. Run it from a clean tree so | ||
| 53 | the release commit is the source the page links to. Override the destination | ||
| 54 | with `DEST=/srv/www/bin ./scripts/publish.sh`, and the download origin baked | ||
| 55 | into the installers with `URL_BASE=https://staging.example/ ./scripts/publish.sh`. | ||
| 56 | `ALLOW_DIRTY=1` skips the clean-tree check for a preview. | ||
| 43 | 57 | ||
| 44 | Builds are per target triple, so these must be installed: | 58 | Builds are per target triple, so these must be installed: |
| 45 | `x86_64-unknown-linux-gnu`, `i686-unknown-linux-gnu` and | 59 | `x86_64-unknown-linux-gnu`, `i686-unknown-linux-gnu` and |
| 46 | `x86_64-pc-windows-gnu`, plus the mingw linker for the Windows build. Client | 60 | `x86_64-pc-windows-gnu`, plus the mingw linker for the Windows build. Client |
| 47 | builds always pass `--no-default-features`, which drops the server's OpenSSL | 61 | builds always pass `--no-default-features`, which drops the server's OpenSSL |
| 48 | dependency; the client is rustls-only. | 62 | dependency; the client is rustls-only. The GUI needs Python 3 at publish time |
| 63 | for the installer templates in `scripts/installers/`. | ||
| 49 | 64 | ||
| 50 | Cargo itself cannot produce these names: it always writes | 65 | Cargo itself cannot produce these names: it always writes |
| 51 | `target/<triple>/release/<bin>`. The script renames after each build. | 66 | `target/<triple>/release/<bin>`. The script renames after each build. |
| @@ -100,8 +115,9 @@ Then open <http://127.0.0.1:8899/>. | |||
| 100 | ``` | 115 | ``` |
| 101 | 116 | ||
| 102 | `deploy.sh` rsyncs `web/` with `--delay-updates`, so a visitor never sees a | 117 | `deploy.sh` rsyncs `web/` with `--delay-updates`, so a visitor never sees a |
| 103 | half-written binary, then fetches the live page and every artifact it lists and | 118 | half-written binary, then fetches the live page and every artifact it lists — |
| 104 | compares the downloaded bytes with the local SHA-256. `--verify-only` skips the | 119 | GUI apps, installers, terminal clients and servers — and compares the |
| 120 | downloaded bytes with the local SHA-256. `--verify-only` skips the | ||
| 105 | upload and only checks the live site. Old versions are left on the server; | 121 | upload and only checks the live site. Old versions are left on the server; |
| 106 | prune them by hand. | 122 | prune them by hand. |
| 107 | 123 | ||
| @@ -124,3 +140,6 @@ php -S 127.0.0.1:8899 -t /srv/staging | |||
| 124 | stay downloadable until you remove them from `bin/`. | 140 | stay downloadable until you remove them from `bin/`. |
| 125 | - The checksum block is in `sha256sum` format, so visitors can save it as | 141 | - The checksum block is in `sha256sum` format, so visitors can save it as |
| 126 | `SHA256SUMS` and run `sha256sum -c SHA256SUMS`. | 142 | `SHA256SUMS` and run `sha256sum -c SHA256SUMS`. |
| 143 | - The page links <https://git.2137697.xyz/zagan-bet.git> for the GPL | ||
| 144 | corresponding source; publish only from a committed release so that link | ||
| 145 | contains the exact source. | ||
diff --git a/web/index.php b/web/index.php index 7ed79da..77edf95 100644 --- a/web/index.php +++ b/web/index.php | |||
| @@ -4,20 +4,23 @@ declare(strict_types=1); | |||
| 4 | /** | 4 | /** |
| 5 | * zagan.bet download page. | 5 | * zagan.bet download page. |
| 6 | * | 6 | * |
| 7 | * Scans ./bin/client and ./bin/server and renders every build it finds, with | 7 | * Scans ./bin/{gui,client,server} and renders every build it finds, with its |
| 8 | * its version, size and SHA-256. No database, no JavaScript, no dependencies. | 8 | * version, size and SHA-256. The GPL source link points at the public git |
| 9 | * repository. No database, no JavaScript, no dependencies. | ||
| 9 | * | 10 | * |
| 10 | * Expected file names (anything else is ignored): | 11 | * Expected file names (anything else is ignored): |
| 11 | * | 12 | * |
| 12 | * bin/client/zagan-bet-client-<version>-<platform>-<arch> | 13 | * bin/gui/zagan-bet-gui-<version>-<platform>-<arch>[.exe] |
| 13 | * bin/client/zagan-bet-client-<version>-<platform>-<arch>.exe | 14 | * bin/gui/zagan-bet-gui-<version>-<platform>-<arch>-install.sh |
| 14 | * bin/server/zagan-bet-server-<version>-<platform>-<arch> | 15 | * bin/gui/zagan-bet-gui-<version>-<platform>-<arch>-install.ps1 |
| 16 | * bin/client/zagan-bet-client-<version>-<platform>-<arch>[.exe] | ||
| 17 | * bin/server/zagan-bet-server-<version>-<platform>-<arch>[.exe] | ||
| 15 | * | 18 | * |
| 16 | * <version> is MAJOR.MINOR.PATCH, <platform> is linux|windows|macos and | 19 | * <version> is MAJOR.MINOR.PATCH, <platform> is linux|windows|macos and |
| 17 | * <arch> is x86_64|i686|aarch64. Example: | 20 | * <arch> is x86_64|i686|aarch64. Example: |
| 18 | * | 21 | * |
| 19 | * bin/client/zagan-bet-client-3.1.1-linux-x86_64 | 22 | * bin/gui/zagan-bet-gui-4.3.0-linux-x86_64 |
| 20 | * bin/server/zagan-bet-server-3.1.1-linux-x86_64 | 23 | * bin/client/zagan-bet-client-4.3.0-linux-x86_64 |
| 21 | * | 24 | * |
| 22 | * SHA-256 values are cached in a JSON file keyed on size and mtime, so a file | 25 | * SHA-256 values are cached in a JSON file keyed on size and mtime, so a file |
| 23 | * is only re-read when it changes. The cache lives in the system temp | 26 | * is only re-read when it changes. The cache lives in the system temp |
| @@ -26,6 +29,10 @@ declare(strict_types=1); | |||
| 26 | */ | 29 | */ |
| 27 | 30 | ||
| 28 | const KINDS = [ | 31 | const KINDS = [ |
| 32 | 'gui' => [ | ||
| 33 | 'title' => 'Desktop app', | ||
| 34 | 'hint' => 'Windows 10 or newer, or a Linux desktop. No terminal needed.', | ||
| 35 | ], | ||
| 29 | 'client' => [ | 36 | 'client' => [ |
| 30 | 'title' => 'Client', | 37 | 'title' => 'Client', |
| 31 | 'hint' => 'Needs a terminal of at least 80×24 cells.', | 38 | 'hint' => 'Needs a terminal of at least 80×24 cells.', |
| @@ -163,7 +170,7 @@ function read_release( | |||
| 163 | bool &$dirty | 170 | bool &$dirty |
| 164 | ): ?array { | 171 | ): ?array { |
| 165 | $pattern = '/^zagan-bet-' . preg_quote($kind, '/') | 172 | $pattern = '/^zagan-bet-' . preg_quote($kind, '/') |
| 166 | . '-v?(\d+\.\d+\.\d+)-([a-z]+)-([a-z0-9_]+)(\.exe)?$/i'; | 173 | . '-v?(\d+\.\d+\.\d+)-([a-z]+)-([a-z0-9_]+)(-install\.sh|-install\.ps1|\.exe)?$/i'; |
| 167 | if (preg_match($pattern, $entry, $matches) !== 1) { | 174 | if (preg_match($pattern, $entry, $matches) !== 1) { |
| 168 | return null; | 175 | return null; |
| 169 | } | 176 | } |
| @@ -192,10 +199,14 @@ function read_release( | |||
| 192 | return null; | 199 | return null; |
| 193 | } | 200 | } |
| 194 | 201 | ||
| 202 | $suffix = strtolower($matches[4] ?? ''); | ||
| 203 | $variant = str_starts_with($suffix, '-install.') ? 'installer' : 'binary'; | ||
| 204 | |||
| 195 | return [ | 205 | return [ |
| 196 | 'version' => $matches[1], | 206 | 'version' => $matches[1], |
| 197 | 'platform' => strtolower($matches[2]), | 207 | 'platform' => strtolower($matches[2]), |
| 198 | 'arch' => strtolower($matches[3]), | 208 | 'arch' => strtolower($matches[3]), |
| 209 | 'variant' => $variant, | ||
| 199 | 'file' => $entry, | 210 | 'file' => $entry, |
| 200 | 'size' => $size, | 211 | 'size' => $size, |
| 201 | 'mtime' => $mtime, | 212 | 'mtime' => $mtime, |
| @@ -257,6 +268,10 @@ foreach (KINDS as $kind => $meta) { | |||
| 257 | if ($byArch !== 0) { | 268 | if ($byArch !== 0) { |
| 258 | return $byArch; | 269 | return $byArch; |
| 259 | } | 270 | } |
| 271 | $byVariant = ($a['variant'] === 'installer' ? 1 : 0) <=> ($b['variant'] === 'installer' ? 1 : 0); | ||
| 272 | if ($byVariant !== 0) { | ||
| 273 | return $byVariant; | ||
| 274 | } | ||
| 260 | return strcmp($a['file'], $b['file']); | 275 | return strcmp($a['file'], $b['file']); |
| 261 | }); | 276 | }); |
| 262 | 277 | ||
| @@ -280,18 +295,41 @@ if ($cacheDirty) { | |||
| 280 | <meta charset="utf-8"> | 295 | <meta charset="utf-8"> |
| 281 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 296 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 282 | <title>żagań.bet</title> | 297 | <title>żagań.bet</title> |
| 283 | <meta name="description" content="Official zagan.bet client and server downloads."> | 298 | <meta name="description" content="Official zagan.bet desktop app, terminal client and server downloads."> |
| 284 | <meta http-equiv="Content-Security-Policy" content="default-src 'none'"> | 299 | <meta http-equiv="Content-Security-Policy" content="default-src 'none'"> |
| 285 | </head> | 300 | </head> |
| 286 | <body> | 301 | <body> |
| 287 | 302 | ||
| 288 | <h1>żagań.bet</h1> | 303 | <h1>żagań.bet</h1> |
| 289 | <p>Official client and server builds.</p> | 304 | <p>Official desktop app, terminal client and server builds.</p> |
| 290 | <?php if ($newest > 0): ?> | 305 | <?php if ($newest > 0): ?> |
| 291 | <p>Builds published <?= e(gmdate('j M Y H:i', $newest)) ?> UTC.</p> | 306 | <p>Builds published <?= e(gmdate('j M Y H:i', $newest)) ?> UTC.</p> |
| 292 | <?php endif; ?> | 307 | <?php endif; ?> |
| 293 | 308 | ||
| 294 | <h2>Client</h2> | 309 | <h2>Desktop app</h2> |
| 310 | <p>Windows 10 or newer, or a Linux desktop. No terminal needed.</p> | ||
| 311 | <?php $guiBinaries = array_values(array_filter($releases['gui'], static fn (array $r): bool => $r['variant'] === 'binary')); ?> | ||
| 312 | <?php $guiInstallers = array_values(array_filter($releases['gui'], static fn (array $r): bool => $r['variant'] === 'installer')); ?> | ||
| 313 | <?php if ($guiBinaries === []): ?> | ||
| 314 | <p>Nothing published yet.</p> | ||
| 315 | <?php else: ?> | ||
| 316 | <ul> | ||
| 317 | <?php foreach ($guiBinaries as $release): ?> | ||
| 318 | <li><a href="<?= e($release['href']) ?>" download><?= e(PLATFORMS[$release['platform']] ?? ucfirst($release['platform'])) ?> <?= e($release['arch']) ?><?php if (isset(ARCHES[$release['arch']])): ?> (<?= e(ARCHES[$release['arch']]) ?>)<?php endif; ?> v<?= e($release['version']) ?> — <?= e(human_size($release['size'])) ?></a></li> | ||
| 319 | <?php endforeach; ?> | ||
| 320 | </ul> | ||
| 321 | <?php endif; ?> | ||
| 322 | <?php if ($guiInstallers !== []): ?> | ||
| 323 | <h3>Installers</h3> | ||
| 324 | <p>The installer checks the download, installs Zagan-Bet for your user and adds it to your programs. Run it next to a downloaded app, or on its own to fetch one.</p> | ||
| 325 | <ul> | ||
| 326 | <?php foreach ($guiInstallers as $release): ?> | ||
| 327 | <li><a href="<?= e($release['href']) ?>" download><?= e(PLATFORMS[$release['platform']] ?? ucfirst($release['platform'])) ?> <?= e($release['arch']) ?> installer (<?= str_ends_with($release['file'], '.ps1') ? 'PowerShell' : 'bash' ?>) v<?= e($release['version']) ?> — <?= e(human_size($release['size'])) ?></a></li> | ||
| 328 | <?php endforeach; ?> | ||
| 329 | </ul> | ||
| 330 | <?php endif; ?> | ||
| 331 | |||
| 332 | <h2>Terminal client</h2> | ||
| 295 | <p>Needs a terminal of at least 80×24 cells.</p> | 333 | <p>Needs a terminal of at least 80×24 cells.</p> |
| 296 | <?php if ($releases['client'] === []): ?> | 334 | <?php if ($releases['client'] === []): ?> |
| 297 | <p>Nothing published yet.</p> | 335 | <p>Nothing published yet.</p> |
| @@ -315,7 +353,7 @@ if ($cacheDirty) { | |||
| 315 | </ul> | 353 | </ul> |
| 316 | <?php endif; ?> | 354 | <?php endif; ?> |
| 317 | 355 | ||
| 318 | <?php $all = array_merge($releases['client'], $releases['server']); ?> | 356 | <?php $all = array_merge($releases['gui'], $releases['client'], $releases['server']); ?> |
| 319 | <?php if ($all !== []): ?> | 357 | <?php if ($all !== []): ?> |
| 320 | <h2>SHA-256</h2> | 358 | <h2>SHA-256</h2> |
| 321 | <p>On Linux use <code>sha256sum <file></code>. On Windows use <code>Get-FileHash <file></code>.</p> | 359 | <p>On Linux use <code>sha256sum <file></code>. On Windows use <code>Get-FileHash <file></code>.</p> |
| @@ -329,8 +367,17 @@ echo e($sums); | |||
| 329 | ?></pre> | 367 | ?></pre> |
| 330 | <?php endif; ?> | 368 | <?php endif; ?> |
| 331 | 369 | ||
| 370 | <h2>Source</h2> | ||
| 371 | <p>Zagan-Bet is free software under the GNU GPL v3 or later. The source for these builds is at <a href="https://git.2137697.xyz/zagan-bet.git">https://git.2137697.xyz/zagan-bet.git</a>.</p> | ||
| 372 | |||
| 332 | <h2>Running it</h2> | 373 | <h2>Running it</h2> |
| 333 | <p>Client:</p> | 374 | <p>Desktop app on Linux:</p> |
| 375 | <pre><code>chmod +x zagan-bet-gui-*-linux-x86_64-install.sh | ||
| 376 | ./zagan-bet-gui-*-linux-x86_64-install.sh</code></pre> | ||
| 377 | <p>Desktop app on Windows (PowerShell):</p> | ||
| 378 | <pre><code>powershell -ExecutionPolicy Bypass -File .\zagan-bet-gui-*-windows-x86_64-install.ps1</code></pre> | ||
| 379 | <p>The installers verify the SHA-256 before installing. You can also run the downloaded app directly.</p> | ||
| 380 | <p>Terminal client:</p> | ||
| 334 | <pre><code>chmod +x <downloaded-client> | 381 | <pre><code>chmod +x <downloaded-client> |
| 335 | ./<downloaded-client></code></pre> | 382 | ./<downloaded-client></code></pre> |
| 336 | <p>Server, first run creates <code>identity.p12</code>, <code>key.pem</code> and <code>cert.pem</code>:</p> | 383 | <p>Server, first run creates <code>identity.p12</code>, <code>key.pem</code> and <code>cert.pem</code>:</p> |
| @@ -338,8 +385,7 @@ echo e($sums); | |||
| 338 | ./<downloaded-server> --init | 385 | ./<downloaded-server> --init |
| 339 | ./<downloaded-server> -i 0.0.0.0 -p 11525</code></pre> | 386 | ./<downloaded-server> -i 0.0.0.0 -p 11525</code></pre> |
| 340 | 387 | ||
| 341 | <p>Windows: run the <code>.exe</code> from Windows Terminal or another real terminal.</p> | 388 | <p>Terminal client on Windows: run the <code>.exe</code> from Windows Terminal or another real terminal.</p> |
| 342 | 389 | <p>Run <code>help</code> inside the terminal client; the server binary supports <code>--help</code>.</p> | |
| 343 | <p>When lost, execute <code>help</code> command inside zagan.bet client. Server binary supports <code>--help</code> flag</p> | ||
| 344 | </body> | 390 | </body> |
| 345 | </html> | 391 | </html> |
