ソースを参照

Support ReactPHP

walkor 9 年 前
コミット
9237b0d798
5 ファイル変更468 行追加1 行削除
  1. 230 0
      Events/React.php
  2. 76 0
      Events/React/ExtEventLoop.php
  3. 77 0
      Events/React/LibEventLoop.php
  4. 71 0
      Events/React/StreamSelectLoop.php
  5. 14 1
      Worker.php

+ 230 - 0
Events/React.php

@@ -0,0 +1,230 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+use React\EventLoop\LoopInterface;
+use React\EventLoop\Timer\TimerInterface;
+
+/**
+ * select eventloop
+ */
+class React implements LoopInterface
+{
+    protected $_loop = null;
+
+    public function __construct() {
+        if (function_exists('event_base_new')) {
+            $this->_loop = new \Workerman\Events\React\LibEventLoop();
+        } elseif (class_exists('EventBase', false)) {
+            $this->_loop = new \Workerman\Events\React\ExtEventLoop();
+        } else {
+            $this->_loop = new \Workerman\Events\React\StreamSelectLoop();
+        }
+    }
+
+    public function add($fd, $flag, $func, $args = array())
+    {
+        switch ($flag) {
+            case EventInterface::EV_READ:
+                return $this->_loop->addReadStream($fd, $func);
+            case EventInterface::EV_WRITE:
+                return $this->_loop->addWriteStream($fd, $func);
+            case EventInterface::EV_SIGNAL:
+                return $this->_loop->addSignal($fd, $func);
+            case EventInterface::EV_TIMER:
+                return $this->_loop->addPeriodicTimer($fd, $func);
+            case EventInterface::EV_TIMER_ONCE:
+                return $this->_loop->addTimer($fd, $func);
+        }
+        return false;
+    }
+
+    public function del($fd, $flag)
+    {
+        switch ($flag) {
+            case EventInterface::EV_READ:
+                return $this->_loop->removeReadStream($fd);
+            case EventInterface::EV_WRITE:
+                return $this->_loop->removeWriteStream($fd);
+            case EventInterface::EV_SIGNAL:
+                return $this->_loop->removeSignal($fd);
+            case EventInterface::EV_TIMER:
+            case EventInterface::EV_TIMER_ONCE;
+                return  $this->_loop->cancelTimer($fd);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function clearAllTimer()
+    {
+
+    }
+
+    public function getLoop()
+    {
+        return $this->_loop;
+    }
+
+
+    /**
+     * {@inheritdoc}
+     */
+    public function loop()
+    {
+        $this->_loop->run();
+    }
+
+    /**
+     * Register a listener to be notified when a stream is ready to read.
+     *
+     * @param resource $stream   The PHP stream resource to check.
+     * @param callable $listener Invoked when the stream is ready.
+     */
+    public function addReadStream($stream, callable $listener) {
+        return call_user_func(array($this->_loop, 'addReadStream'), $stream, $listener);
+    }
+
+    /**
+     * Register a listener to be notified when a stream is ready to write.
+     *
+     * @param resource $stream   The PHP stream resource to check.
+     * @param callable $listener Invoked when the stream is ready.
+     */
+    public function addWriteStream($stream, callable $listener) {
+        return call_user_func(array($this->_loop, 'addWriteStream'), $stream, $listener);
+    }
+
+    /**
+     * Remove the read event listener for the given stream.
+     *
+     * @param resource $stream The PHP stream resource.
+     */
+    public function removeReadStream($stream) {
+        return call_user_func(array($this->_loop, 'removeReadStream'), $stream);
+    }
+
+    /**
+     * Remove the write event listener for the given stream.
+     *
+     * @param resource $stream The PHP stream resource.
+     */
+    public function removeWriteStream($stream) {
+        return call_user_func(array($this->_loop, 'removeWriteStream'), $stream);
+    }
+
+    /**
+     * Remove all listeners for the given stream.
+     *
+     * @param resource $stream The PHP stream resource.
+     */
+    public function removeStream($stream) {
+        return call_user_func(array($this->_loop, 'removeStream'), $stream);
+    }
+
+    /**
+     * Enqueue a callback to be invoked once after the given interval.
+     *
+     * The execution order of timers scheduled to execute at the same time is
+     * not guaranteed.
+     *
+     * @param int|float $interval The number of seconds to wait before execution.
+     * @param callable  $callback The callback to invoke.
+     *
+     * @return TimerInterface
+     */
+    public function addTimer($interval, callable $callback) {
+        return call_user_func(array($this->_loop, 'addTimer'), $interval, $callback);
+    }
+
+    /**
+     * Enqueue a callback to be invoked repeatedly after the given interval.
+     *
+     * The execution order of timers scheduled to execute at the same time is
+     * not guaranteed.
+     *
+     * @param int|float $interval The number of seconds to wait before execution.
+     * @param callable  $callback The callback to invoke.
+     *
+     * @return TimerInterface
+     */
+    public function addPeriodicTimer($interval, callable $callback) {
+        return call_user_func(array($this->_loop, 'addPeriodicTimer'), $interval, $callback);
+    }
+
+    /**
+     * Cancel a pending timer.
+     *
+     * @param TimerInterface $timer The timer to cancel.
+     */
+    public function cancelTimer(TimerInterface $timer) {
+        return call_user_func(array($this->_loop, 'cancelTimer'), $timer);
+    }
+
+    /**
+     * Check if a given timer is active.
+     *
+     * @param TimerInterface $timer The timer to check.
+     *
+     * @return boolean True if the timer is still enqueued for execution.
+     */
+    public function isTimerActive(TimerInterface $timer) {
+        return call_user_func(array($this->_loop, 'isTimerActive'), $timer);
+    }
+
+    /**
+     * Schedule a callback to be invoked on the next tick of the event loop.
+     *
+     * Callbacks are guaranteed to be executed in the order they are enqueued,
+     * before any timer or stream events.
+     *
+     * @param callable $listener The callback to invoke.
+     */
+    public function nextTick(callable $listener) {
+        return call_user_func(array($this->_loop, 'nextTick'), $listener);
+    }
+
+    /**
+     * Schedule a callback to be invoked on a future tick of the event loop.
+     *
+     * Callbacks are guaranteed to be executed in the order they are enqueued.
+     *
+     * @param callable $listener The callback to invoke.
+     */
+    public function futureTick(callable $listener) {
+        return call_user_func(array($this->_loop, 'futureTick'), $listener);
+    }
+
+    /**
+     * Perform a single iteration of the event loop.
+     */
+    public function tick() {
+        return call_user_func(array($this->_loop, 'tick'));
+    }
+
+    /**
+     * Run the event loop until there are no more tasks to perform.
+     */
+    public function run() {
+        return call_user_func(array($this->_loop, 'run'));
+    }
+
+    /**
+     * Instruct a running event loop to stop.
+     */
+    public function stop() {
+        return call_user_func(array($this->_loop, 'stop'));
+    }
+}

+ 76 - 0
Events/React/ExtEventLoop.php

@@ -0,0 +1,76 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+
+/**
+ * Class ExtEventLoop
+ * @package Workerman\Events\React
+ */
+class ExtEventLoop extends \React\EventLoop\ExtEventLoop
+{
+    /**
+     * Event base.
+     *
+     * @var EventBase
+     */
+    protected $_eventBase = null;
+
+    /**
+     * All signal Event instances.
+     *
+     * @var array
+     */
+    protected $_signalEvents = array();
+
+    /**
+     * Construct
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $class = new \ReflectionClass('\React\EventLoop\ExtEventLoop');
+        $property = $class->getProperty('eventBase');
+        $property->setAccessible(true);
+        $this->_eventBase = $property->getValue($this);
+    }
+
+    /**
+     * Add signal handler.
+     *
+     * @param $signal
+     * @param $callback
+     * @return bool
+     */
+    public function addSignal($signal, $callback)
+    {
+        $event = \Event::signal($this->_eventBase, $signal, $callback);
+        if (!$event||!$event->add()) {
+            return false;
+        }
+        $this->_signalEvents[$signal] = $event;
+    }
+
+    /**
+     * Remove signal handler.
+     *
+     * @param $signal
+     */
+    public function removeSignal($signal)
+    {
+        if (isset($this->_signalEvents[$signal])) {
+            $this->_signalEvents[$signal]->del();
+            unset($this->_signalEvents[$signal]);
+        }
+    }
+}

+ 77 - 0
Events/React/LibEventLoop.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+
+/**
+ * Class LibEventLoop
+ * @package Workerman\Events\React
+ */
+class LibEventLoop extends \React\EventLoop\LibEventLoop
+{
+    /**
+     * Event base.
+     *
+     * @var event_base resource
+     */
+    protected $_eventBase = null;
+
+    /**
+     * All signal Event instances.
+     *
+     * @var array
+     */
+    protected $_signalEvents = array();
+
+    /**
+     * Construct.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $class = new \ReflectionClass('\React\EventLoop\LibEventLoop');
+        $property = $class->getProperty('eventBase');
+        $property->setAccessible(true);
+        $this->_eventBase = $property->getValue($this);
+    }
+
+    /**
+     * Add signal handler.
+     *
+     * @param $signal
+     * @param $callback
+     * @return bool
+     */
+    public function addSignal($signal, $callback)
+    {
+        $event = event_new();
+        $this->_signalEvents[$signal] = $event;
+        event_set($event, $signal, EV_SIGNAL | EV_PERSIST, $callback);
+        event_base_set($event, $this->_eventBase);
+        event_add($event);
+    }
+
+    /**
+     * Remove signal handler.
+     *
+     * @param $signal
+     */
+    public function removeSignal($signal)
+    {
+        if (isset($this->_signalEvents[$signal])) {
+            $event = $this->_signalEvents[$signal];
+            event_del($event);
+            unset($this->_signalEvents[$signal]);
+        }
+    }
+}

+ 71 - 0
Events/React/StreamSelectLoop.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+
+/**
+ * Class StreamSelectLoop
+ * @package Workerman\Events\React
+ */
+class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop
+{
+    /**
+     * Add signal handler.
+     *
+     * @param $signal
+     * @param $callback
+     * @return bool
+     */
+    public function addSignal($signal, $callback)
+    {
+        pcntl_signal($signal, $callback);
+    }
+
+    /**
+     * Remove signal handler.
+     *
+     * @param $signal
+     */
+    public function removeSignal($signal)
+    {
+        pcntl_signal($signal, SIG_IGN);
+    }
+
+    /**
+     * Emulate a stream_select() implementation that does not break when passed
+     * empty stream arrays.
+     *
+     * @param array        &$read   An array of read streams to select upon.
+     * @param array        &$write  An array of write streams to select upon.
+     * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
+     *
+     * @return integer|false The total number of streams that are ready for read/write.
+     * Can return false if stream_select() is interrupted by a signal.
+     */
+    protected function streamSelect(array &$read, array &$write, $timeout)
+    {
+        if ($read || $write) {
+            $except = null;
+            // Calls signal handlers for pending signals
+            pcntl_signal_dispatch();
+            // suppress warnings that occur, when stream_select is interrupted by a signal
+            return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout);
+        }
+
+        // Calls signal handlers for pending signals
+        pcntl_signal_dispatch();
+        $timeout && usleep($timeout);
+
+        return 0;
+    }
+}

+ 14 - 1
Worker.php

@@ -33,7 +33,7 @@ class Worker
      *
      * @var string
      */
-    const VERSION = '3.3.5';
+    const VERSION = '3.3.6';
 
     /**
      * Status starting.
@@ -542,6 +542,16 @@ class Worker
     }
 
     /**
+     * Get global event-loop instance.
+     *
+     * @return EventInterface
+     */
+    public static function getEventLoop()
+    {
+        return self::$globalEvent;
+    }
+
+    /**
      * Init idMap.
      * return void
      */
@@ -834,6 +844,9 @@ class Worker
      */
     protected static function getEventLoopName()
     {
+        if (interface_exists('\React\EventLoop\LoopInterface')) {
+            return 'React';
+        }
         foreach (self::$_availableEventLoops as $name) {
             if (extension_loaded($name)) {
                 self::$_eventLoopName = $name;