Skip to content

Commit 79078e6

Browse files
committed
Init
0 parents  commit 79078e6

24 files changed

+904
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
vendor
2+
bin
3+
composer.lock
4+
tmp/*

EProcess/Adapter/ChildProcess.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
namespace EProcess\Adapter;
4+
5+
use EProcess\Behaviour\UniversalSerializer;
6+
use EProcess\MessengerFactory;
7+
8+
use React\ChildProcess\Process;
9+
use React\EventLoop\LoopInterface;
10+
use Symfony\Component\Process\PhpExecutableFinder;
11+
12+
class ChildProcess
13+
{
14+
use UniversalSerializer;
15+
16+
private $script = <<<PHP
17+
<?php
18+
19+
require_once '%s';
20+
21+
set_time_limit(0);
22+
23+
use EProcess\MessengerFactory;
24+
use EProcess\Application\ApplicationFactory;
25+
use React\EventLoop\Factory;
26+
27+
\$loop = Factory::create();
28+
29+
\$messenger = MessengerFactory::client(
30+
'%s',
31+
\$loop
32+
);
33+
34+
\$application = ApplicationFactory::create('%s');
35+
36+
\$application->messenger(\$messenger);
37+
\$application->loop(\$loop);
38+
\$application->data(\$application->unserialize(base64_decode('%s')));
39+
40+
\$messenger->emit('initialized', true);
41+
42+
try {
43+
\$application->run();
44+
\$loop->run();
45+
} catch (\Exception \$e) {
46+
echo \$e;
47+
}
48+
PHP;
49+
50+
private $loop;
51+
private $process;
52+
private $executableFinder;
53+
54+
public function __construct(LoopInterface $loop)
55+
{
56+
$this->loop = $loop;
57+
$this->executableFinder = new PhpExecutableFinder();
58+
}
59+
60+
public function create($class, array $data = [])
61+
{
62+
if (false === $php = $this->executableFinder->find()) {
63+
throw new \RuntimeException('Unable to find the PHP executable.');
64+
}
65+
66+
$node = uniqid('thread_');
67+
$unix = sprintf('unix://tmp/%s.sock', $node);
68+
69+
$messenger = MessengerFactory::server($unix, $this->loop);
70+
71+
$file = sprintf(__DIR__ . '/../../tmp/%s.php', $node);
72+
73+
file_put_contents($file, sprintf(
74+
$this->script,
75+
EPROCESS_AUTOLOAD,
76+
$unix,
77+
$class,
78+
base64_encode($this->serialize($data))
79+
));
80+
81+
$this->process = new Process(sprintf('exec %s %s', $php, realpath($file)));
82+
$this->process->start($this->loop);
83+
84+
$this->loop->addTimer(5, function() use ($file) {
85+
unlink($file);
86+
});
87+
88+
$this->process->stdout->on('data', function($data) {
89+
echo $data;
90+
});
91+
92+
$this->process->stderr->on('data', function($data) {
93+
echo $data;
94+
});
95+
96+
register_shutdown_function(function() use ($unix) {
97+
unlink($unix);
98+
});
99+
100+
return $messenger;
101+
}
102+
103+
public function kill()
104+
{
105+
$this->process->close();
106+
}
107+
}

EProcess/Adapter/PThreads.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace EProcess\Adapter;
4+
5+
use EProcess\MessengerFactory;
6+
use React\EventLoop\LoopInterface;
7+
8+
class PThreads
9+
{
10+
private $loop;
11+
private $process;
12+
13+
public function __construct(LoopInterface $loop)
14+
{
15+
$this->loop = $loop;
16+
}
17+
18+
public function create($class, array $data = [])
19+
{
20+
$node = uniqid('thread_');
21+
$unix = sprintf('unix://tmp/%s.sock', $node);
22+
23+
$messenger = MessengerFactory::server($unix, $this->loop);
24+
25+
$this->process = new Thread($unix, $class, $data);
26+
$this->process->start(PTHREADS_INHERIT_NONE);
27+
28+
return $messenger;
29+
}
30+
31+
public function kill()
32+
{
33+
$this->process->kill();
34+
}
35+
}

EProcess/Adapter/SymfonyProcess.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace EProcess\Adapter;
4+
5+
use EProcess\Behaviour\UniversalSerializer;
6+
use Symfony\Component\Process\PhpProcess;
7+
use React\EventLoop\LoopInterface;
8+
use EProcess\MessengerFactory;
9+
10+
class SymfonyProcess
11+
{
12+
use UniversalSerializer;
13+
14+
private $script = <<<PHP
15+
<?php
16+
17+
require_once '%s';
18+
19+
set_time_limit(0);
20+
21+
use EProcess\MessengerFactory;
22+
use EProcess\Application\ApplicationFactory;
23+
use React\EventLoop\Factory;
24+
25+
\$loop = Factory::create();
26+
27+
\$messenger = MessengerFactory::client(
28+
'%s',
29+
\$loop
30+
);
31+
32+
\$application = ApplicationFactory::create('%s');
33+
34+
\$application->messenger(\$messenger);
35+
\$application->loop(\$loop);
36+
\$application->data(\$application->unserialize(base64_decode('%s')));
37+
38+
\$messenger->emit('initialized', true);
39+
40+
try {
41+
\$application->run();
42+
\$loop->run();
43+
} catch (\Exception \$e) {
44+
echo \$e;
45+
}
46+
PHP;
47+
48+
private $loop;
49+
private $process;
50+
51+
public function __construct(LoopInterface $loop)
52+
{
53+
$this->loop = $loop;
54+
}
55+
56+
public function create($class, array $data = [])
57+
{
58+
$node = uniqid('thread_');
59+
$unix = sprintf('unix://app/cache/%s.sock', $node);
60+
61+
$messenger = MessengerFactory::server($unix, $this->loop);
62+
63+
$script = sprintf($this->script, EPROCESS_AUTOLOAD, $unix, $class, base64_encode($this->serialize($data)));
64+
65+
$this->process = new PhpProcess($script);
66+
$this->process->start();
67+
68+
return $messenger;
69+
}
70+
71+
public function kill()
72+
{
73+
$this->process->stop();
74+
}
75+
}

EProcess/Adapter/Thread.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace EProcess\Adapter;
4+
5+
use EProcess\Application\ApplicationFactory;
6+
use EProcess\MessengerFactory;
7+
use React\EventLoop\Factory;
8+
9+
class Thread extends \Thread
10+
{
11+
private $class;
12+
private $unix;
13+
private $data;
14+
15+
public function __construct($unix, $class, array $data)
16+
{
17+
$this->unix = $unix;
18+
$this->class = $class;
19+
$this->data = $data;
20+
}
21+
22+
public function run()
23+
{
24+
require_once EPROCESS_AUTOLOAD;
25+
26+
$loop = Factory::create();
27+
28+
$messenger = MessengerFactory::client($this->unix, $loop);
29+
$application = ApplicationFactory::create($this->class);
30+
31+
$application->messenger($messenger);
32+
$application->loop($loop);
33+
$application->data($this->data);
34+
35+
$messenger->emit('initialized', true);
36+
37+
try {
38+
$application->run();
39+
$loop->run();
40+
} catch (\Exception $e) {
41+
echo $e;
42+
}
43+
}
44+
}

EProcess/Application/Application.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace EProcess\Application;
4+
5+
use EProcess\Behaviour\UniversalSerializer;
6+
use EProcess\Behaviour\Workable;
7+
use Evenement\EventEmitterTrait;
8+
use React\EventLoop\LoopInterface;
9+
use EProcess\Messenger;
10+
use EProcess\Message;
11+
12+
abstract class Application
13+
{
14+
use EventEmitterTrait {
15+
EventEmitterTrait::emit as emitterEmit;
16+
}
17+
use UniversalSerializer;
18+
use Workable;
19+
20+
private $loop;
21+
private $messenger;
22+
private $data;
23+
24+
public function loop(LoopInterface $loop = null)
25+
{
26+
if ($loop) {
27+
$this->loop = $loop;
28+
}
29+
30+
return $this->loop;
31+
}
32+
33+
public function messenger(Messenger $messenger = null)
34+
{
35+
if ($messenger) {
36+
$messenger->on('message', function(Message $message) {
37+
$this->emitterEmit($message->getEvent(), [$message->getContent()]);
38+
});
39+
40+
$this->messenger = $messenger;
41+
}
42+
43+
return $this->messenger;
44+
}
45+
46+
public function data(array $data = null)
47+
{
48+
if ($data) {
49+
$this->data = $data;
50+
}
51+
52+
return $this->data;
53+
}
54+
55+
public function emit($event, $data)
56+
{
57+
$this->messenger->emit($event, $data);
58+
}
59+
60+
abstract public function run();
61+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace EProcess\Application;
4+
5+
use React\EventLoop\Factory;
6+
7+
class ApplicationFactory
8+
{
9+
public static function launch($fqcn)
10+
{
11+
$application = static::create($fqcn);
12+
13+
try {
14+
$application->run();
15+
$application->loop()->run();
16+
} catch (\Exception $e) {
17+
echo $e;
18+
}
19+
}
20+
21+
public static function create($fqcn)
22+
{
23+
if (!is_subclass_of($fqcn, Application::class)) {
24+
throw new \InvalidArgumentException('Should be a subclass of Application');
25+
}
26+
27+
$loop = Factory::create();
28+
29+
$application = new $fqcn();
30+
$application->loop($loop);
31+
32+
return $application;
33+
}
34+
}

0 commit comments

Comments
 (0)