feat(maintenance): per-message choke to freeze non-admins during platform maintenance

Read the shared platform:maintenance DB-cache flag at controll_message (after
auth resolves) and refuse every controller event for non-admins with
{message, maintenance:true}, so a host app can run a deploy / write-locking
migration without clients mutating state. Admins bypass to smoke-test. The key
is hardcoded to match App\Support\Maintenance::CACHE_KEY and dodge the
fork-child package-config-merge gap; cache reads are guarded so a hiccup can
never wedge the socket.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Fabian @ Blax Software 2026-08-06 10:42:34 +02:00
parent ed15ef8c23
commit b678a25a3c
1 changed files with 43 additions and 0 deletions

View File

@ -51,6 +51,34 @@ class Controller
*/ */
public function unboot(): void {} public function unboot(): void {}
/**
* Shared platform-maintenance flag, read from the same DB-cache key the host
* app writes via App\Support\Maintenance::CACHE_KEY. Hardcoded (not config)
* to dodge the fork-child package-config-merge gap, and wrapped so a cache
* hiccup can never wedge the socket. Keep the key string in sync with the app.
*/
protected static function maintenanceActive(): bool
{
try {
return (bool) cache()->get('platform:maintenance', false);
} catch (\Throwable) {
return false;
}
}
protected static function maintenanceMessage(): string
{
try {
$message = cache()->get('platform:maintenance:message');
} catch (\Throwable) {
$message = null;
}
return is_string($message) && $message !== ''
? $message
: 'We are performing scheduled maintenance and will be back shortly.';
}
public static function controll_message( public static function controll_message(
ConnectionInterface $connection, ConnectionInterface $connection,
PrivateChannel|Channel|PresenceChannel $channel, PrivateChannel|Channel|PresenceChannel $channel,
@ -133,6 +161,21 @@ class Controller
} }
} }
// Platform maintenance freeze. Once auth (incl. the self-heal above)
// has resolved the user, refuse every controller event for non-admins
// so a deploy/migration can run without clients mutating state. Admins
// bypass to smoke-test. The `auth` handshake + channel introspection
// are single-part events handled earlier, so a maintainer can still
// authenticate to obtain the bypass.
if (self::maintenanceActive() && ! ($connection->user?->is_admin ?? false)) {
$controller->error([
'message' => self::maintenanceMessage(),
'maintenance' => true,
]);
$controller->unboot();
return;
}
if (! method_exists($controllerClass, $method)) { if (! method_exists($controllerClass, $method)) {
$controller->error('Event could not be handled'); $controller->error('Event could not be handled');
$controller->unboot(); $controller->unboot();