Files
biiproject-kit-v1/app/Services/System/MaintenanceManagementService.php

204 lines
6.3 KiB
PHP

<?php
/**
* ============================================================
*
* @project biiproject
*
* @author Andika Debi Putra
*
* @email andikadebiputra@gmail.com
*
* @website https://biiproject.com
*
* @copyright Copyright (c) 2026 Andika Debi Putra
* @license Proprietary - All Rights Reserved
*
* @version 1.0.0
*
* @created 2026-05-01
* ============================================================
*
* Unauthorized copying, modification, distribution, or use
* of this file is strictly prohibited without prior written
* permission from the author.
* ============================================================
*/
namespace App\Services\System;
use App\Events\SystemNotification;
use App\Models\User;
use App\Notifications\SystemManagementNotification;
use App\Services\SystemConfig\SystemConfigService;
use Exception;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
class MaintenanceManagementService
{
public function __construct(
protected SystemConfigService $configService
) {}
/**
* Sync the physical maintenance state with the database configuration.
*/
public function syncState()
{
try {
$settings = $this->configService->all();
$enabled = filter_var($settings['maintenance_mode_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN);
$isCurrentlyDown = $this->isDown();
if ($enabled) {
$this->activateMaintenance($settings);
// Only notify if it was NOT already down
if (! $isCurrentlyDown) {
Notification::send(
User::permission('view notification center')->get(),
new SystemManagementNotification('Maintenance Active', 'System is entering Maintenance Mode.', 'warning')
);
}
} else {
$this->deactivateMaintenance();
// Only notify if it WAS previously down
if ($isCurrentlyDown) {
Notification::send(
User::permission('view notification center')->get(),
new SystemManagementNotification('System Online', 'System is now LIVE and online.', 'success')
);
}
}
return true;
} catch (Exception $e) {
Log::error('Maintenance Mode Sync Error: '.$e->getMessage());
return false;
}
}
/**
* Activate Laravel's native maintenance mode with dynamic parameters.
*/
protected function activateMaintenance(array $settings)
{
$options = [];
// 1. Secret Bypass URL
if (! empty($settings['maintenance_mode_secret'])) {
$options['--secret'] = $settings['maintenance_mode_secret'];
}
// 2. Refresh (Browser refresh interval)
$options['--refresh'] = 60; // Default 60 seconds
// 3. Retry After Header
if (! empty($settings['maintenance_mode_retry'])) {
$options['--retry'] = (int) $settings['maintenance_mode_retry'];
}
// 4. Allowed IPs
if (! empty($settings['maintenance_mode_allowed_ips'])) {
// Convert textarea lines/commas to array
$ips = preg_split('/[\s,]+/', $settings['maintenance_mode_allowed_ips'], -1, PREG_SPLIT_NO_EMPTY);
if (! empty($ips)) {
$options['--allow'] = $ips;
}
}
// 5. Status Code (Always 503 for maintenance)
$options['--status'] = 503;
Log::info('System: Activating Maintenance Mode', $options);
// Note: Laravel 11+ down command handles these options
Artisan::call('down', $options);
}
/**
* Deactivate maintenance mode.
*/
protected function deactivateMaintenance()
{
if (app()->isDownForMaintenance()) {
Log::info('System: Deactivating Maintenance Mode');
Artisan::call('up');
}
}
/**
* Check if the system is currently in maintenance mode.
*/
public function isDown(): bool
{
return app()->isDownForMaintenance();
}
/**
* Automatically release maintenance mode if the end time has passed.
*/
public function autoCheckAndRelease(): void
{
$settings = $this->configService->all();
$enabled = filter_var($settings['maintenance_mode_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN);
$endAt = $settings['maintenance_mode_end_at'] ?? null;
if (! $enabled || empty($endAt)) {
return;
}
try {
$endTime = new \DateTime($endAt);
$now = new \DateTime;
if ($now >= $endTime) {
Log::info('System: Maintenance window expired. Automatically deactivating maintenance mode.', [
'expired_at' => $endAt,
'current_time' => $now->format('Y-m-d H:i:s'),
]);
// Update configuration in DB
$this->configService->update([
'maintenance_mode_enabled' => false,
'maintenance_mode_end_at' => null, // Optional: Clear the end time
]);
// Physical release (artisan up)
$this->syncState();
}
} catch (Exception $e) {
Log::error('System: Automatic Maintenance Release failed: '.$e->getMessage());
}
}
/**
* Broadcast a real-time warning to all active users via WebSockets.
*/
public function broadcastWarning(int $minutes)
{
$message = __('SYSTEM ALERT: The system will enter maintenance mode in :min minutes. Please save your work immediately.', ['min' => $minutes]);
// 1. Broadcast event for real-time UI notification (WebSockets)
event(new SystemNotification(
message: $message,
type: 'warning',
title: __('Maintenance Warning')
));
// 2. Persistent notification in the database
Notification::send(
User::all(), // Notify everyone
new SystemManagementNotification('Scheduled Maintenance', $message, 'warning', 'Developer')
);
Log::info("System: Broadcasted maintenance warning (Starting in {$minutes}m).");
return true;
}
}