Skip to content

Commit 0d35a3a

Browse files
committed
initial commit
0 parents  commit 0d35a3a

10 files changed

+229
-0
lines changed

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Voryx LLC
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Child Process Component
2+
3+
Provides RxPHP Observables for ReactPHP's [Child Process](https://github.com/reactphp/child-process)
4+

composer.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "rx/child-process",
3+
"type": "library",
4+
"description": "Library for executing child processes for RxPHP",
5+
"keywords": [
6+
"child process",
7+
"rxphp",
8+
"reactivex",
9+
"react",
10+
"reactphp",
11+
"stream",
12+
"rx.php"
13+
],
14+
"license": "MIT",
15+
"authors": [
16+
{
17+
"name": "David Dan",
18+
"email": "[email protected]",
19+
"role": "Developer"
20+
},
21+
{
22+
"name": "Matt Bonneau",
23+
"email": "[email protected]",
24+
"role": "Developer"
25+
}
26+
],
27+
"autoload": {
28+
"psr-4": {
29+
"Rx\\React\\": "src/"
30+
}
31+
},
32+
"require": {
33+
"voryx/event-loop": "^0.2.0",
34+
"reactivex/rxphp": "^1.0.0",
35+
"react/child-process": "^0.4.0"
36+
}
37+
}

examples/command.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
$process = new \Rx\React\ProcessSubject('echo foo');
6+
7+
$process->subscribe(new \Rx\Observer\CallbackObserver(function ($x) {
8+
echo $x;
9+
}));

examples/command_many.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
$ls1 = new \Rx\React\ProcessSubject('ls ' . __DIR__);
6+
$ls2 = new \Rx\React\ProcessSubject('ls ' . __DIR__ . '/../');
7+
8+
$ls1
9+
->merge($ls2)
10+
->subscribe(new \Rx\Observer\CallbackObserver(function ($x) {
11+
echo $x;
12+
}));

examples/command_with_error.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
$errors = new \Rx\Subject\Subject();
6+
7+
$process = new \Rx\React\ProcessSubject('somebadcommand', $errors);
8+
9+
$process->subscribe(new \Rx\Observer\CallbackObserver(function ($x) {
10+
echo $x;
11+
}));
12+
13+
$errors->subscribe(new \Rx\Observer\CallbackObserver(function (Exception $ex) {
14+
echo $ex->getMessage();
15+
}));
16+
17+
//sh: somebadcommand: command not found

examples/command_with_input.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
$process = new \Rx\React\ProcessSubject('echo "name:"; read name; echo $name');
6+
7+
$process->subscribe(new \Rx\Observer\CallbackObserver(function ($x) use ($process){
8+
echo $x;
9+
10+
//write to the process
11+
$process->onNext("Bob\n");
12+
}));

phpunit.xml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<phpunit
3+
backupGlobals="false"
4+
backupStaticAttributes="false"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
syntaxCheck="false"
12+
bootstrap="tests/bootstrap.php">
13+
<testsuites>
14+
<testsuite name="Rx/ChildProcess Tests">
15+
<directory>tests/</directory>
16+
</testsuite>
17+
</testsuites>
18+
</phpunit>

src/ProcessSubject.php

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Rx\React;
4+
5+
use React\ChildProcess\Process;
6+
use React\EventLoop\LoopInterface;
7+
use React\EventLoop\Timer\Timer;
8+
use Rx\Disposable\CallbackDisposable;
9+
use Rx\ObserverInterface;
10+
use Rx\Subject\Subject;
11+
12+
class ProcessSubject extends Subject
13+
{
14+
private $process;
15+
private $loop;
16+
private $errorObserver;
17+
18+
public function __construct($cmd, ObserverInterface $errorObserver = null, $cwd = null, array $env = null, array $options = [], LoopInterface $loop = null)
19+
{
20+
$this->process = $process = new Process($cmd, $cwd, $env, $options);
21+
$this->loop = $loop ?: \EventLoop\getLoop();
22+
$this->errorObserver = $errorObserver ?: new Subject();
23+
}
24+
25+
/**
26+
* @param $data
27+
*/
28+
public function onNext($data)
29+
{
30+
if ($this->process->stdin) {
31+
$this->process->stdin->write($data);
32+
}
33+
}
34+
35+
/**
36+
* @param ObserverInterface $observer
37+
* @param null $scheduler
38+
* @return CallbackDisposable
39+
*/
40+
public function subscribe(ObserverInterface $observer, $scheduler = null)
41+
{
42+
$this->loop->addTimer(0.001, function (Timer $timer) use ($observer) {
43+
44+
try {
45+
$this->process->start($timer->getLoop());
46+
47+
$this->process->stdout->on('data', function ($output) use ($observer) {
48+
$observer->onNext($output);
49+
});
50+
51+
$this->process->stderr->on('data', function ($output) use ($observer) {
52+
if ($output)
53+
$this->errorObserver->onNext(new \Exception($output));
54+
});
55+
56+
$this->process->stdout->on('close', function ($output) use ($observer) {
57+
$observer->onCompleted();
58+
});
59+
} catch (\Exception $e) {
60+
$observer->onError($e);
61+
}
62+
63+
});
64+
65+
return new CallbackDisposable(function () {
66+
$this->process->terminate();
67+
});
68+
}
69+
70+
/**
71+
* @return Process
72+
*/
73+
public function getProcess()
74+
{
75+
return $this->process;
76+
}
77+
}

tests/bootstrap.php

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Find the auto loader file
4+
*/
5+
$locations = [
6+
__DIR__ . '/../',
7+
__DIR__ . '/../../',
8+
__DIR__ . '/../../../',
9+
__DIR__ . '/../../../../',
10+
];
11+
12+
13+
foreach ($locations as $location) {
14+
15+
$file = $location . "vendor/autoload.php";
16+
17+
if (file_exists($file)) {
18+
$loader = require_once $file;
19+
$loader->addPsr4('Rx\\React\\Tests\\', __DIR__);
20+
break;
21+
}
22+
}

0 commit comments

Comments
 (0)