diff --git a/src/vector/platform/WebPlatform.ts b/src/vector/platform/WebPlatform.ts index fab4bfa9d9..52401b5a55 100644 --- a/src/vector/platform/WebPlatform.ts +++ b/src/vector/platform/WebPlatform.ts @@ -27,6 +27,7 @@ import UAParser from 'ua-parser-js'; import { logger } from "matrix-js-sdk/src/logger"; import VectorBasePlatform from './VectorBasePlatform'; +import { parseQs } from "../url_utils"; const POKE_RATE_MS = 10 * 60 * 1000; // 10 min @@ -119,25 +120,56 @@ export default class WebPlatform extends VectorBasePlatform { } startUpdater() { - this.pollForUpdate(); - setInterval(this.pollForUpdate, POKE_RATE_MS); + // Poll for an update immediately, and reload the page now if we're out of date + // already as we've just initialised an old version of the app somehow. + // + // Forcibly reloading the page aims to avoid users interacting at all with the old + // and potentially broken version of the app. + // + // Ideally, loading an old copy would be impossible with the + // cache-control: nocache HTTP header set, but Firefox doesn't always obey it :/ + this.pollForUpdate((version: string, newVersion: string) => { + const query = parseQs(location); + if (query.updated === "1") { + // We just reloaded already and are still on the old version! + // Show the toast rather than reload in a loop. + showUpdateToast(version, newVersion); + return; + } + + // Set updated=1 as a query param so we can detect that we've already done this once + // and reload the page. + let suffix = "updated=1"; + if (window.location.search.length === 0) { + suffix = "?" + suffix; + } else { + suffix = "&" + suffix; + } + + // This line has the effect of loading the page at the new location + window.location.href = window.location.href + suffix; + }); + setInterval(() => this.pollForUpdate(showUpdateToast, hideUpdateToast), POKE_RATE_MS); } async canSelfUpdate(): Promise<boolean> { return true; } - pollForUpdate = () => { + pollForUpdate = ( + showUpdate: (currentVersion: string, mostRecentVersion: string) => void, + showNoUpdate?: () => void, + ) => { return this.getMostRecentVersion().then((mostRecentVersion) => { const currentVersion = this.getNormalizedAppVersion(process.env.VERSION); if (currentVersion !== mostRecentVersion) { if (this.shouldShowUpdate(mostRecentVersion)) { - showUpdateToast(currentVersion, mostRecentVersion); + showUpdate(currentVersion, mostRecentVersion); } return { status: UpdateCheckStatus.Ready }; } else { - hideUpdateToast(); + showNoUpdate?.(); } return { status: UpdateCheckStatus.NotAvailable }; @@ -152,7 +184,7 @@ export default class WebPlatform extends VectorBasePlatform { startUpdateCheck() { super.startUpdateCheck(); - this.pollForUpdate().then((updateState) => { + this.pollForUpdate(showUpdateToast, hideUpdateToast).then((updateState) => { dis.dispatch<CheckUpdatesPayload>({ action: Action.CheckUpdates, ...updateState,