v0.2.0 (11/N): periodic auto-update check
PLAN.md §11 *Auto-update* described "check on launch and once per N hours; offer install on next restart, never auto-restart". v0.1.0 shipped checkForUpdates() and applyUpdate() Q_INVOKABLEs but only manual triggers — no scheduling. This wires the polling. armAutoUpdateOnFirstOnline() runs from setState(Online) in bundled mode: - A QTimer::singleShot fires checkForUpdates() 10 s after the first Online transition (lets cold-boot bandwidth/CPU settle first). - A recurring QTimer fires checkForUpdates() every 6 hours after that. - One-shot guard via m_autoUpdateArmed so reconnect cycles don't re-arm the timers. Dev mode skips entirely (developers don't want their `make dev` workflow polling AppImageUpdate). Env-var knobs: - BRIDGE_AUTO_UPDATE_DISABLE=1 — skip entirely (respect-opt-out baseline; user-facing settings UI can layer on top later). - BRIDGE_AUTO_UPDATE_PERIOD_MIN=<minutes> — override the period (handy for testing or shorter intervals on power-user opt-in). The actual install (apply + restart) stays manual — never auto- restart, per PLAN.md's UX rule. checkForUpdates emits updatesAvailable(); QML decides whether/when to show a banner and call applyUpdate(). Verified locally with QT_LOGGING_RULES=phpqml.bridge.bundled.info=true: "phpqml.bridge.bundled: auto-update armed: launch check in 10000 ms, period 360 min" appears in the host log after the BackendConnection probe sees /healthz=200. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -615,6 +615,45 @@ void BackendConnection::setState(ConnectionState s)
|
||||
if (m_state == s) return;
|
||||
m_state = s;
|
||||
emit connectionStateChanged();
|
||||
if (s == ConnectionState::Online) {
|
||||
armAutoUpdateOnFirstOnline();
|
||||
}
|
||||
}
|
||||
|
||||
void BackendConnection::armAutoUpdateOnFirstOnline()
|
||||
{
|
||||
if (m_autoUpdateArmed) return;
|
||||
if (m_mode != Mode::Bundled) return;
|
||||
if (qEnvironmentVariableIsSet("BRIDGE_AUTO_UPDATE_DISABLE")
|
||||
&& qgetenv("BRIDGE_AUTO_UPDATE_DISABLE") == "1") {
|
||||
qCInfo(lcBundled) << "auto-update disabled via BRIDGE_AUTO_UPDATE_DISABLE";
|
||||
m_autoUpdateArmed = true;
|
||||
return;
|
||||
}
|
||||
m_autoUpdateArmed = true;
|
||||
|
||||
int periodMs = kAutoUpdateDefaultPeriodMs;
|
||||
bool ok = false;
|
||||
const int overrideMin = qgetenv("BRIDGE_AUTO_UPDATE_PERIOD_MIN").toInt(&ok);
|
||||
if (ok && overrideMin > 0) {
|
||||
periodMs = overrideMin * 60 * 1000;
|
||||
}
|
||||
|
||||
// First check: a few seconds after first Online so a fresh launch
|
||||
// doesn't fight for bandwidth/CPU with the cold boot. Subsequent
|
||||
// checks: every periodMs (default 6h).
|
||||
QTimer::singleShot(kAutoUpdateLaunchDelayMs, this, &BackendConnection::checkForUpdates);
|
||||
|
||||
if (!m_autoUpdateTimer) {
|
||||
m_autoUpdateTimer = new QTimer(this);
|
||||
m_autoUpdateTimer->setSingleShot(false);
|
||||
connect(m_autoUpdateTimer, &QTimer::timeout,
|
||||
this, &BackendConnection::checkForUpdates);
|
||||
}
|
||||
m_autoUpdateTimer->start(periodMs);
|
||||
qCInfo(lcBundled) << "auto-update armed: launch check in"
|
||||
<< kAutoUpdateLaunchDelayMs << "ms, period"
|
||||
<< (periodMs / 60000) << "min";
|
||||
}
|
||||
|
||||
void BackendConnection::setError(const QString& msg)
|
||||
|
||||
@@ -175,6 +175,17 @@ private:
|
||||
QProcess* m_updateCheck = nullptr;
|
||||
QProcess* m_updateApply = nullptr;
|
||||
|
||||
/// Periodic AppImageUpdate poll. Armed on first Online transition
|
||||
/// in bundled mode; PLAN.md §11 *Auto-update*. Disabled by env
|
||||
/// `BRIDGE_AUTO_UPDATE_DISABLE=1`; period override via
|
||||
/// `BRIDGE_AUTO_UPDATE_PERIOD_MIN=<minutes>`.
|
||||
QTimer* m_autoUpdateTimer = nullptr;
|
||||
bool m_autoUpdateArmed = false;
|
||||
static constexpr int kAutoUpdateLaunchDelayMs = 10'000; // 10s after first Online
|
||||
static constexpr int kAutoUpdateDefaultPeriodMs = 6 * 60 * 60 * 1000; // 6h
|
||||
|
||||
void armAutoUpdateOnFirstOnline();
|
||||
|
||||
QString resolveSidecarUpdater() const;
|
||||
QString currentAppImagePath() const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user