From d58216f7297c5e726bae25a2c9f0d00eff38d417 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 8 Apr 2025 01:17:11 +0200 Subject: [PATCH 1/6] feat: add `--watch` option to `nutgram:run` command --- composer.json | 3 ++- config/nutgram.php | 14 +++++++++++++ src/Console/RunCommand.php | 40 +++++++++++++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a3af4fc..41b6c23 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "require": { "php": "^8.2", "nunomaduro/termwind": "^1.0|^2.0", - "nutgram/nutgram": "^4.17.0" + "nutgram/nutgram": "^4.17.0", + "spatie/file-system-watcher": "^1.2" }, "require-dev": { "illuminate/testing": "^9.0|^10.0|^11.0|^12.0", diff --git a/config/nutgram.php b/config/nutgram.php index 2134833..23fa288 100644 --- a/config/nutgram.php +++ b/config/nutgram.php @@ -22,4 +22,18 @@ // Set log channel 'log_channel' => env('TELEGRAM_LOG_CHANNEL', 'null'), + + // Watch configs used by the "nutgram:run --watch" command + 'watch' => [ + // PHP binary to use + 'bin' => PHP_BINARY, + + // Interval in microseconds to check for changes + 'interval' => 250 * 1000, + + // Paths to watch + 'paths' => [ + app_path('Telegram'), + ] + ], ]; diff --git a/src/Console/RunCommand.php b/src/Console/RunCommand.php index 1d7830e..2df775c 100644 --- a/src/Console/RunCommand.php +++ b/src/Console/RunCommand.php @@ -3,22 +3,60 @@ namespace Nutgram\Laravel\Console; use Illuminate\Console\Command; +use Illuminate\Process\InvokedProcess; +use Illuminate\Support\Facades\Process; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use SergiX44\Nutgram\Nutgram; +use Spatie\Watcher\Watch; class RunCommand extends Command { - protected $signature = 'nutgram:run'; + protected $signature = 'nutgram:run {--watch : Watch for changes and restart the bot}'; protected $description = 'Start the bot in long polling mode'; + protected ?InvokedProcess $watchProcess = null; + /** * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function handle(Nutgram $bot): void { + if ($this->option('watch')) { + $this->watch(); + + return; + } + $bot->run(); } + + protected function watch(): void + { + $this->info('Watching for changes...'); + $this->startWatchProcess(); + + Watch::paths(...config('nutgram.watch.paths', [])) + ->setIntervalTime(config('nutgram.watch.interval', 250 * 1000)) + ->onAnyChange(function () { + $this->warn('Restarting the bot...'); + $this->watchProcess?->stop(); + $this->startWatchProcess(); + }) + ->start(); + } + + protected function startWatchProcess(): void + { + $this->watchProcess = Process::start( + command: config('nutgram.watch.bin', PHP_BINARY).' artisan nutgram:run', + output: function (string $type, string $output) { + $this->output->write($output); + } + ); + + $this->output->write($this->watchProcess->output()); + } } From 56933d64df4ae701770a3a3bf036665af84218e4 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 8 Apr 2025 01:20:30 +0200 Subject: [PATCH 2/6] fix: remove unused output --- src/Console/RunCommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Console/RunCommand.php b/src/Console/RunCommand.php index 2df775c..17ee688 100644 --- a/src/Console/RunCommand.php +++ b/src/Console/RunCommand.php @@ -56,7 +56,5 @@ protected function startWatchProcess(): void $this->output->write($output); } ); - - $this->output->write($this->watchProcess->output()); } } From 787862e7625f8c6363ce5f11f22fcfabd1572134 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 8 Apr 2025 22:00:15 +0200 Subject: [PATCH 3/6] fix realtime output on unix --- src/Console/RunCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/RunCommand.php b/src/Console/RunCommand.php index 17ee688..16a1463 100644 --- a/src/Console/RunCommand.php +++ b/src/Console/RunCommand.php @@ -50,7 +50,7 @@ protected function watch(): void protected function startWatchProcess(): void { - $this->watchProcess = Process::start( + $this->watchProcess = Process::tty(Process::supportsTty())->start( command: config('nutgram.watch.bin', PHP_BINARY).' artisan nutgram:run', output: function (string $type, string $output) { $this->output->write($output); From 40943a79f5da09cf87ee4dbcdbab277caf072e71 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 8 Apr 2025 23:57:10 +0200 Subject: [PATCH 4/6] refactor --- config/nutgram.php | 15 ++----- src/Console/RunCommand.php | 84 +++++++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/config/nutgram.php b/config/nutgram.php index 23fa288..8d14735 100644 --- a/config/nutgram.php +++ b/config/nutgram.php @@ -23,17 +23,8 @@ // Set log channel 'log_channel' => env('TELEGRAM_LOG_CHANNEL', 'null'), - // Watch configs used by the "nutgram:run --watch" command - 'watch' => [ - // PHP binary to use - 'bin' => PHP_BINARY, - - // Interval in microseconds to check for changes - 'interval' => 250 * 1000, - - // Paths to watch - 'paths' => [ - app_path('Telegram'), - ] + // Watch paths used by the "nutgram:run --watch" command + 'watch_paths' => [ + app_path('Telegram'), ], ]; diff --git a/src/Console/RunCommand.php b/src/Console/RunCommand.php index 16a1463..1b04eaa 100644 --- a/src/Console/RunCommand.php +++ b/src/Console/RunCommand.php @@ -3,8 +3,8 @@ namespace Nutgram\Laravel\Console; use Illuminate\Console\Command; -use Illuminate\Process\InvokedProcess; -use Illuminate\Support\Facades\Process; +use Symfony\Component\Process\PhpSubprocess; +use Symfony\Component\Process\Process; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use SergiX44\Nutgram\Nutgram; @@ -12,49 +12,85 @@ class RunCommand extends Command { - protected $signature = 'nutgram:run {--watch : Watch for changes and restart the bot}'; + protected $signature = 'nutgram:run {--watch : Watch for changes and restart the bot} + {--without-tty : Disable output to TTY}'; protected $description = 'Start the bot in long polling mode'; - protected ?InvokedProcess $watchProcess = null; + protected ?Process $runProcess = null; /** * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ - public function handle(Nutgram $bot): void + public function handle(Nutgram $bot): int { - if ($this->option('watch')) { - $this->watch(); + if (!$this->option('watch')) { + $bot->run(); - return; + return Command::SUCCESS; } - $bot->run(); + $this->info('Watching for changes...'); + + if(!$this->startAsyncRun()){ + return Command::FAILURE; + } + + $this->listenForChanges(); + + return Command::SUCCESS; } - protected function watch(): void + protected function startAsyncRun(): bool { - $this->info('Watching for changes...'); - $this->startWatchProcess(); - - Watch::paths(...config('nutgram.watch.paths', [])) - ->setIntervalTime(config('nutgram.watch.interval', 250 * 1000)) - ->onAnyChange(function () { - $this->warn('Restarting the bot...'); - $this->watchProcess?->stop(); - $this->startWatchProcess(); + $this->runProcess = (new PhpSubprocess(['artisan', 'nutgram:run', '--ansi'])) + ->setTty(Process::isTtySupported() && !$this->option('without-tty')) + ->setTimeout(null); + + $this->runProcess->start(function (string $type, string $output) { + if(Process::isTtySupported() && !$this->option('without-tty')) { + $this->output->write($output); + } + }); + + sleep(1); + + return ! $this->runProcess->isTerminated(); + } + + protected function listenForChanges(): self + { + Watch::paths(...config('nutgram.watch_paths', [])) + ->setIntervalTime(200 * 1000) + ->onAnyChange(function (string $event, string $path) { + if ($this->isPhpFile($path)) { + $this->restartAsyncRun(); + } }) ->start(); + + return $this; + } + + protected function isPhpFile(string $path): bool + { + return str_ends_with(strtolower($path), '.php'); } - protected function startWatchProcess(): void + protected function restartAsyncRun(): self { - $this->watchProcess = Process::tty(Process::supportsTty())->start( - command: config('nutgram.watch.bin', PHP_BINARY).' artisan nutgram:run', - output: function (string $type, string $output) { + $this->components->info('Change detected! Restarting bot...'); + + $this->runProcess->stop(); + $this->runProcess->wait(function (string $type, string $output) { + if(Process::isTtySupported() && !$this->option('without-tty')) { $this->output->write($output); } - ); + }); + + $this->startAsyncRun(); + + return $this; } } From 01ad845d2a44a704d5252a30df516334e2a12757 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Wed, 9 Apr 2025 00:04:18 +0200 Subject: [PATCH 5/6] refactor --- src/Console/RunCommand.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Console/RunCommand.php b/src/Console/RunCommand.php index 1b04eaa..b5f0194 100644 --- a/src/Console/RunCommand.php +++ b/src/Console/RunCommand.php @@ -80,14 +80,10 @@ protected function isPhpFile(string $path): bool protected function restartAsyncRun(): self { - $this->components->info('Change detected! Restarting bot...'); + $this->components->info('Changes detected! Restarting bot...'); $this->runProcess->stop(); - $this->runProcess->wait(function (string $type, string $output) { - if(Process::isTtySupported() && !$this->option('without-tty')) { - $this->output->write($output); - } - }); + $this->runProcess->wait(); $this->startAsyncRun(); From 12aaf6df1fff7b6699995a2500d3764b2f956694 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Wed, 9 Apr 2025 00:09:07 +0200 Subject: [PATCH 6/6] refactor --- src/Console/RunCommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Console/RunCommand.php b/src/Console/RunCommand.php index b5f0194..12f2abe 100644 --- a/src/Console/RunCommand.php +++ b/src/Console/RunCommand.php @@ -54,8 +54,6 @@ protected function startAsyncRun(): bool } }); - sleep(1); - return ! $this->runProcess->isTerminated(); }