Skip to content

Commit

Permalink
swoole running and watch ok
Browse files Browse the repository at this point in the history
  • Loading branch information
asika32764 committed Aug 28, 2023
1 parent 4fb9897 commit 0a54d91
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 27 deletions.
16 changes: 16 additions & 0 deletions bin/file-watcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const chokidar = require('chokidar');

const paths = JSON.parse(process.argv[2]);
const options = JSON.parse(process.argv[3] || {});

const watcher = chokidar.watch(paths, {
ignoreInitial: true,
...options
});

watcher
.on('add', path => console.log(`fileCreated - ${path}`))
.on('change', path => console.log(`fileUpdated - ${path}`))
.on('unlink', path => console.log(`fileDeleted - ${path}`))
.on('addDir', path => console.log(`directoryCreated - ${path}`))
.on('unlinkDir', path => console.log(`directoryDeleted - ${path}`));
11 changes: 7 additions & 4 deletions src/Core/CliServer/CliServerClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public function logRequestInfo(RequestInterface $request, int $statusCode, float

$method = $request->getMethod();
$uri = $request->getUri()->getPath();
$pid = (string) getmypid();
$memory = number_format(memory_get_usage() / 1024 / 1024, 2) . 'MB';
$durationText = number_format($duration) . 'ms';

Expand All @@ -50,20 +51,22 @@ public function logRequestInfo(RequestInterface $request, int $statusCode, float
default => 'white',
};

$spaces = 25;
$length = $spaces + strlen($method . $statusCode . $uri . $memory . $durationText);
$spaces = 33;
$length = $spaces + strlen($method . $statusCode . $uri . $pid . $memory . $durationText);

$dots = str_repeat('.', $terminalWidth - $length);
$dots = str_repeat('.', max($terminalWidth - $length, 0));

$log = sprintf(
' [<fg=%s;options=bold>%s</>][%s] %s <fg=gray>%s</> [<fg=%s;options=bold>%s</>] %s - %s',
' [<fg=%s;options=bold>%s</>][%s] %s <fg=gray>%s</> [<fg=%s;options=bold>%s</>] ' .
'pid: <fg=yellow>%s</> - %s - %s',
$color,
$method,
$name,
$uri,
$dots,
$color,
$statusCode,
$pid,
$memory,
$durationText,
);
Expand Down
4 changes: 2 additions & 2 deletions src/Core/CliServer/CliServerEngineFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public function create(string $name, ?ConsoleOutputInterface $output = null): Cl
];

