205 lines
6.4 KiB
Plaintext
205 lines
6.4 KiB
Plaintext
<?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(
|
|
title: __('Maintenance Warning'),
|
|
message: $message,
|
|
type: 'warning',
|
|
user_id: null // Broadcast to all
|
|
));
|
|
|
|
// 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;
|
|
}
|
|
}
|