diff --git a/README.md b/README.md index 6d2dfb0..9593b5e 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,40 @@ server actions or send browser push notifications after the app closes. Plugins support named release versions, GitHub DLL imports and update discovery. See [Plugin releases](docs/plugin-releases.md) for the import and beta workflow. +## Plutonium updates and scheduled restarts + +Open **Settings → Plutonium updates & restarts** to check the latest published +revision, inspect each server's running revision, and queue a server or fleet +restart. Release and running-version checks also run hourly. The published +revision comes from the [official changelog](https://plutonium.pw/docs/changelog/); +running revisions come from RCON `version`. Unsupported replies and failed +queries appear as unknown rather than being treated as up to date. A failed +changelog request retains the last release with a visible error. + +Daily fleet restarts are optional and disabled by default. Choose a **UTC** queue +time and save the schedule; the next run is also shown in your display timezone. +Every due run queues the current fleet, regardless of whether an update exists. +The schedule and jobs survive app restarts. Missed days become one run, and a +server can have only one pending maintenance restart. Disabling the schedule +does not cancel work already queued; use **Cancel** for those jobs. + +Maintenance waits for a fresh zero-player RCON response and for existing +deployment/beta work, then uses the shared rolling restart limit. Unreachable or +occupied servers remain queued. After container and RCON recovery, Electric +Cherry queries the running revision again. If a fresh published revision was +known when queued, recovery on an older or unknown revision is reported as a +failed verification, without an automatic restart loop. Ambiguous restart +failures likewise require inspection before a new request. Activity is retained +for 30 days, with pending jobs and the latest 100 records shown in Settings. + +Updates rely on Plutainer's startup updater (`PLUTAINER_AUTO_UPDATE` must be +enabled); Electric Cherry does not download binaries or pull a container image. +See [Plutainer's startup flow](https://github.com/Ayymoss/Plutainer/blob/main/CLAUDE.md) +and [environment migration reference](https://github.com/Ayymoss/Plutainer/blob/main/MIGRATION.md). +The worker starts on the first application request, so keep the app running and +reachable for scheduled maintenance. Validate RCON revision replies and updater +behavior on your live T5/T6 servers before relying on unattended maintenance. + ## How restarts stay safe Betas support configurable gameplay, participation, stability and manual-review diff --git a/src/lib/plutonium.ts b/src/lib/plutonium.ts new file mode 100644 index 0000000..f90efde --- /dev/null +++ b/src/lib/plutonium.ts @@ -0,0 +1,55 @@ +export interface MaintenanceSchedule { + enabled: boolean; + time: string; + nextAt: string | null; +} +export interface PlutoniumRelease { + revision: number | null; + checkedAt: string | null; + error: string | null; +} +export interface PlutoniumVersion { + server: string; + revision: number | null; + checked_at: string | null; + error: string | null; +} +export interface MaintenanceJob { + id: number; + server: string; + state: 'queued' | 'restarting' | 'done' | 'failed' | 'cancelled'; + target_revision: number | null; + requested_at: string; + restarted_at: string | null; + finished_at: string | null; + detail: string | null; +} +export interface PlutoniumStatus { + release: PlutoniumRelease; + schedule: MaintenanceSchedule; + servers: PlutoniumVersion[]; + jobs: MaintenanceJob[]; +} + +/** Accept explicit revision tokens only, never engine versions or build dates. */ +export function parsePlutoniumRevision(text: string): number | null { + const match = text.replace(/\^[0-9]/g, '').match(/\br([1-9]\d{2,8})\b/i); + return match ? Number(match[1]) : null; +} + +export function parseChangelogRevision(html: string): number { + const headings = [...html.matchAll(/
Plutainer applies updates on startup when auto-update is enabled. Restarts wait for a fresh player count of zero and share the fleet’s rolling restart limit.
+ {#if error}{error}
{/if} + {#if notice}{notice}
{/if} + {#if data} +Latest published revision: {data.release.revision ? `r${data.release.revision}` : 'Unknown'} + · Changelog + {#if data.release.checkedAt} · Checked {$timeFormat.dateTime(data.release.checkedAt)}{/if} +
+ {#if data.release.error}Update check failed: {data.release.error} Any displayed release is cached.
{/if} + +This restarts all fleet servers daily, even without a new release. Busy servers may restart later. Disabling the schedule stops future runs; cancel existing queued restarts below.
+ {#if data.schedule.nextAt}Next run: {$timeFormat.dateTime(data.schedule.nextAt)}
{/if} +| Server | Running revision | Update status | Action |
|---|---|---|---|
| {server.server} | +{server.revision ? `r${server.revision}` : 'Unknown'} + {#if server.checked_at}Checked {$timeFormat.dateTime(server.checked_at)}{/if} + {#if server.error}{server.error}{/if} + | +{server.revision === null || data.release.revision === null || data.release.error ? 'Unverified' + : server.revision < data.release.revision ? 'Update available' : server.revision > data.release.revision ? 'Ahead of changelog' : 'Up to date'} | +|
| No fleet servers yet. | |||
{busy ? 'Loading maintenance status…' : 'Maintenance status unavailable.'}
{/if} +Example: {$timeFormat.dateTime(data.checkedAt)}
{/if} {#if $timeZonePersistenceError}Browser storage is unavailable. Your timezone applies for this visit but cannot be saved.
{/if} +Check your connections and the prerequisites for a playable server.