return match ($name) {
'php' => $this->container->newInstance(PhpCliServerEngine::class, $args),
'swoole' => $this->container->newInstance(SwooleCliServerEngine::class, $args),
'php' => $this->container->newInstance(PhpNativeEngine::class, $args),
'swoole' => $this->container->newInstance(SwooleEngine::class, $args),
default => $this->container->resolve($this->serverTypes[$name], $args),
};
}
Expand Down
4 changes: 1 addition & 3 deletions src/Core/CliServer/CliServerRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@
*/
class CliServerRuntime
{
protected static string $stateFilePath = '';

protected static CliServerStateManager $cliServerStateManager;

public static ConsoleOutput $output;

public static function parseArgv(array $argv): CliServerState
{
self::$stateFilePath = $stateFilePath = $argv[1] ?? '';
$stateFilePath = $argv[1] ?? '';

$cliServerStateManager = new CliServerStateManager($stateFilePath);

Expand Down
10 changes: 5 additions & 5 deletions src/Core/CliServer/CliServerState.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
class CliServerState extends ValueObject
{
public string $name = '';
public int $pid = 0;
public int $masterPid = 0;
public string $host = '';
public int $port = 0;
public int $managerPid = 0;
Expand Down Expand Up @@ -56,9 +56,9 @@ public function setName(string $name): static
return $this;
}

public function setPid(int $pid): static
public function setMasterPid(int $masterPid): static
{
$this->pid = $pid;
$this->masterPid = $masterPid;

return $this;
}
Expand All @@ -82,9 +82,9 @@ public function getManagerPid(): int
return $this->managerPid;
}

public function getPid(): int
public function getMasterPid(): int
{
return $this->pid;
return $this->masterPid;
}

public function getName(): string
Expand Down
37 changes: 37 additions & 0 deletions src/Core/CliServer/CliServerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* Part of cati project.
*
* @copyright Copyright (C) 2023 __ORGANIZATION__.
* @license __LICENSE__
*/

declare(strict_types=1);

namespace Windwalker\Core\CliServer;

use Symfony\Component\Process\PhpExecutableFinder;
use Windwalker\Core\Filesystem\FileWatcher;

/**
* Trait CliServerTrait
*/
trait CliServerTrait
{
protected function getPhpBinary(): false|string
{
return (new PhpExecutableFinder())->find();
}

public function createFileWatcher(string $mainFile): FileWatcher
{
$paths = (array) $this->app->config('reactor.watch');

$paths[] = $mainFile;

return FileWatcher::paths(...$paths)
->usePolling(false)
->awaitWriteFinish();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface ServerProcessManageInterface
{
public function isRunning(): bool;

public function reloadServer(): bool;
public function reloadServer(): void;

public function stopServer(): bool;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* docroot: string,
* }
*/
class PhpCliServerEngine implements CliServerEngineInterface
class PhpNativeEngine implements CliServerEngineInterface
{
use OptionsResolverTrait;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@
use function Windwalker\swoole_installed;

/**
* The SwooleCliServerEngine class.
* The SwooleEngine class.
*/
class SwooleCliServerEngine implements CliServerEngineInterface, ServerProcessManageInterface
class SwooleEngine implements CliServerEngineInterface, ServerProcessManageInterface
{
use InstanceCacheTrait;
use OptionsResolverTrait;
use MessageOutputTrait;
use ProcessRunnerTrait;
use CliServerTrait;

public function __construct(
protected ConsoleApplication $app,
Expand Down Expand Up @@ -108,7 +107,7 @@ public function run(string $host, int $port, array $options = []): int

$process = $this->app->createProcess(
[
$this->getPhpBinary(),
$this->getPhpBinary() ?: 'php',
$options['main'],
$this->serverStateManager->getFilePath(),
]
Expand All @@ -127,6 +126,7 @@ public function run(string $host, int $port, array $options = []): int

protected function runServerProcess(Process $process, CliServerState $state): int
{
$options = $state->getManagerOptions();
$process->start();

while (!$process->isStarted()) {
Expand All @@ -139,9 +139,12 @@ protected function runServerProcess(Process $process, CliServerState $state): in
$output->writeln('Starting...');
$output->newLine();

while (true) {
usleep(1000 * 500); // 0.5 seconds
if ($options['watch'] ?? null) {
$watcher = $this->createFileWatcher($options['main']);
$watcher->listen();
}

while ($process->isRunning()) {
$output = $process->getIncrementalOutput();
$errOutput = $process->getIncrementalErrorOutput();

Expand All @@ -155,6 +158,14 @@ protected function runServerProcess(Process $process, CliServerState $state): in
if ($errOutput) {
$this->output->write($errOutput);
}

if (isset($watcher) && $watcher->hasChanged()) {
$this->output->writeln('File changes detected. Restarting server.');

$this->reloadServer();
}

usleep(1000 * 500); // 0.5 seconds
}

return 0;
Expand All @@ -163,18 +174,21 @@ protected function runServerProcess(Process $process, CliServerState $state): in
public function isRunning(): bool
{
$state = $this->serverStateManager->getState();
$pid = $state->getPid();
$masterPid = $state->getMasterPid();
$managerPid = $state->getManagerPid();

if ($managerPid) {
return $pid && $managerPid && $this->isAlive($managerPid);
return $masterPid && $managerPid && $this->isAlive($managerPid);
}

return $pid && $this->isAlive($pid);
return $masterPid && $this->isAlive($masterPid);
}

public function reloadServer(): bool
public function reloadServer(): void
{
$state = $this->serverStateManager->getState();

static::signal($state->getMasterPid(), SIGUSR1);
}

public function stopServer(): bool
Expand Down
139 changes: 139 additions & 0 deletions src/Core/Filesystem/FileWatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

/**
* Part of cati project.
*
* @copyright Copyright (C) 2023 __ORGANIZATION__.
* @license __LICENSE__
*/

declare(strict_types=1);

namespace Windwalker\Core\Filesystem;

use Spatie\Watcher\Watch;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
use Windwalker\Utilities\Options\OptionAccessTrait;

/**
* The FileWatcher class.
*/
class FileWatcher extends Watch
{
use OptionAccessTrait;

protected ?Process $process = null;

public function __construct()
{
parent::__construct();

$this->options['usePolling'] = true;
}

public static function path(string $path): self
{
return (new static())->setPaths($path);
}

public static function paths(...$paths): self
{
return (new static())->setPaths($paths);
}

public function isRunning(): bool
{
return $this->process?->isRunning();
}

public function getChangedInfo(): string
{
return $this->process?->getIncrementalOutput();
}

public function hasChanged(): bool
{
return (bool) $this->getChangedInfo();
}

public function onFileChanged(callable $handler): self
{
$this->onFileCreated[] = $handler;
$this->onFileUpdated[] = $handler;
$this->onFileDeleted[] = $handler;

return $this;
}

public function doActions(string $output): void
{
$this->actOnOutput($output);
}

public function listen(): static
{
$this->process = $this->getWatchProcess();

return $this;
}

protected function getWatchProcess(): Process
{
$command = [
(new ExecutableFinder())->find('node'),
dirname(__DIR__, 3) . '/bin/file-watcher.js',
json_encode($this->paths, JSON_THROW_ON_ERROR),
json_encode($this->options, JSON_THROW_ON_ERROR),
];

$process = new Process(
command: $command,
timeout: null,
);

$process->start();

return $process;
}

public function stop(int $timeout = 10, int $signal = null): ?int
{
return $this->getRunningProcess()->stop($timeout, $signal);
}

public function getRunningProcess(): Process
{
if (!$this->process) {
throw new \RuntimeException('Process not exists');
}

if (!$this->process->isRunning()) {
throw new \RuntimeException('Process not running.');
}

return $this->process;
}

public function getProcess(): ?Process
{
return $this->process;
}

public function usePolling(bool $value): static
{
return $this->setOption('usePolling', $value);
}

public function awaitWriteFinish(int $stabilityThreshold = 2000, int $pollInterval = 100): static
{
return $this->setOption('awaitWriteFinish', compact('stabilityThreshold', 'pollInterval'));
}

public function disableAwaitWriteFinish(): static
{
unset($this->options['awaitWriteFinish']);

return $this;
}
}

0 comments on commit 0a54d91

Please sign in to comment.