Changeset 422b20d in Klonkt


Ignore:
Timestamp:
07/02/2026 03:07:42 PM (2 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
8b5c076
Parents:
7d61ab8
Message:

fix(updates): in-app updates on the Android app (third topology)

The Updates page only knew git topologies (GitHub checkout / fleet bare
repo); the Android app installs from a prebuilt tarball with no git, so
it showed "no update source reachable" and could never update itself.

New ANDROID topology, detected via process.platform === 'android'
(Termux node) with a filesystem fallback:

  • "Latest" = the package.json version on the klonkt STABLE branch (the channel the phone tarballs are built from), fetched with an 8s abort.
  • The update button spawns the phone's own klonkt-update detached; the shell survives the pkill/restart the updater performs.
  • Renders version chips (v1.3.1) instead of commit hashes; the existing view handles the null git fields as-is.
  • src/routes/admin-updates.js — IS_ANDROID detection, androidLatestVersion(), android branches in GET / and POST /run
  • CHANGELOG(.nl/.de).md — user-facing entry under Unreleased (3 languages)

Co-Authored-By: Claude <noreply@…>

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG.de.md

    r7d61ab8 r422b20d  
    55
    66## [Unreleased]
     7
     8### Behoben
     9- **Die Updates-Seite funktioniert jetzt in der Android-App.** Sie zeigt ab
     10  sofort die neueste verfügbare Version, und der Aktualisieren-Button lädt und
     11  installiert sie direkt auf dem Handy (Beiträge und Einstellungen bleiben
     12  erhalten).
    713
    814## [1.3.1] — 2026-07-02
  • CHANGELOG.md

    r7d61ab8 r422b20d  
    55
    66## [Unreleased]
     7
     8### Fixed
     9- **The Updates page now works in the Android app.** It now shows the newest
     10  available version, and the update button downloads and installs it right on
     11  your phone (your posts and settings are kept).
    712
    813## [1.3.1] — 2026-07-02
  • CHANGELOG.nl.md

    r7d61ab8 r422b20d  
    55
    66## [Unreleased]
     7
     8### Opgelost
     9- **De Updates-pagina werkt nu in de Android-app.** Hij toont voortaan de
     10  nieuwste beschikbare versie, en de bijwerk-knop downloadt en installeert die
     11  direct op je telefoon (je posts en instellingen blijven staan).
    712
    813## [1.3.1] — 2026-07-02
  • src/routes/admin-updates.js

    r7d61ab8 r422b20d  
    44 *   POST /admin/updates/run  -> fetch latest + restart (fleet only; see below)
    55 *
    6  * Two topologies are supported, detected automatically:
     6 * Three topologies are supported, detected automatically:
    77 *   - CHECKOUT (external self-hoster): the app dir is itself a git clone with
    88 *     origin = GitHub. "Latest" = origin/<branch> (fetched on view). Updating is
     
    1212 *     a `checkout -f` work-tree (no .git). "Latest" = <branch>. The detached
    1313 *     self-update script runs in-app (no root needed) → the button works.
     14 *   - ANDROID (the Klonkt phone app, Termux — node reports platform 'android'):
     15 *     installed from a prebuilt tarball, no git at all. "Latest" = the package
     16 *     version on the klonkt STABLE branch (the channel the phone tarballs are
     17 *     built from). The button runs the phone's own `klonkt-update` command
     18 *     detached, which survives the server restart it causes.
    1419 * git stderr is ignored so a foreign/missing repo never spams "fatal: ...".
    1520 */
     
    3540const IS_CHECKOUT = (() => { try { return fs.existsSync(path.join(APP_DIR, '.git')); } catch { return false; } })();
    3641const REMOTE_REF = IS_CHECKOUT ? `origin/${BRANCH}` : BRANCH; // what "latest" resolves to
     42
     43// The Klonkt Android app (Termux): node there reports platform 'android'; the
     44// filesystem check is belt-and-braces for exotic node builds.
     45const IS_ANDROID = process.platform === 'android'
     46  || (() => { try { return fs.existsSync('/data/data/com.termux/files/usr/bin'); } catch { return false; } })();
     47// Phone tarballs are built from the stable branch → that's the phone's "latest".
     48const ANDROID_LATEST_URL = 'https://raw.githubusercontent.com/roboburr/klonkt/stable/package.json';
     49
     50async function androidLatestVersion() {
     51  try {
     52    const ctl = new AbortController();
     53    const t = setTimeout(() => ctl.abort(), 8000);
     54    const r = await fetch(ANDROID_LATEST_URL, { signal: ctl.signal });
     55    clearTimeout(t);
     56    if (!r.ok) return null;
     57    return (await r.json()).version || null;
     58  } catch { return null; }
     59}
    3760
    3861function appVersion() {
     
    6285}
    6386
    64 router.get('/', requireGod, (req, res) => {
     87router.get('/', requireGod, async (req, res) => {
     88  // ANDROID: version-based check against the stable branch; the update button
     89  // runs the phone's klonkt-update (always present, the start script writes it).
     90  if (IS_ANDROID) {
     91    const cur = appVersion();
     92    const latest = await androidLatestVersion();
     93    return renderPage(req, res, 'pages/admin-updates', {
     94      pageTitleKey: 'admin.t_updates',
     95      bodyClass: 'on-admin',
     96      appVersion: cur,
     97      currentSha: cur ? 'v' + cur : null,
     98      currentDesc: null,
     99      latestSha: latest ? 'v' + latest : null,
     100      latestDesc: null,
     101      upToDate: !!(cur && latest && cur === latest),
     102      canCheck: !!latest,
     103      canSelfUpdate: true,
     104      manualCommand: null,
     105      behind: null,
     106      changes: [],
     107      success: req.query.success || null,
     108      error: req.query.error || null,
     109    });
     110  }
    65111  // For a GitHub checkout, refresh the remote ref so "latest" is current. Quiet +
    66112  // shallow; offline just leaves the last-known ref. stderr ignored (no log noise).
     
    93139
    94140router.post('/run', requireGod, (req, res) => {
     141  // ANDROID: run the phone's updater detached. It kills node (this process),
     142  // swaps the code while keeping storage/.env, and restarts everything — the
     143  // detached shell survives the pkill because it isn't a node process.
     144  if (IS_ANDROID) {
     145    try {
     146      const child = spawn('bash', ['-c', 'klonkt-update >> "$HOME/klonkt-update.log" 2>&1'], { detached: true, stdio: 'ignore' });
     147      child.unref();
     148    } catch (e) {
     149      return res.redirect('/admin/updates?error=' + encodeURIComponent('Kon update niet starten: ' + (e.message || e)));
     150    }
     151    return res.redirect('/admin/updates?success=' + encodeURIComponent('Bijwerken gestart — de site is ~1 minuut bezig (downloaden + herstarten). Ververs daarna deze pagina.'));
     152  }
    95153  if (!fs.existsSync(UPDATE_SCRIPT)) {
    96154    return res.redirect('/admin/updates?error=' + encodeURIComponent('In-app updaten is hier niet beschikbaar — werk bij met `klonkt-update` op de server.'));
Note: See TracChangeset for help on using the changeset viewer.