Skip to content

Commit a395b1d

Browse files
committed
Moved shared code for plugins in traits
1 parent eeb8979 commit a395b1d

File tree

4 files changed

+73
-71
lines changed

4 files changed

+73
-71
lines changed

src/Plugin/NullStop.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Luzrain\PHPStreamServer\Plugin;
6+
7+
use Amp\Future;
8+
use function Amp\async;
9+
10+
trait NullStop
11+
{
12+
public function stop(): Future
13+
{
14+
return async(static fn() => null);
15+
}
16+
}

src/Plugin/PcntlExecCommand.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Luzrain\PHPStreamServer\Plugin;
6+
7+
use Luzrain\PHPStreamServer\Server;
8+
9+
trait PcntlExecCommand
10+
{
11+
/**
12+
* Prepare command for pcntl_exec acceptable format
13+
*
14+
* @return array{0: string, 1: list<string>}
15+
*/
16+
private function prepareCommandForPcntlExec(string $command): array
17+
{
18+
// Check if command contains logic operators such as && and ||
19+
if (\preg_match('/(\'[^\']*\'|"[^"]*")(*SKIP)(*FAIL)|&&|\|\|/', $command) === 1) {
20+
throw new \RuntimeException(\sprintf(
21+
'%s does not directly support executing multiple commands with logical operators. Use shell with -c option e.g. "/bin/sh -c "%s"',
22+
Server::NAME,
23+
$command,
24+
));
25+
}
26+
27+
\preg_match_all('/\'[^\']*\'|"[^"]*"|\S+/', $command, $matches);
28+
$parts = \array_map(static fn (string $part): string => \trim($part, '"\''), $matches[0]);
29+
$binary = \array_shift($parts);
30+
$args = $parts;
31+
32+
if (!\str_starts_with($binary, '/') && \is_string($absoluteBinaryPath = \shell_exec("command -v $binary"))) {
33+
$binary = \trim($absoluteBinaryPath);
34+
}
35+
36+
return [$binary, $args];
37+
}
38+
}

src/Plugin/Scheduler/Scheduler.php

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
namespace Luzrain\PHPStreamServer\Plugin\Scheduler;
66

7-
use Amp\Future;
87
use Luzrain\PHPStreamServer\Internal\MasterProcess;
98
use Luzrain\PHPStreamServer\PeriodicProcess;
9+
use Luzrain\PHPStreamServer\Plugin\PcntlExecCommand;
10+
use Luzrain\PHPStreamServer\Plugin\NullStop;
1011
use Luzrain\PHPStreamServer\Plugin\PluginInterface;
11-
use Luzrain\PHPStreamServer\Server;
12-
use function Amp\async;
1312

1413
final readonly class Scheduler implements PluginInterface
1514
{
15+
use NullStop;
16+
use PcntlExecCommand;
17+
1618
/**
1719
* @param string|\Closure(PeriodicProcess): void $command bash command as string or php closure
1820
*/
@@ -34,56 +36,21 @@ public function start(MasterProcess $masterProcess): void
3436
default => $this->name,
3537
};
3638

37-
if (\is_string($this->command) && $this->isCommandContainsLogicOperators($this->command)) {
38-
throw new \RuntimeException(\sprintf(
39-
'%s does not directly support executing multiple commands with logical operators. Use shell with -c option e.g. "/bin/sh -c "%s"',
40-
Server::NAME,
41-
$this->command
42-
));
43-
}
39+
$pcntlExec = \is_string($this->command) ? $this->prepareCommandForPcntlExec($this->command) : null;
4440

