From e2b07b90dfda88528375309262970df47000f7c9 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 16:33:41 -0500 Subject: [PATCH 1/6] feat: enhance server process management with error handling and health checks --- server | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 169 insertions(+), 24 deletions(-) diff --git a/server b/server index dbd009e..0b83140 100644 --- a/server +++ b/server @@ -18,10 +18,18 @@ $config = Dotenv::createArrayBacked(__DIR__, '.env')->load(); class Watcher extends Watch { protected string $host; + protected int $port; + protected int|null $pid; + protected Process $serverProcess; + protected int $consecutiveErrors = 0; + + protected int $maxConsecutiveErrors = 5; + + public function __construct( array $paths, array $config = [] @@ -38,20 +46,13 @@ class Watcher extends Watch $watcher = $this->getWatchProcess(); while (true) { - if (! $watcher->isRunning()) { - throw CouldNotStartWatcher::make($watcher); - } + $this->ensureWatcherIsRunning($watcher); - if ($output = $watcher->getIncrementalOutput()) { - $this->actOnOutput($output); - } + $this->handleWatcherOutput($watcher); - if ($this->serverProcess->isRunning()) { - echo $this->serverProcess->getIncrementalOutput(); - echo $this->serverProcess->getIncrementalErrorOutput(); - } + $this->handleServerProcess(); - if (! ($this->shouldContinue)()) { + if (!($this->shouldContinue)()) { break; } @@ -59,15 +60,15 @@ class Watcher extends Watch } } - public function watch(): void { + public function watch(): void + { echo "Watching for changes..." . PHP_EOL . PHP_EOL; $this->onAnyChange(function (): void { $this->killExistingProcess(); $this->runServer(); - }) - ->start(); + })->start(); } public function systemIsReady(): bool @@ -100,27 +101,171 @@ class Watcher extends Watch } } - public function runServer(): void { - $this->serverProcess = Process::fromShellCommandline("php public/index.php"); + public function runServer(): void + { + if ($this->consecutiveErrors >= $this->maxConsecutiveErrors) { + echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + + return; + } + + $command = "XDEBUG_MODE=off php public/index.php"; + $this->serverProcess = Process::fromShellCommandline($command); $this->serverProcess->setTimeout(null); - $this->serverProcess->start(); - $this->pid = $this->serverProcess->getPid(); + try { + $this->serverProcess->start(); + + usleep(100000); // 100ms + + if (!$this->serverProcess->isRunning()) { + $exitCode = $this->serverProcess->getExitCode(); + $this->consecutiveErrors++; + + echo "Server failed to start. Exit code: {$exitCode}" . PHP_EOL; + echo "Error: " . $this->serverProcess->getErrorOutput() . PHP_EOL; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer(); + } - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; - echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; + return; + } + + $this->consecutiveErrors = 0; + $this->pid = $this->serverProcess->getPid(); + + echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; + echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; + + } catch (Exception $e) { + $this->consecutiveErrors++; + + echo "Failed to start server: " . $e->getMessage() . PHP_EOL; + echo "Command: {$command}" . PHP_EOL; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer(); + } + } } - protected function killExistingProcess() + private function ensureWatcherIsRunning(Process $watcher): void { - if ($this->pid) { + if (!$watcher->isRunning()) { + throw CouldNotStartWatcher::make($watcher); + } + } + + private function handleWatcherOutput(Process $watcher): void + { + if ($output = $watcher->getIncrementalOutput()) { + $this->actOnOutput($output); + } + } + + private function handleServerProcess(): void + { + if (!isset($this->serverProcess)) { + return; + } + + if ($this->serverProcess->isRunning()) { + $this->outputServerProcess(); + + $this->periodicHealthCheck(); + } else { + $this->handleServerExit(); + } + } + + private function outputServerProcess(): void + { + echo $this->serverProcess->getIncrementalOutput(); + echo $this->serverProcess->getIncrementalErrorOutput(); + } + + private function periodicHealthCheck(): void + { + static $lastHealthCheck = 0; + if (time() - $lastHealthCheck > 10) { + if (!$this->isServerHealthy()) { + echo "Server health check failed. Restarting..." . PHP_EOL; + $this->killExistingProcess(); + $this->runServer(); + } + $lastHealthCheck = time(); + } + } + + private function handleServerExit(): void + { + $exitCode = $this->serverProcess->getExitCode(); + + if ($exitCode !== null && $exitCode !== 0) { + echo "Server process exited with error code: {$exitCode}" . PHP_EOL; + echo "Error output: " . $this->serverProcess->getErrorOutput() . PHP_EOL; echo "Restarting server..." . PHP_EOL . PHP_EOL; - $killProcess = Process::fromShellCommandline('kill ' . escapeshellarg($this->pid)); - $killProcess->run(); + $this->runServer(); + } + } + + private function killExistingProcess(): void + { + if (!isset($this->serverProcess) || !$this->pid) { + return; + } + + echo "Restarting server..." . PHP_EOL . PHP_EOL; + + try { + // First try graceful termination + $this->serverProcess->stop(3); // 3 second timeout + + // If still running, force kill + if ($this->serverProcess->isRunning()) { + $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); + $killProcess->run(); + } echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; + + } catch (\Exception $e) { + echo "Error stopping server: " . $e->getMessage() . PHP_EOL; + + // Force kill as last resort + $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); + $killProcess->run(); } + + $this->pid = null; + } + + private function isServerHealthy(): bool + { + if (!isset($this->serverProcess) || !$this->serverProcess->isRunning()) { + return false; + } + + // Check if server is responding by making a simple HTTP request + $context = stream_context_create([ + 'http' => [ + 'timeout' => 1, + 'ignore_errors' => true + ] + ]); + + $url = str_replace(['http://', 'https://'], '', $this->host) . ':' . $this->port; + $result = @file_get_contents("http://{$url}", false, $context); + + return $result !== false; } } From da0b468fe71ea5296dcdace7f43f0a832d87b111 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 16:35:35 -0500 Subject: [PATCH 2/6] feat: implement periodic health check for server process management --- server | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server b/server index 0b83140..ecaa258 100644 --- a/server +++ b/server @@ -29,6 +29,8 @@ class Watcher extends Watch protected int $maxConsecutiveErrors = 5; + protected int $lastHealthCheck = 0; + public function __construct( array $paths, @@ -193,14 +195,15 @@ class Watcher extends Watch private function periodicHealthCheck(): void { - static $lastHealthCheck = 0; - if (time() - $lastHealthCheck > 10) { + if (time() - $this->lastHealthCheck > 10) { if (!$this->isServerHealthy()) { echo "Server health check failed. Restarting..." . PHP_EOL; + $this->killExistingProcess(); $this->runServer(); } - $lastHealthCheck = time(); + + $this->lastHealthCheck = time(); } } From 3d0b6d45c8f3395d9ee34bad44ac6f9a0730cb51 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 16:39:00 -0500 Subject: [PATCH 3/6] fix: improve server termination process and error handling --- server | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/server b/server index ecaa258..80e21f9 100644 --- a/server +++ b/server @@ -229,10 +229,8 @@ class Watcher extends Watch echo "Restarting server..." . PHP_EOL . PHP_EOL; try { - // First try graceful termination $this->serverProcess->stop(3); // 3 second timeout - // If still running, force kill if ($this->serverProcess->isRunning()) { $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); @@ -240,10 +238,9 @@ class Watcher extends Watch echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; - } catch (\Exception $e) { + } catch (Exception $e) { echo "Error stopping server: " . $e->getMessage() . PHP_EOL; - // Force kill as last resort $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); } @@ -257,7 +254,6 @@ class Watcher extends Watch return false; } - // Check if server is responding by making a simple HTTP request $context = stream_context_create([ 'http' => [ 'timeout' => 1, From aa45281f13dc4585f1c61f6dc89377d4008fbd9b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 17:01:19 -0500 Subject: [PATCH 4/6] feat: enhance server error handling with stop attempts and health check logic --- server | 67 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/server b/server index 80e21f9..6b5e189 100644 --- a/server +++ b/server @@ -31,6 +31,8 @@ class Watcher extends Watch protected int $lastHealthCheck = 0; + protected bool $stopAttempts = false; + public function __construct( array $paths, @@ -103,10 +105,14 @@ class Watcher extends Watch } } - public function runServer(): void + public function runServer(bool $incrementErrorCounter = true): void { - if ($this->consecutiveErrors >= $this->maxConsecutiveErrors) { - echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + if ($this->consecutiveErrors >= $this->maxConsecutiveErrors || $this->stopAttempts) { + if (!$this->stopAttempts) { + echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + + $this->stopAttempts = true; + } return; } @@ -122,7 +128,10 @@ class Watcher extends Watch if (!$this->serverProcess->isRunning()) { $exitCode = $this->serverProcess->getExitCode(); - $this->consecutiveErrors++; + + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } echo "Server failed to start. Exit code: {$exitCode}" . PHP_EOL; echo "Error: " . $this->serverProcess->getErrorOutput() . PHP_EOL; @@ -131,20 +140,24 @@ class Watcher extends Watch if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); - $this->runServer(); + $this->runServer($incrementErrorCounter); } return; } - $this->consecutiveErrors = 0; + if ($incrementErrorCounter) { + $this->consecutiveErrors = 0; + } $this->pid = $this->serverProcess->getPid(); echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; } catch (Exception $e) { - $this->consecutiveErrors++; + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } echo "Failed to start server: " . $e->getMessage() . PHP_EOL; echo "Command: {$command}" . PHP_EOL; @@ -153,7 +166,7 @@ class Watcher extends Watch if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); - $this->runServer(); + $this->runServer($incrementErrorCounter); } } } @@ -195,12 +208,33 @@ class Watcher extends Watch private function periodicHealthCheck(): void { + if ($this->stopAttempts) { + return; + } + if (time() - $this->lastHealthCheck > 10) { if (!$this->isServerHealthy()) { echo "Server health check failed. Restarting..." . PHP_EOL; + $this->consecutiveErrors++; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + $this->killExistingProcess(); - $this->runServer(); + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + $this->runServer(false); + } else { + echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + + $this->stopAttempts = true; + } + } else { + if ($this->consecutiveErrors > 0) { + echo "Server health check passed. Resetting error counter." . PHP_EOL; + + $this->consecutiveErrors = 0; + $this->stopAttempts = false; // Allow attempts again + } } $this->lastHealthCheck = time(); @@ -209,6 +243,10 @@ class Watcher extends Watch private function handleServerExit(): void { + if ($this->stopAttempts) { + return; + } + $exitCode = $this->serverProcess->getExitCode(); if ($exitCode !== null && $exitCode !== 0) { @@ -216,7 +254,16 @@ class Watcher extends Watch echo "Error output: " . $this->serverProcess->getErrorOutput() . PHP_EOL; echo "Restarting server..." . PHP_EOL . PHP_EOL; - $this->runServer(); + $this->consecutiveErrors++; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + $this->runServer(false); + } else { + echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + + $this->stopAttempts = true; + } } } From 96bd1aa53f8ec1b2d69c0c4bac187b3ca0e84734 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 17:39:49 -0500 Subject: [PATCH 5/6] feat: enhance output formatting with colorized messages for server status and errors --- server | 157 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 28 deletions(-) diff --git a/server b/server index 6b5e189..4cee512 100644 --- a/server +++ b/server @@ -13,6 +13,57 @@ if (php_sapi_name() !== 'cli') { exit; } +class Output +{ + public const RESET = "\033[0m"; + public const BOLD = "\033[1m"; + + // Text colors + public const RED = "\033[31m"; + public const GREEN = "\033[32m"; + public const YELLOW = "\033[33m"; + public const BLUE = "\033[34m"; + public const MAGENTA = "\033[35m"; + public const CYAN = "\033[36m"; + public const WHITE = "\033[37m"; + public const GRAY = "\033[90m"; + + // Background colors + public const BG_RED = "\033[41m"; + public const BG_GREEN = "\033[42m"; + public const BG_YELLOW = "\033[43m"; + + public static function colorize(string $text, string $color): string + { + return $color . $text . self::RESET; + } + + public static function success(string $text): string + { + return self::colorize("🚀 " . $text, self::GREEN . self::BOLD); + } + + public static function error(string $text): string + { + return self::colorize("❌ " . $text, self::RED . self::BOLD); + } + + public static function warning(string $text): string + { + return self::colorize("âš ī¸ " . $text, self::YELLOW . self::BOLD); + } + + public static function info(string $text): string + { + return self::colorize("â„šī¸ " . $text, self::CYAN . self::BOLD); + } + + public static function debug(string $text): string + { + return self::colorize($text, self::GRAY); + } +} + $config = Dotenv::createArrayBacked(__DIR__, '.env')->load(); class Watcher extends Watch @@ -66,7 +117,7 @@ class Watcher extends Watch public function watch(): void { - echo "Watching for changes..." . PHP_EOL . PHP_EOL; + echo Output::info("Watching for changes...") . PHP_EOL . PHP_EOL; $this->onAnyChange(function (): void { $this->killExistingProcess(); @@ -86,18 +137,18 @@ class Watcher extends Watch if ($process->isSuccessful() && strpos($process->getOutput(), $packageName) !== false) { return true; } else { - echo "Chokidar is not installed. Installing..." . PHP_EOL; + echo Output::warning("Chokidar is not installed. Installing...") . PHP_EOL; $installCommand = 'npm install ' . escapeshellarg($packageName); $installProcess = Process::fromShellCommandline($installCommand); $installProcess->run(); if ($installProcess->isSuccessful()) { - echo "Chokidar installed successfully." . PHP_EOL; + echo Output::success("Chokidar installed successfully.") . PHP_EOL; return true; } else { - echo "Failed to install chokidar. Please check your npm configuration." . PHP_EOL; + echo Output::error("Failed to install chokidar. Please check your npm configuration.") . PHP_EOL; echo $installProcess->getErrorOutput(); return false; @@ -109,7 +160,7 @@ class Watcher extends Watch { if ($this->consecutiveErrors >= $this->maxConsecutiveErrors || $this->stopAttempts) { if (!$this->stopAttempts) { - echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + echo Output::error("Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts.") . PHP_EOL; $this->stopAttempts = true; } @@ -133,9 +184,9 @@ class Watcher extends Watch $this->consecutiveErrors++; } - echo "Server failed to start. Exit code: {$exitCode}" . PHP_EOL; - echo "Error: " . $this->serverProcess->getErrorOutput() . PHP_EOL; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + echo Output::error("Server failed to start. Exit code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); @@ -151,17 +202,17 @@ class Watcher extends Watch } $this->pid = $this->serverProcess->getPid(); - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; - echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; + echo Output::success("Server started on {$this->host}:{$this->port}") . PHP_EOL; + echo Output::info("PID: {$this->pid}") . PHP_EOL . PHP_EOL; } catch (Exception $e) { if ($incrementErrorCounter) { $this->consecutiveErrors++; } - echo "Failed to start server: " . $e->getMessage() . PHP_EOL; - echo "Command: {$command}" . PHP_EOL; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + echo Output::error("Failed to start server: " . $e->getMessage()) . PHP_EOL; + echo Output::debug("Command: {$command}") . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); @@ -202,8 +253,58 @@ class Watcher extends Watch private function outputServerProcess(): void { - echo $this->serverProcess->getIncrementalOutput(); - echo $this->serverProcess->getIncrementalErrorOutput(); + $output = $this->serverProcess->getIncrementalOutput(); + $errorOutput = $this->serverProcess->getIncrementalErrorOutput(); + + if ($output) { + echo $this->colorizeServerOutput($output); + } + + if ($errorOutput) { + echo Output::colorize($errorOutput, Output::RED); + } + } + + private function colorizeServerOutput(string $output): string + { + $lines = explode("\n", $output); + $colorizedLines = []; + + foreach ($lines as $line) { + if (empty(trim($line))) { + $colorizedLines[] = $line; + + continue; + } + + if (strpos($line, '.NOTICE:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::CYAN); + } elseif (strpos($line, '.WARNING:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, '.ERROR:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::RED); + } elseif (strpos($line, '.DEBUG:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GRAY); + } elseif (strpos($line, '.INFO:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GREEN . Output::BOLD); + } elseif (strpos($line, 'GET') !== false || strpos($line, 'POST') !== false || strpos($line, 'PUT') !== false) { + if (strpos($line, ' 200 ') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, ' 404 ') !== false) { + $colorizedLines[] = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, ' 500 ') !== false) { + $colorizedLines[] = Output::colorize($line, Output::RED); + } else { + $colorizedLines[] = Output::colorize($line, Output::BLUE); + } + } else { + $colorizedLines[] = $line; + } + } + + return implode("\n", $colorizedLines); } private function periodicHealthCheck(): void @@ -214,23 +315,23 @@ class Watcher extends Watch if (time() - $this->lastHealthCheck > 10) { if (!$this->isServerHealthy()) { - echo "Server health check failed. Restarting..." . PHP_EOL; + echo Output::warning("Server health check failed. Restarting...") . PHP_EOL; $this->consecutiveErrors++; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL; $this->killExistingProcess(); if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { $this->runServer(false); } else { - echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + echo Output::error("Maximum consecutive errors reached. Server will not restart automatically.") . PHP_EOL; $this->stopAttempts = true; } } else { if ($this->consecutiveErrors > 0) { - echo "Server health check passed. Resetting error counter." . PHP_EOL; + echo Output::success("Server health check passed. Resetting error counter.") . PHP_EOL; $this->consecutiveErrors = 0; $this->stopAttempts = false; // Allow attempts again @@ -250,17 +351,17 @@ class Watcher extends Watch $exitCode = $this->serverProcess->getExitCode(); if ($exitCode !== null && $exitCode !== 0) { - echo "Server process exited with error code: {$exitCode}" . PHP_EOL; - echo "Error output: " . $this->serverProcess->getErrorOutput() . PHP_EOL; - echo "Restarting server..." . PHP_EOL . PHP_EOL; + echo Output::error("Server process exited with error code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error output: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::info("Restarting server...") . PHP_EOL . PHP_EOL; $this->consecutiveErrors++; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL; if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { $this->runServer(false); } else { - echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + echo Output::error("Maximum consecutive errors reached. Server will not restart automatically.") . PHP_EOL; $this->stopAttempts = true; } @@ -273,7 +374,7 @@ class Watcher extends Watch return; } - echo "Restarting server..." . PHP_EOL . PHP_EOL; + echo Output::info("Restarting server...") . PHP_EOL . PHP_EOL; try { $this->serverProcess->stop(3); // 3 second timeout @@ -283,10 +384,10 @@ class Watcher extends Watch $killProcess->run(); } - echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; + echo Output::success("Server was stopped (PID {$this->pid})") . PHP_EOL . PHP_EOL; } catch (Exception $e) { - echo "Error stopping server: " . $e->getMessage() . PHP_EOL; + echo Output::error("Error stopping server: " . $e->getMessage()) . PHP_EOL; $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); @@ -330,7 +431,7 @@ try { $watcher->watch(); } else { - echo "System is not ready. Exiting..." . PHP_EOL . PHP_EOL; + echo Output::error("System is not ready. Exiting...") . PHP_EOL . PHP_EOL; } } catch (Throwable $th) { echo $th->getMessage(); From 0538f1d2c485a6e67c8bb61fee44c28ee905bae5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 17:43:38 -0500 Subject: [PATCH 6/6] feat: refactor line colorization logic for improved readability and maintainability --- server | 78 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/server b/server index 4cee512..328ab9d 100644 --- a/server +++ b/server @@ -271,40 +271,58 @@ class Watcher extends Watch $colorizedLines = []; foreach ($lines as $line) { - if (empty(trim($line))) { - $colorizedLines[] = $line; + $colorizedLines[] = $this->colorizeLine($line); + } - continue; - } + return implode("\n", $colorizedLines); + } - if (strpos($line, '.NOTICE:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::CYAN); - } elseif (strpos($line, '.WARNING:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::YELLOW); - } elseif (strpos($line, '.ERROR:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::RED); - } elseif (strpos($line, '.DEBUG:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GRAY); - } elseif (strpos($line, '.INFO:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GREEN); - } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GREEN . Output::BOLD); - } elseif (strpos($line, 'GET') !== false || strpos($line, 'POST') !== false || strpos($line, 'PUT') !== false) { - if (strpos($line, ' 200 ') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GREEN); - } elseif (strpos($line, ' 404 ') !== false) { - $colorizedLines[] = Output::colorize($line, Output::YELLOW); - } elseif (strpos($line, ' 500 ') !== false) { - $colorizedLines[] = Output::colorize($line, Output::RED); - } else { - $colorizedLines[] = Output::colorize($line, Output::BLUE); - } - } else { - $colorizedLines[] = $line; - } + private function colorizeLine(string $line): string + { + $trimmed = trim($line); + $result = $line; + + if ($trimmed === '') { + // leave $result as $line + } elseif (strpos($line, '.NOTICE:') !== false) { + $result = Output::colorize($line, Output::CYAN); + } elseif (strpos($line, '.WARNING:') !== false) { + $result = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, '.ERROR:') !== false) { + $result = Output::colorize($line, Output::RED); + } elseif (strpos($line, '.DEBUG:') !== false) { + $result = Output::colorize($line, Output::GRAY); + } elseif (strpos($line, '.INFO:') !== false) { + $result = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { + $result = Output::colorize($line, Output::GREEN . Output::BOLD); + } elseif ($this->isHttpMethodLine($line)) { + $result = $this->colorizeHttpStatusLine($line); } - return implode("\n", $colorizedLines); + return $result; + } + + private function isHttpMethodLine(string $line): bool + { + return strpos($line, 'GET') !== false + || strpos($line, 'POST') !== false + || strpos($line, 'PUT') !== false; + } + + private function colorizeHttpStatusLine(string $line): string + { + $colorized = Output::colorize($line, Output::BLUE); + + if (strpos($line, ' 200 ') !== false) { + $colorized = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, ' 404 ') !== false) { + $colorized = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, ' 500 ') !== false) { + $colorized = Output::colorize($line, Output::RED); + } + + return $colorized; } private function periodicHealthCheck(): void