Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -1,87 +1,185 @@
<?php
declare(strict_types=1);
namespace App\Framework\Filesystem;
use App\Framework\Async\FiberManager;
use App\Framework\Filesystem\Exceptions\DirectoryCreateException;
use App\Framework\Filesystem\Exceptions\DirectoryListException;
use App\Framework\Filesystem\Exceptions\FileCopyException;
use App\Framework\Filesystem\Exceptions\FileDeleteException;
use App\Framework\Filesystem\Exceptions\FileMetadataException;
use App\Framework\Filesystem\Exceptions\FileNotFoundException;
use App\Framework\Filesystem\Exceptions\FilePermissionException;
use App\Framework\Filesystem\Exceptions\FileReadException;
use App\Framework\Filesystem\Exceptions\FileWriteException;
use App\Framework\Filesystem\Traits\AppendableStorageTrait;
use App\Framework\Filesystem\Traits\AtomicStorageTrait;
use App\Framework\Filesystem\Traits\CompressibleStorageTrait;
use App\Framework\Filesystem\Traits\LockableStorageTrait;
use App\Framework\Filesystem\Traits\StreamableStorageTrait;
final readonly class FileStorage implements Storage
final readonly class FileStorage implements Storage, AtomicStorage, AppendableStorage, StreamableStorage, LockableStorage, CompressibleStorage
{
use StorageTrait;
use AtomicStorageTrait;
use AppendableStorageTrait;
use StreamableStorageTrait;
use LockableStorageTrait;
use CompressibleStorageTrait;
public readonly PermissionChecker $permissions;
public readonly FiberManager $fiberManager;
public function __construct(
private string $basePath = '/',
?FiberManager $fiberManager = null
) {
$this->permissions = new PermissionChecker($this);
$this->fiberManager = $fiberManager ?? $this->createDefaultFiberManager();
}
private function createDefaultFiberManager(): FiberManager
{
// Create minimal dependencies for FiberManager
$clock = new \App\Framework\DateTime\SystemClock();
$timer = new \App\Framework\DateTime\SystemTimer($clock);
return new FiberManager($clock, $timer);
}
private function resolvePath(string $path): string
{
// Absolute path bleibt unverändert
if (str_starts_with($path, '/')) {
return $path;
}
// Relative paths werden an basePath gehängt
return rtrim($this->basePath, '/') . '/' . ltrim($path, '/');
}
public function get(string $path): string
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
$content = @file_get_contents($path);
if (! is_readable($resolvedPath)) {
throw FilePermissionException::read($path, 'File is not readable');
}
$content = @file_get_contents($resolvedPath);
if ($content === false) {
$error = error_get_last();
if ($error && str_contains($error['message'], 'Permission denied')) {
throw FilePermissionException::read($path, $error['message']);
}
throw new FileReadException($path);
}
return $content;
}
public function put(string $path, string $content): void
{
$dir = dirname($path);
if (!is_dir($dir)) {
if (!@mkdir($dir, 0777, true) && !is_dir($dir)) {
$resolvedPath = $this->resolvePath($path);
$dir = dirname($resolvedPath);
// Prüfe Directory-Permissions
if (! is_dir($dir)) {
if (! @mkdir($dir, 0777, true) && ! is_dir($dir)) {
$error = error_get_last();
if ($error && str_contains($error['message'], 'Permission denied')) {
throw FilePermissionException::createDirectory($dir, $error['message']);
}
throw new DirectoryCreateException($dir);
}
} elseif (! is_writable($dir)) {
throw FilePermissionException::write($path, 'Directory is not writable: ' . $dir);
}
if (@file_put_contents($path, $content) === false) {
// Prüfe File-Permissions wenn Datei bereits existiert
if (is_file($resolvedPath) && ! is_writable($resolvedPath)) {
throw FilePermissionException::write($path, 'File is not writable');
}
if (@file_put_contents($resolvedPath, $content) === false) {
$error = error_get_last();
if ($error && str_contains($error['message'], 'Permission denied')) {
throw FilePermissionException::write($path, $error['message']);
}
throw new FileWriteException($path);
}
}
public function exists(string $path): bool
{
return is_file($path);
return is_file($this->resolvePath($path));
}
public function delete(string $path): void
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
if (!@unlink($path)) {
// Prüfe Directory-Permissions
$dir = dirname($resolvedPath);
if (! is_writable($dir)) {
throw FilePermissionException::delete($path, 'Directory is not writable: ' . $dir);
}
// Prüfe File-Permissions
if (! is_writable($resolvedPath)) {
throw FilePermissionException::delete($path, 'File is not writable');
}
if (! @unlink($resolvedPath)) {
$error = error_get_last();
if ($error && str_contains($error['message'], 'Permission denied')) {
throw FilePermissionException::delete($path, $error['message']);
}
throw new FileDeleteException($path);
}
}
public function copy(string $source, string $destination): void
{
if (!is_file($source)) {
$resolvedSource = $this->resolvePath($source);
$resolvedDestination = $this->resolvePath($destination);
if (! is_file($resolvedSource)) {
throw new FileNotFoundException($source);
}
// Stelle sicher, dass das Zielverzeichnis existiert
$dir = dirname($destination);
if (!is_dir($dir)) {
$this->createDirectory($dir);
$dir = dirname($resolvedDestination);
if (! is_dir($dir)) {
$this->createDirectory($destination);
}
if (!@copy($source, $destination)) {
if (! @copy($resolvedSource, $resolvedDestination)) {
throw new FileCopyException($source, $destination);
}
}
public function size(string $path): int
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
$size = @filesize($path);
$size = @filesize($resolvedPath);
if ($size === false) {
throw new FileReadException($path);
}
@@ -91,11 +189,12 @@ final readonly class FileStorage implements Storage
public function lastModified(string $path): int
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
$time = @filemtime($path);
$time = @filemtime($resolvedPath);
if ($time === false) {
throw new FileReadException($path);
}
@@ -105,11 +204,12 @@ final readonly class FileStorage implements Storage
public function getMimeType(string $path): string
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
$mimeType = @mime_content_type($path);
$mimeType = @mime_content_type($resolvedPath);
if ($mimeType === false) {
throw new FileMetadataException($path);
}
@@ -119,29 +219,32 @@ final readonly class FileStorage implements Storage
public function isReadable(string $path): bool
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
return is_readable($path);
return is_readable($resolvedPath);
}
public function isWritable(string $path): bool
{
if (!is_file($path)) {
$resolvedPath = $this->resolvePath($path);
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
return is_writable($path);
return is_writable($resolvedPath);
}
public function listDirectory(string $directory): array
{
if (!is_dir($directory)) {
$resolvedDirectory = $this->resolvePath($directory);
if (! is_dir($resolvedDirectory)) {
throw new DirectoryCreateException($directory);
}
$files = @scandir($directory);
$files = @scandir($resolvedDirectory);
if ($files === false) {
throw new DirectoryListException($directory);
}
@@ -151,10 +254,15 @@ final readonly class FileStorage implements Storage
return $file !== '.' && $file !== '..';
});
// Vollständige Pfade erstellen
// Relative Pfade zurückgeben (ohne basePath)
$result = [];
foreach ($files as $file) {
$result[] = $directory . DIRECTORY_SEPARATOR . $file;
$fullPath = $resolvedDirectory . DIRECTORY_SEPARATOR . $file;
// Entferne basePath für relativen Pfad
$relativePath = str_starts_with($fullPath, $this->basePath)
? substr($fullPath, strlen(rtrim($this->basePath, '/')) + 1)
: $fullPath;
$result[] = $relativePath;
}
return array_values($result);
@@ -162,12 +270,67 @@ final readonly class FileStorage implements Storage
public function createDirectory(string $path, int $permissions = 0755, bool $recursive = true): void
{
if (is_dir($path)) {
$resolvedPath = $this->resolvePath($path);
if (is_dir($resolvedPath)) {
return; // Verzeichnis existiert bereits
}
if (!@mkdir($path, $permissions, $recursive) && !is_dir($path)) {
// Prüfe Parent-Directory Permissions
$parentDir = dirname($resolvedPath);
if (is_dir($parentDir) && ! is_writable($parentDir)) {
throw FilePermissionException::createDirectory($path, 'Parent directory is not writable: ' . $parentDir);
}
if (! @mkdir($resolvedPath, $permissions, $recursive) && ! is_dir($resolvedPath)) {
$error = error_get_last();
if ($error && str_contains($error['message'], 'Permission denied')) {
throw FilePermissionException::createDirectory($path, $error['message']);
}
throw new DirectoryCreateException($path);
}
}
// Batch-Operationen für explizite Parallelverarbeitung
public function batch(array $operations): array
{
return $this->fiberManager->batch($operations);
}
public function getMultiple(array $paths): array
{
$operations = [];
foreach ($paths as $path) {
$operations[$path] = fn () => $this->get($path);
}
return $this->batch($operations);
}
public function putMultiple(array $files): void
{
$operations = [];
foreach ($files as $path => $content) {
$operations[$path] = fn () => $this->put($path, $content);
}
$this->batch($operations);
}
public function getMetadataMultiple(array $paths): array
{
$operations = [];
foreach ($paths as $path) {
$operations[$path] = fn () => new FileMetadata(
size: $this->size($path),
lastModified: $this->lastModified($path),
mimeType: $this->getMimeType($path),
isReadable: $this->isReadable($path),
isWritable: $this->isWritable($path)
);
}
return $this->batch($operations);
}
}