summaryrefslogtreecommitdiffstats
path: root/web/index.php
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-01 21:35:30 +0100
committersalmonik <salmonik@tuta.io>2026-11-01 21:38:36 +0100
commit7830b3c5e89f0339949940b8986bf4849ad7f223 (patch)
treed4ebb4f10583cef1da3b181e093dd5d65ac8a0bb /web/index.php
parentv4.2.1: plain-language game copy and a balance fetch on login (diff)
downloadzagan-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.
Diffstat (limited to 'web/index.php')
-rw-r--r--web/index.php78
1 files changed, 62 insertions, 16 deletions
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
28const KINDS = [ 31const 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 &lt;file&gt;</code>. On Windows use <code>Get-FileHash &lt;file&gt;</code>.</p> 359<p>On Linux use <code>sha256sum &lt;file&gt;</code>. On Windows use <code>Get-FileHash &lt;file&gt;</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 &lt;downloaded-client&gt; 381<pre><code>chmod +x &lt;downloaded-client&gt;
335./&lt;downloaded-client&gt;</code></pre> 382./&lt;downloaded-client&gt;</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./&lt;downloaded-server&gt; --init 385./&lt;downloaded-server&gt; --init
339./&lt;downloaded-server&gt; -i 0.0.0.0 -p 11525</code></pre> 386./&lt;downloaded-server&gt; -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>