|
|
@@ -0,0 +1,81 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+declare(strict_types=1);
|
|
|
+
|
|
|
+namespace App\Services;
|
|
|
+
|
|
|
+use Illuminate\Support\Facades\Cache;
|
|
|
+use Throwable;
|
|
|
+
|
|
|
+class DiskSpaceMonitor
|
|
|
+{
|
|
|
+ private const CACHE_KEY = 'disk_space_monitor.status';
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return array{warning: bool, free_bytes: int|null, threshold_bytes: int, path: string, checked_at: string|null}
|
|
|
+ */
|
|
|
+ public function status(): array
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ return Cache::remember(
|
|
|
+ self::CACHE_KEY,
|
|
|
+ now()->addSeconds($this->cacheSeconds()),
|
|
|
+ fn (): array => $this->freshStatus()
|
|
|
+ );
|
|
|
+ } catch (Throwable) {
|
|
|
+ return $this->freshStatus();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function formatBytes(?int $bytes): string
|
|
|
+ {
|
|
|
+ if ($bytes === null) {
|
|
|
+ return 'неизвестно';
|
|
|
+ }
|
|
|
+
|
|
|
+ $units = ['Б', 'КБ', 'МБ', 'ГБ', 'ТБ'];
|
|
|
+ $value = (float) $bytes;
|
|
|
+ $unitIndex = 0;
|
|
|
+
|
|
|
+ while ($value >= 1024 && $unitIndex < count($units) - 1) {
|
|
|
+ $value /= 1024;
|
|
|
+ $unitIndex++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return sprintf('%s %s', round($value, $unitIndex === 0 ? 0 : 2), $units[$unitIndex]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return array{warning: bool, free_bytes: int|null, threshold_bytes: int, path: string, checked_at: string|null}
|
|
|
+ */
|
|
|
+ private function freshStatus(): array
|
|
|
+ {
|
|
|
+ $path = $this->path();
|
|
|
+ $thresholdBytes = $this->thresholdBytes();
|
|
|
+ $freeBytes = @disk_free_space($path);
|
|
|
+ $freeBytes = $freeBytes === false ? null : (int) $freeBytes;
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'warning' => $freeBytes !== null && $freeBytes < $thresholdBytes,
|
|
|
+ 'free_bytes' => $freeBytes,
|
|
|
+ 'threshold_bytes' => $thresholdBytes,
|
|
|
+ 'path' => $path,
|
|
|
+ 'checked_at' => now()->toDateTimeString(),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ private function path(): string
|
|
|
+ {
|
|
|
+ return (string) config('app.disk_space_warning.path', storage_path());
|
|
|
+ }
|
|
|
+
|
|
|
+ private function thresholdBytes(): int
|
|
|
+ {
|
|
|
+ return max(0, (int) config('app.disk_space_warning.threshold_bytes', 1024 * 1024 * 1024));
|
|
|
+ }
|
|
|
+
|
|
|
+ private function cacheSeconds(): int
|
|
|
+ {
|
|
|
+ return max(1, (int) config('app.disk_space_warning.cache_seconds', 300));
|
|
|
+ }
|
|
|
+}
|