| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- <?php
- namespace Libs;
- use React\ChildProcess\Process;
- use React\Promise\Deferred;
- use React\EventLoop\Loop;
- final class ExecLib
- {
- public static function exec(string $cmd, ?float $timeoutSecs = null)
- {
- $process = new Process($cmd);
- $deferred = new Deferred();
- $bufferOut = '';
- $bufferErr = '';
- $timers = [];
- $process->start(Loop::get());
- if ($process->stdin !== null) {
- $process->stdin->end();
- }
- if ($process->stdout) {
- $process->stdout->on('data', function ($chunk) use (&$bufferOut) {
- $bufferOut .= (string)$chunk;
- });
- }
- if ($process->stderr) {
- $process->stderr->on('data', function ($chunk) use (&$bufferErr) {
- $bufferErr .= (string)$chunk;
- });
- }
- if ($timeoutSecs !== null && $timeoutSecs > 0) {
- $timers['timeout'] = Loop::addTimer($timeoutSecs, function () use ($process, $deferred) {
- if ($process->isRunning()) {
- $process->terminate(); // SIGTERM
- Loop::addTimer(1.0, function () use ($process) {
- if ($process->isRunning()) {
- $process->terminate(\defined('SIGKILL') ? \SIGKILL : null);
- }
- });
- }
- $deferred->reject(new \RuntimeException('CLI timeout'));
- });
- }
- $process->on('exit', function ($exitCode) use (&$bufferOut, &$bufferErr, $deferred, &$timers) {
- foreach ($timers as $t) {
- if ($t) {
- Loop::cancelTimer($t);
- }
- }
- $output = trim($bufferOut !== '' ? $bufferOut : $bufferErr);
- $deferred->resolve([(int)$exitCode, $output]);
- });
- $process->on('error', function (\Throwable $e) use ($deferred, &$timers) {
- foreach ($timers as $t) {
- if ($t) {
- Loop::cancelTimer($t);
- }
- }
- $deferred->reject($e);
- });
- return $deferred->promise();
- }
- }
|