4541
$masterProcess->addWorker(new PeriodicProcess(
4642
name: $name,
4743
schedule: $this->schedule,
4844
jitter: $this->jitter,
4945
user: $this->user,
5046
group: $this->group,
51-
onStart: function (PeriodicProcess $worker) {
52-
if (\is_string($this->command)) {
53-
$worker->exec(...$this->prepareCommand($this->command));
47+
onStart: function (PeriodicProcess $worker) use ($pcntlExec) {
48+
if ($pcntlExec !== null) {
49+
$worker->exec(...$pcntlExec);
5450
} else {
5551
($this->command)($worker);
5652
}
5753
},
5854
));
5955
}
60-
61-
/**
62-
* @return array{0: string, 1: list<string>}
63-
*/
64-
private function prepareCommand(string $command): array
65-
{
66-
\preg_match_all('/\'[^\']*\'|"[^"]*"|\S+/', $command, $matches);
67-
$parts = \array_map(static fn (string $part) => \trim($part, '"\''), $matches[0]);
68-
$binary = \array_shift($parts);
69-
$args = $parts;
70-
71-
if (!\str_starts_with($binary, '/')) {
72-
if (\is_string($absoluteBinaryPath = \shell_exec("command -v $binary"))) {
73-
$binary = \trim($absoluteBinaryPath);
74-
}
75-
}
76-
77-
return [$binary, $args];
78-
}
79-
80-
private function isCommandContainsLogicOperators(string $command): bool
81-
{
82-
return \preg_match('/(\'[^\']*\'|"[^"]*")(*SKIP)(*FAIL)|&&|\|\|/', $command) === 1;
83-
}
84-
85-
public function stop(): Future
86-
{
87-
return async(static fn() => null);
88-
}
8956
}

src/Plugin/Supervisor/Supervisor.php

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
namespace Luzrain\PHPStreamServer\Plugin\Supervisor;
66

7-
use Amp\Future;
87
use Luzrain\PHPStreamServer\Internal\MasterProcess;
8+
use Luzrain\PHPStreamServer\Plugin\PcntlExecCommand;
9+
use Luzrain\PHPStreamServer\Plugin\NullStop;
910
use Luzrain\PHPStreamServer\Plugin\PluginInterface;
1011
use Luzrain\PHPStreamServer\WorkerProcess;
11-
use function Amp\async;
1212

1313
final readonly class Supervisor implements PluginInterface
1414
{
15+
use NullStop;
16+
use PcntlExecCommand;
17+
1518
/**
1619
* @param string|\Closure(WorkerProcess): void $command bash command as string or php closure
1720
*/
@@ -34,44 +37,22 @@ public function start(MasterProcess $masterProcess): void
3437
default => $this->name,
3538
};
3639

40+
$pcntlExec = \is_string($this->command) ? $this->prepareCommandForPcntlExec($this->command) : null;
41+
3742
$masterProcess->addWorker(new WorkerProcess(
3843
name: $name,
3944
count: $this->count,
4045
reloadable: $this->reloadable,
4146
restartDelay: $this->restartDelay,
4247
user: $this->user,
4348
group: $this->group,
44-
onStart: function (WorkerProcess $worker) {
45-
if (\is_string($this->command)) {
46-
$worker->exec(...$this->prepareCommand($this->command));
49+
onStart: function (WorkerProcess $worker) use ($pcntlExec) {
50+
if ($pcntlExec !== null) {
51+
$worker->exec(...$pcntlExec);
4752
} else {
4853
($this->command)($worker);
4954
}
5055
},
5156
));
5257
}
53-
54-
/**
55-
* @return array{0: string, 1: list<string>}
56-
*/
57-
private function prepareCommand(string $command): array
58-
{
59-
\preg_match_all('/\'[^\']*\'|"[^"]*"|\S+/', $command, $matches);
60-
$parts = \array_map(static fn (string $part) => \trim($part, '"\''), $matches[0]);
61-
$binary = \array_shift($parts);
62-
$args = $parts;
63-
64-
if (!\str_starts_with($binary, '/')) {
65-
if (\is_string($absoluteBinaryPath = \shell_exec("command -v $binary"))) {
66-
$binary = \trim($absoluteBinaryPath);
67-
}
68-
}
69-
70-
return [$binary, $args];
71-
}
72-
73-
public function stop(): Future
74-
{
75-
return async(static fn() => null);
76-
}
7758
}

0 commit comments

Comments
 (0)