Ship FrankenPHP Compose services with Reverb WebSockets for real-time transcription status, skip re-uploading identical audio via content hash, and format disk usage without requiring intl.
98 lines
2.7 KiB
PHP
98 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class DiskSpaceService
|
|
{
|
|
/**
|
|
* Snapshot of free/used space for the recordings storage volume.
|
|
*
|
|
* @return array{
|
|
* total_bytes: int,
|
|
* free_bytes: int,
|
|
* used_bytes: int,
|
|
* used_percent: float,
|
|
* free_percent: float,
|
|
* total_human: string,
|
|
* free_human: string,
|
|
* used_human: string
|
|
* }|null
|
|
*/
|
|
public function snapshot(?string $path = null): ?array
|
|
{
|
|
$path ??= Storage::disk('local')->path('');
|
|
|
|
if (! is_dir($path)) {
|
|
@mkdir($path, 0755, true);
|
|
}
|
|
|
|
/** @var array{total_bytes: int, free_bytes: int, used_bytes: int, used_percent: float, free_percent: float, total_human: string, free_human: string, used_human: string}|null */
|
|
return Cache::remember(
|
|
'disk-space:'.md5($path),
|
|
now()->addSeconds(30),
|
|
fn () => $this->measure($path),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return array{
|
|
* total_bytes: int,
|
|
* free_bytes: int,
|
|
* used_bytes: int,
|
|
* used_percent: float,
|
|
* free_percent: float,
|
|
* total_human: string,
|
|
* free_human: string,
|
|
* used_human: string
|
|
* }|null
|
|
*/
|
|
private function measure(string $path): ?array
|
|
{
|
|
$total = @disk_total_space($path);
|
|
$free = @disk_free_space($path);
|
|
|
|
if ($total === false || $free === false || $total <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$totalBytes = (int) $total;
|
|
$freeBytes = (int) max(0, $free);
|
|
$usedBytes = (int) max(0, $totalBytes - $freeBytes);
|
|
$usedPercent = round(($usedBytes / $totalBytes) * 100, 1);
|
|
$freePercent = round(($freeBytes / $totalBytes) * 100, 1);
|
|
|
|
return [
|
|
'total_bytes' => $totalBytes,
|
|
'free_bytes' => $freeBytes,
|
|
'used_bytes' => $usedBytes,
|
|
'used_percent' => $usedPercent,
|
|
'free_percent' => $freePercent,
|
|
'total_human' => $this->formatBytes($totalBytes),
|
|
'free_human' => $this->formatBytes($freeBytes),
|
|
'used_human' => $this->formatBytes($usedBytes),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Human-readable byte size without requiring the intl extension.
|
|
*/
|
|
private function formatBytes(int $bytes): string
|
|
{
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
$value = (float) max(0, $bytes);
|
|
$unit = 0;
|
|
|
|
while ($value >= 1024 && $unit < count($units) - 1) {
|
|
$value /= 1024;
|
|
$unit++;
|
|
}
|
|
|
|
$precision = $unit === 0 ? 0 : 1;
|
|
|
|
return number_format($value, $precision).' '.$units[$unit];
|
|
}
|
|
}
|