diff --git a/src/Autoloader.php b/src/Autoloader.php index 33bb88b..e96f283 100644 --- a/src/Autoloader.php +++ b/src/Autoloader.php @@ -1,5 +1,4 @@ _remoteAddress) = \explode(':', $remote_address, 2); - if ('unix' === strtolower($scheme)) { + if('unix' === strtolower($scheme)) { $this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2); } if (!$this->_remoteAddress) { @@ -135,13 +135,13 @@ public function __construct($remote_address, array $context_option = array()) $this->_remotePort = $address_info['port']; $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; - $this->_remoteAddress = 'unix' === strtolower($scheme) - ? substr($remote_address, strpos($remote_address, '/') + 2) - : $this->_remoteHost . ':' . $this->_remotePort; + $this->_remoteAddress = 'unix' === strtolower($scheme) + ? substr($remote_address, strpos($remote_address, '/') + 2) + : $this->_remoteHost . ':' . $this->_remotePort; } $this->id = $this->_id = self::$_idRecorder++; - if (\PHP_INT_MAX === self::$_idRecorder) { + if(\PHP_INT_MAX === self::$_idRecorder){ self::$_idRecorder = 0; } // Check application layer protocol class. @@ -173,10 +173,8 @@ public function __construct($remote_address, array $context_option = array()) */ public function connect() { - if ( - $this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && - $this->_status !== self::STATUS_CLOSED - ) { + if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && + $this->_status !== self::STATUS_CLOSED) { return; } $this->_status = self::STATUS_CONNECTING; @@ -184,36 +182,20 @@ public function connect() if ($this->transport !== 'unix') { if (!$this->_remotePort) { $this->_remotePort = $this->transport === 'ssl' ? 443 : 80; - $this->_remoteAddress = $this->_remoteHost . ':' . $this->_remotePort; + $this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort; } // Open socket connection asynchronously. if ($this->_contextOption) { $context = \stream_context_create($this->_contextOption); - $this->_socket = \stream_socket_client( - "tcp://{$this->_remoteHost}:{$this->_remotePort}", - $errno, - $errstr, - 0, - \STREAM_CLIENT_ASYNC_CONNECT, - $context - ); + $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", + $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); } else { - $this->_socket = \stream_socket_client( - "tcp://{$this->_remoteHost}:{$this->_remotePort}", - $errno, - $errstr, - 0, - \STREAM_CLIENT_ASYNC_CONNECT - ); + $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", + $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT); } } else { - $this->_socket = \stream_socket_client( - "{$this->transport}://{$this->_remoteAddress}", - $errno, - $errstr, - 0, - \STREAM_CLIENT_ASYNC_CONNECT - ); + $this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + \STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. if (!$this->_socket || !\is_resource($this->_socket)) { @@ -228,14 +210,14 @@ public function connect() } // Add socket to global event loop waiting connection is successfully established or faild. Server::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection')); - // Для винды - if (\DIRECTORY_SEPARATOR === '\\') { + // For windows. + if(\DIRECTORY_SEPARATOR === '\\') { Server::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection')); } } /** - * Переподключение. + * Reconnect. * * @param int $after * @return void @@ -255,7 +237,7 @@ public function reconnect($after = 0) } /** - * Отмена переподключения. + * CancelReconnect. */ public function cancelReconnect() { @@ -265,7 +247,7 @@ public function cancelReconnect() } /** - * Получение удалённого хоста. + * Get remote address. * * @return string */ @@ -275,7 +257,7 @@ public function getRemoteHost() } /** - * Получение удалённого URI. + * Get remote URI. * * @return string */ @@ -285,7 +267,7 @@ public function getRemoteURI() } /** - * Попытка вызвать onError. + * Try to emit onError callback. * * @param int $code * @param string $msg @@ -293,13 +275,8 @@ public function getRemoteURI() */ protected function emitError($code, $msg) { - // Статус: закрытие соединения $this->_status = self::STATUS_CLOSING; - - // Если onError вообще задан if ($this->onError) { - // Попытка вызова - // Не получится - останавливай всё и логируй исключение/ошибку try { \call_user_func($this->onError, $this, $code, $msg); } catch (\Exception $e) { @@ -311,15 +288,15 @@ protected function emitError($code, $msg) } /** - * Проверка соединения. + * Check connection is successfully established or faild. * * @param resource $socket * @return void */ public function checkConnection() { - // Удалите EV_EXPEPE для Windows. - if (\DIRECTORY_SEPARATOR === '\\') { + // Remove EV_EXPECT for windows. + if(\DIRECTORY_SEPARATOR === '\\') { Server::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT); } diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index bb2c2b8..b269eb9 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -1,5 +1,4 @@ protocol = '\\Protocols\\' . $scheme; @@ -70,13 +70,13 @@ public function __construct($remote_address, $context_option = null) } } } - + $this->_remoteAddress = \substr($address, 2); $this->_contextOption = $context_option; } - + /** - * Для пакета UDP. + * For udp package. * * @param resource $socket * @return bool @@ -87,7 +87,7 @@ public function baseRead($socket) if (false === $recv_buffer || empty($remote_address)) { return false; } - + if ($this->onMessage) { if ($this->protocol) { $parser = $this->protocol; @@ -106,7 +106,7 @@ public function baseRead($socket) } /** - * Отправляет данные на соединение. + * Sends data on the connection. * * @param string $send_buffer * @param bool $raw @@ -126,10 +126,10 @@ public function send($send_buffer, $raw = false) } return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0); } - - + + /** - * Закрытие соединения + * Close connection. * * @param mixed $data * @param bool $raw @@ -138,17 +138,13 @@ public function send($send_buffer, $raw = false) */ public function close($data = null, $raw = false) { - // Если есть что сказать - скажи сейчас if ($data !== null) { $this->send($data, $raw); } - - // Удаляем из событий на чтение и закрываем стрим Server::$globalEvent->del($this->_socket, EventInterface::EV_READ); \fclose($this->_socket); $this->connected = false; - - // Попытка вызвать onClose + // Try to emit onClose callback. if ($this->onClose) { try { \call_user_func($this->onClose, $this); @@ -163,53 +159,35 @@ public function close($data = null, $raw = false) } /** - * Соединение + * Connect. * * @return void */ public function connect() { - // Если соединение уже есть не нужно подключаться дважды if ($this->connected === true) { return; } - - // Если есть контекст - используем его - // Если нет - просто слушаем стрим if ($this->_contextOption) { $context = \stream_context_create($this->_contextOption); - $this->_socket = \stream_socket_client( - "udp://{$this->_remoteAddress}", - $errno, - $errmsg, - 30, - \STREAM_CLIENT_CONNECT, - $context - ); + $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg, + 30, \STREAM_CLIENT_CONNECT, $context); } else { $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); } - // Обрабатываем исключение if (!$this->_socket) { Server::safeEcho(new \Exception($errmsg)); return; } - - // Отключаем блокировку стрима (non-blocking mode) - // Так мы сможем получать данные сразу без ожиданий + \stream_set_blocking($this->_socket, false); - - // Если есть обработчик - добавляем событие - // Если нет - не тратим время + if ($this->onMessage) { Server::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); } - - // Соединено $this->connected = true; - - // Попытка вызвать onConnect + // Try to emit onConnect callback. if ($this->onConnect) { try { \call_user_func($this->onConnect, $this); @@ -220,4 +198,5 @@ public function connect() } } } + } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 6182fee..1a3e4b3 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -1,5 +1,4 @@ id + * Connection->id. * * @var int */ public $id = 0; /** - * Копия $server->id который использовался для очистки $server->connections + * A copy of $server->id which used to clean up the connection in server->connections * * @var int */ protected $_id = 0; /** - * Максимальный размер буфера отправки для текущего соединения - * Когда буфер заполнится будет вызван OnBufferFull + * Sets the maximum send buffer size for the current connection. + * OnBufferFull callback will be emited When the send buffer is full. * * @var int */ public $maxSendBufferSize = 1048576; /** - * Стандартный размер буфера отправки + * Default send buffer size. * * @var int */ @@ -171,16 +169,16 @@ class TcpConnection extends ConnectionInterface * @var int */ public $maxPackageSize = 1048576; - + /** - * Максимально приемлемый размер пакета по умолчанию + * Default maximum acceptable packet size. * * @var int */ public static $defaultMaxPackageSize = 10485760; /** - * ID Регистратор + * Id recorder. * * @var int */ @@ -194,28 +192,28 @@ class TcpConnection extends ConnectionInterface protected $_socket = null; /** - * Буфер отправки + * Send buffer. * * @var string */ protected $_sendBuffer = ''; /** - * Буфер получения + * Receive buffer. * * @var string */ protected $_recvBuffer = ''; /** - * Длина текущего пакета + * Current package length. * * @var int */ protected $_currentPackageLength = 0; /** - * Статус соединения + * Connection status. * * @var int */ @@ -236,21 +234,21 @@ class TcpConnection extends ConnectionInterface protected $_isPaused = false; /** - * SSL-handshake? + * SSL handshake completed or not. * * @var bool */ protected $_sslHandshakeCompleted = false; /** - * Все экземпляры соеденения + * All connection instances. * * @var array */ public static $connections = array(); /** - * Статус в строку + * Status to string. * * @var array */ @@ -272,7 +270,7 @@ public function __construct($socket, $remote_address = '') { ++self::$statistics['connection_count']; $this->id = $this->_id = self::$_idRecorder++; - if (self::$_idRecorder === \PHP_INT_MAX) { + if(self::$_idRecorder === \PHP_INT_MAX){ self::$_idRecorder = 0; } $this->_socket = $socket; @@ -289,7 +287,11 @@ public function __construct($socket, $remote_address = '') } /** - * {@inheritdoc} + * Get status. + * + * @param bool $raw_output + * + * @return int|string */ public function getStatus($raw_output = true) { @@ -321,8 +323,7 @@ public function send($send_buffer, $raw = false) } } - if ( - $this->_status !== self::STATUS_ESTABLISHED || + if ($this->_status !== self::STATUS_ESTABLISHED || ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) ) { if ($this->_sendBuffer && $this->bufferIsFull()) { @@ -394,7 +395,9 @@ public function send($send_buffer, $raw = false) } /** - * {@inheritdoc} + * Get remote IP. + * + * @return string */ public function getRemoteIp() { @@ -406,7 +409,9 @@ public function getRemoteIp() } /** - * {@inheritdoc} + * Get remote port. + * + * @return int */ public function getRemotePort() { @@ -417,7 +422,9 @@ public function getRemotePort() } /** - * {@inheritdoc} + * Get remote address. + * + * @return string */ public function getRemoteAddress() { @@ -425,7 +432,9 @@ public function getRemoteAddress() } /** - * {@inheritdoc} + * Get local IP. + * + * @return string */ public function getLocalIp() { @@ -438,7 +447,9 @@ public function getLocalIp() } /** - * {@inheritdoc} + * Get local port. + * + * @return int */ public function getLocalPort() { @@ -451,7 +462,9 @@ public function getLocalPort() } /** - * {@inheritdoc} + * Get local address. + * + * @return string */ public function getLocalAddress() { @@ -519,7 +532,7 @@ public function pauseRecv() } /** - * Возобновление чтения после вызова pauseRecv + * Resumes reading after a call to pauseRecv. * * @return void */ @@ -532,8 +545,10 @@ public function resumeRecv() } } + + /** - * Базовый обработчик чтения + * Base read handler. * * @param resource $socket * @param bool $check_eof @@ -541,7 +556,7 @@ public function resumeRecv() */ public function baseRead($socket, $check_eof = true) { - // SSL-handshake + // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { if ($this->doSslHandshake($socket)) { $this->_sslHandshakeCompleted = true; @@ -556,11 +571,9 @@ public function baseRead($socket, $check_eof = true) $buffer = ''; try { $buffer = @\fread($socket, self::READ_BUFFER_SIZE); - } catch (\Exception $e) { - } catch (\Error $e) { - } + } catch (\Exception $e) {} catch (\Error $e) {} - // Проверка закрытия соединения + // Check connection closed. if ($buffer === '' || $buffer === false) { if ($check_eof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) { $this->destroy(); @@ -585,9 +598,7 @@ public function baseRead($socket, $check_eof = true) // Get current package length. try { $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); - } catch (\Exception $e) { - } catch (\Error $e) { - } + } catch (\Exception $e) {} catch (\Error $e) {} // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; @@ -655,32 +666,24 @@ public function baseRead($socket, $check_eof = true) } /** - * Базовый обработчик записи + * Base write handler. * * @return void|bool */ public function baseWrite() { - // Обработчик ошибок... пока не до тебя - \set_error_handler(function () { - }); - - // Если это SSL - ограничим длину + \set_error_handler(function(){}); if ($this->transport === 'ssl') { $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192); } else { $len = @\fwrite($this->_socket, $this->_sendBuffer); } - - // А теперь восстанавливаем прежний обработчик)) \restore_error_handler(); - - // Следим за буфером if ($len === \strlen($this->_sendBuffer)) { $this->bytesWritten += $len; Server::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); $this->_sendBuffer = ''; - // Попытка вызвать onBufferDrain когда буфер отправки пустой + // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { \call_user_func($this->onBufferDrain, $this); @@ -705,50 +708,48 @@ public function baseWrite() } /** - * SSL-handshake + * SSL handshake. * * @param resource $socket * @return bool */ - public function doSslHandshake($socket) - { + public function doSslHandshake($socket){ if (\feof($socket)) { $this->destroy(); return false; } $async = $this instanceof AsyncTcpConnection; - + /** - * Поддержка SSL3 отключена. Подробнее: https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. - * Лучше не включать, но пусть это побудет здесь - */ + * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. + * You can enable ssl3 by the codes below. + */ /*if($async){ $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT; }else{ $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER; }*/ - - if ($async) { + + if($async){ $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT; - } else { + }else{ $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER; } - - // Обработчик ошибок с SSL - \set_error_handler(function ($errno, $errstr, $file) { + + // Hidden error. + \set_error_handler(function($errno, $errstr, $file){ if (!Server::$daemonize) { Server::safeEcho("SSL handshake error: $errstr \n"); } }); $ret = \stream_socket_enable_crypto($socket, true, $type); \restore_error_handler(); - - // Соединение прервалось + // Negotiation has failed. if (false === $ret) { $this->destroy(); return false; } elseif (0 === $ret) { - // Там недостаточно данных, мы должны попробовать еще раз + // There isn't enough data and should try again. return 0; } if (isset($this->onSslHandshake)) { @@ -764,21 +765,21 @@ public function doSslHandshake($socket) } /** - * Этот метод вытаскивает все данные из читаемого потока и записывает их в указанное место назначения. + * This method pulls all the data out of a readable stream, and writes it to the supplied destination. * * @param self $dest * @return void */ public function pipe(self $dest) { - $source = $this; - $this->onMessage = function ($source, $data) use ($dest) { + $source = $this; + $this->onMessage = function ($source, $data) use ($dest) { $dest->send($data); }; - $this->onClose = function ($source) use ($dest) { + $this->onClose = function ($source) use ($dest) { $dest->close(); }; - $dest->onBufferFull = function ($dest) use ($source) { + $dest->onBufferFull = function ($dest) use ($source) { $source->pauseRecv(); }; $dest->onBufferDrain = function ($dest) use ($source) { @@ -787,7 +788,7 @@ public function pipe(self $dest) } /** - * Удаление $length данных из буфера чтения + * Remove $length of data from receive buffer. * * @param int $length * @return void @@ -806,7 +807,7 @@ public function consumeRecvBuffer($length) */ public function close($data = null, $raw = false) { - if ($this->_status === self::STATUS_CONNECTING) { + if($this->_status === self::STATUS_CONNECTING){ $this->destroy(); return; } @@ -820,7 +821,7 @@ public function close($data = null, $raw = false) } $this->_status = self::STATUS_CLOSING; - + if ($this->_sendBuffer === '') { $this->destroy(); } else { @@ -859,12 +860,13 @@ protected function checkBufferWillFull() } /** - * Заполнен ли буфер отправки? + * Whether send buffer is full. * * @return bool */ protected function bufferIsFull() { + // Buffer has been marked as full but still has data to send then the packet is discarded. if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onError) { try { @@ -879,43 +881,39 @@ protected function bufferIsFull() } return false; } - + /** - * Пуст ли буфер отправки? + * Whether send buffer is Empty. * * @return bool */ public function bufferIsEmpty() { - return empty($this->_sendBuffer); + return empty($this->_sendBuffer); } /** - * Разорвать соединение + * Destroy connection. * * @return void */ public function destroy() { - // Избегаем повторяющихся вызовов + // Avoid repeated calls. if ($this->_status === self::STATUS_CLOSED) { return; } - - // Удаляем обработчик события + // Remove event listener. Server::$globalEvent->del($this->_socket, EventInterface::EV_READ); Server::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); - // Закрытие сокета + // Close socket. try { @\fclose($this->_socket); - } catch (\Exception $e) { - } catch (\Error $e) { - } + } catch (\Exception $e) {} catch (\Error $e) {} $this->_status = self::STATUS_CLOSED; - - // Попытка вызова onClose + // Try to emit onClose callback. if ($this->onClose) { try { \call_user_func($this->onClose, $this); @@ -925,8 +923,7 @@ public function destroy() Server::stopAll(250, $e); } } - - // Попытка вызова protocol::onClose + // Try to emit protocol::onClose if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { \call_user_func(array($this->protocol, 'onClose'), $this); @@ -936,14 +933,13 @@ public function destroy() Server::stopAll(250, $e); } } - $this->_sendBuffer = $this->_recvBuffer = ''; $this->_currentPackageLength = 0; $this->_isPaused = $this->_sslHandshakeCompleted = false; if ($this->_status === self::STATUS_CLOSED) { - // Очищаем обработчик, чтобы избежать утечки памяти + // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; - // Удаляем соединение из server->connections. + // Remove from server->connections. if ($this->server) { unset($this->server->connections[$this->_id]); } @@ -952,6 +948,8 @@ public function destroy() } /** + * Destruct. + * * @return void */ public function __destruct() @@ -964,10 +962,10 @@ public function __destruct() } if (0 === self::$statistics['connection_count'] % $mod) { - Server::log('Сервер [' . \posix_getpid() . ']: осталось ' . self::$statistics['connection_count'] . ' соединений'); + Server::log('server[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } - if (0 === self::$statistics['connection_count']) { + if(0 === self::$statistics['connection_count']) { Server::stopAll(); } } diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index fb87ac8..a15dc73 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -1,5 +1,4 @@ _eventTimer[self::$_timerId] = $event; return self::$_timerId++; - default: + default : $fd_key = (int)$fd; $real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE; $event = new \EvIo($fd, $real_flag, $callback); $this->_allEvents[$fd_key][$flag] = $event; return true; } + } /** diff --git a/src/Events/Event.php b/src/Events/Event.php index 26085b9..9072bd2 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -1,5 +1,4 @@ -_eventBase = new $class_name(); } - + /** - * Добавление события - * * @see EventInterface::add() */ - public function add($fd, $flag, $func, $args = array()) + public function add($fd, $flag, $func, $args=array()) { - // Да, тут по сути в каждом событии будет функция добавления нового события - // В формате того же класса Event if (\class_exists('\\\\Event', false)) { $class_name = '\\\\Event'; } else { @@ -86,7 +79,7 @@ public function add($fd, $flag, $func, $args = array()) $fd_key = (int)$fd; $event = $class_name::signal($this->_eventBase, $fd, $func); - if (!$event || !$event->add()) { + if (!$event||!$event->add()) { return false; } $this->_eventSignal[$fd_key] = $event; @@ -96,28 +89,26 @@ public function add($fd, $flag, $func, $args = array()) case self::EV_TIMER_ONCE: $param = array($func, (array)$args, $flag, $fd, self::$_timerId); - $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, array($this, "timerCallback"), $param); - if (!$event || !$event->addTimer($fd)) { + $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT|$class_name::PERSIST, array($this, "timerCallback"), $param); + if (!$event||!$event->addTimer($fd)) { return false; } $this->_eventTimer[self::$_timerId] = $event; return self::$_timerId++; - - default: + + default : $fd_key = (int)$fd; $real_flag = $flag === self::EV_READ ? $class_name::READ | $class_name::PERSIST : $class_name::WRITE | $class_name::PERSIST; $event = new $class_name($this->_eventBase, $fd, $real_flag, $func, $fd); - if (!$event || !$event->add()) { + if (!$event||!$event->add()) { return false; } $this->_allEvents[$fd_key][$flag] = $event; return true; } } - + /** - * Удаление события - * * @see Events\EventInterface::del() */ public function del($fd, $flag) @@ -155,8 +146,9 @@ public function del($fd, $flag) } return true; } - + /** + * Timer callback. * @param int|null $fd * @param int $what * @param int $timer_id @@ -164,7 +156,7 @@ public function del($fd, $flag) public function timerCallback($fd, $what, $param) { $timer_id = $param[4]; - + if ($param[2] === self::EV_TIMER_ONCE) { $this->_eventTimer[$timer_id]->del(); unset($this->_eventTimer[$timer_id]); @@ -178,7 +170,7 @@ public function timerCallback($fd, $what, $param) Server::stopAll(250, $e); } } - + /** * @see Events\EventInterface::clearAllTimer() * @return void @@ -190,7 +182,7 @@ public function clearAllTimer() } $this->_eventTimer = array(); } - + /** * @see EventInterface::loop() @@ -201,7 +193,7 @@ public function loop() } /** - * Разорвать цикл. + * Destroy loop. * * @return void */ @@ -211,7 +203,7 @@ public function destroy() } /** - * Кол-во таймеров. + * Get timer count. * * @return integer */ diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 4abc22a..4cd0b97 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -1,5 +1,4 @@ _eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval); return $timer_id; - default: + default : $fd_key = (int)$fd; $real_flag = $flag === self::EV_READ ? \EV_READ | \EV_PERSIST : \EV_WRITE | \EV_PERSIST; @@ -119,6 +117,7 @@ public function add($fd, $flag, $func, $args = array()) return true; } + } /** @@ -222,3 +221,4 @@ public function getTimerCount() return \count($this->_eventTimer); } } + diff --git a/src/Events/React/Base.php b/src/Events/React/Base.php index 08defe3..0757bdf 100644 --- a/src/Events/React/Base.php +++ b/src/Events/React/Base.php @@ -1,5 +1,4 @@ _signalHandlerMap[$fd] = $func; return $this->addSignal($fd, $func); case EventInterface::EV_TIMER: - $timer_obj = $this->addPeriodicTimer($fd, function () use ($func, $args) { + $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { \call_user_func_array($func, $args); }); $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; return $this->_timerIdIndex; case EventInterface::EV_TIMER_ONCE: $index = ++$this->_timerIdIndex; - $timer_obj = $this->addTimer($fd, function () use ($func, $args, $index) { - $this->del($index, EventInterface::EV_TIMER_ONCE); + $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { + $this->del($index,EventInterface::EV_TIMER_ONCE); \call_user_func_array($func, $args); }); $this->_timerIdMap[$index] = $timer_obj; @@ -117,7 +115,7 @@ public function del($fd, $flag) case EventInterface::EV_TIMER: case EventInterface::EV_TIMER_ONCE: - if (isset($this->_timerIdMap[$fd])) { + if (isset($this->_timerIdMap[$fd])){ $timer_obj = $this->_timerIdMap[$fd]; unset($this->_timerIdMap[$fd]); $this->cancelTimer($timer_obj); @@ -146,6 +144,7 @@ public function loop() */ public function destroy() { + } /** diff --git a/src/Events/React/ExtEventLoop.php b/src/Events/React/ExtEventLoop.php index 76de25c..f396fb6 100644 --- a/src/Events/React/ExtEventLoop.php +++ b/src/Events/React/ExtEventLoop.php @@ -1,5 +1,4 @@ _eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); $select_timeout = ($run_time - \microtime(true)) * 1000000; $select_timeout = $select_timeout <= 0 ? 1 : $select_timeout; - if ($this->_selectTimeout > $select_timeout) { - $this->_selectTimeout = (int) $select_timeout; - } + if( $this->_selectTimeout > $select_timeout ){ + $this->_selectTimeout = (int) $select_timeout; + } return $timer_id; } @@ -185,12 +183,13 @@ public function del($fd, $flag) return true; case self::EV_EXCEPT: unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]); - if (empty($this->_allEvents[$fd_key])) { + if(empty($this->_allEvents[$fd_key])) + { unset($this->_allEvents[$fd_key]); } return true; case self::EV_SIGNAL: - if (\DIRECTORY_SEPARATOR !== '/') { + if(\DIRECTORY_SEPARATOR !== '/') { return false; } unset($this->_signalEvents[$fd_key]); @@ -257,7 +256,7 @@ public function clearAllTimer() public function loop() { while (1) { - if (\DIRECTORY_SEPARATOR === '/') { + if(\DIRECTORY_SEPARATOR === '/') { // Calls signal handlers for pending signals \pcntl_signal_dispatch(); } @@ -271,9 +270,8 @@ public function loop() // Waiting read/write/signal/timeout events. try { $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout); - } catch (\Exception $e) { - } catch (\Error $e) { - } + } catch (\Exception $e) {} catch (\Error $e) {} + } else { $this->_selectTimeout >= 1 && usleep($this->_selectTimeout); $ret = false; @@ -292,10 +290,8 @@ public function loop() foreach ($read as $fd) { $fd_key = (int)$fd; if (isset($this->_allEvents[$fd_key][self::EV_READ])) { - \call_user_func_array( - $this->_allEvents[$fd_key][self::EV_READ][0], - array($this->_allEvents[$fd_key][self::EV_READ][1]) - ); + \call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], + array($this->_allEvents[$fd_key][self::EV_READ][1])); } } } @@ -304,22 +300,18 @@ public function loop() foreach ($write as $fd) { $fd_key = (int)$fd; if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { - \call_user_func_array( - $this->_allEvents[$fd_key][self::EV_WRITE][0], - array($this->_allEvents[$fd_key][self::EV_WRITE][1]) - ); + \call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], + array($this->_allEvents[$fd_key][self::EV_WRITE][1])); } } } - if ($except) { - foreach ($except as $fd) { + if($except) { + foreach($except as $fd) { $fd_key = (int) $fd; - if (isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) { - \call_user_func_array( - $this->_allEvents[$fd_key][self::EV_EXCEPT][0], - array($this->_allEvents[$fd_key][self::EV_EXCEPT][1]) - ); + if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) { + \call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0], + array($this->_allEvents[$fd_key][self::EV_EXCEPT][1])); } } } @@ -327,16 +319,17 @@ public function loop() } /** - * Разорвать цикл. + * Destroy loop. * * @return void */ public function destroy() { + } /** - * Кол-во таймеров. + * Get timer count. * * @return integer */ diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index b753117..0b5934a 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -1,5 +1,4 @@ _hasSignal && $res) { - Timer::tick( - static::$signalDispatchInterval, + if (! $this->_hasSignal && $res) { + Timer::tick(static::$signalDispatchInterval, function () { \pcntl_signal_dispatch(); - } - ); + }); $this->_hasSignal = true; } return $res; @@ -64,10 +60,9 @@ function () { $mapId = $this->mapId++; $t = (int)($fd * 1000); if ($t < 1) { - $t = 1; + $t = 1; } - $timer_id = Timer::$method( - $t, + $timer_id = Timer::$method($t, function ($timer_id = null) use ($func, $args, $mapId) { try { \call_user_func_array($func, (array)$args); @@ -77,18 +72,15 @@ function ($timer_id = null) use ($func, $args, $mapId) { Server::stopAll(250, $e); } // EV_TIMER_ONCE - if (!isset($timer_id)) { + if (! isset($timer_id)) { // may be deleted in $func if (\array_key_exists($mapId, $this->_timerOnceMap)) { $timer_id = $this->_timerOnceMap[$mapId]; - unset( - $this->_timer[$timer_id], - $this->_timerOnceMap[$mapId] - ); + unset($this->_timer[$timer_id], + $this->_timerOnceMap[$mapId]); } } - } - ); + }); if ($flag === self::EV_TIMER_ONCE) { $this->_timerOnceMap[$mapId] = $timer_id; $this->_timer[$timer_id] = $mapId; @@ -99,7 +91,7 @@ function ($timer_id = null) use ($func, $args, $mapId) { case self::EV_READ: case self::EV_WRITE: $fd_key = (int) $fd; - if (!isset($this->_fd[$fd_key])) { + if (! isset($this->_fd[$fd_key])) { if ($flag === self::EV_READ) { $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ); $fd_type = SWOOLE_EVENT_READ; @@ -115,22 +107,14 @@ function ($timer_id = null) use ($func, $args, $mapId) { $res = true; if ($flag === self::EV_READ) { if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) { - $res = Event::set( - $fd, - $func, - null, - SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE - ); + $res = Event::set($fd, $func, null, + SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); $this->_fd[$fd_key] |= SWOOLE_EVENT_READ; } } else { if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) { - $res = Event::set( - $fd, - null, - $func, - SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE - ); + $res = Event::set($fd, null, $func, + SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE; } } @@ -153,7 +137,7 @@ public function del($fd, $flag) case self::EV_TIMER: case self::EV_TIMER_ONCE: // already remove in EV_TIMER_ONCE callback. - if (!\array_key_exists($fd, $this->_timer)) { + if (! \array_key_exists($fd, $this->_timer)) { return true; } $res = Timer::clear($fd); @@ -171,9 +155,9 @@ public function del($fd, $flag) if (isset($this->_fd[$fd_key])) { $fd_val = $this->_fd[$fd_key]; if ($flag === self::EV_READ) { - $flag_remove = ~SWOOLE_EVENT_READ; + $flag_remove = ~ SWOOLE_EVENT_READ; } else { - $flag_remove = ~SWOOLE_EVENT_WRITE; + $flag_remove = ~ SWOOLE_EVENT_WRITE; } $fd_val &= $flag_remove; if (0 === $fd_val) { diff --git a/src/Events/Uv.php b/src/Events/Uv.php index c595347..800eec6 100644 --- a/src/Events/Uv.php +++ b/src/Events/Uv.php @@ -1,5 +1,4 @@ _eventLoop = \uv_default_loop(); return; - } + } $this->_eventLoop = $loop; } @@ -88,9 +88,10 @@ public function __construct(\UVLoop $loop = null) */ public function add($fd, $flag, $func, $args = null) { - switch ($flag) { + switch ($flag) + { case self::EV_SIGNAL: - $signalCallback = function ($watcher, $socket) use ($func, $fd) { + $signalCallback = function($watcher, $socket)use($func, $fd){ try { \call_user_func($func, $fd); } catch (\Exception $e) { @@ -99,7 +100,7 @@ public function add($fd, $flag, $func, $args = null) Server::stopAll(250, $e); } }; - $signalWatcher = \uv_signal_init(); + $signalWatcher = \uv_signal_init(); \uv_signal_start($signalWatcher, $signalCallback, $fd); $this->_eventSignal[$fd] = $signalWatcher; return true; @@ -107,8 +108,8 @@ public function add($fd, $flag, $func, $args = null) case self::EV_TIMER_ONCE: $repeat = $flag === self::EV_TIMER_ONCE ? 0 : (int)($fd * 1000); $param = array($func, (array)$args, $flag, $fd, self::$_timerId); - $timerWatcher = \uv_timer_init(); - \uv_timer_start($timerWatcher, 1, $repeat, function ($watcher) use ($param) { + $timerWatcher = \uv_timer_init(); + \uv_timer_start($timerWatcher, 1, $repeat, function($watcher)use($param){ call_user_func_array([$this, 'timerCallback'], [$param]); }); $this->_eventTimer[self::$_timerId] = $timerWatcher; @@ -116,7 +117,7 @@ public function add($fd, $flag, $func, $args = null) case self::EV_READ: case self::EV_WRITE: $fd_key = (int)$fd; - $ioCallback = function ($watcher, $status, $events, $fd) use ($func) { + $ioCallback = function($watcher, $status, $events, $fd)use($func){ try { \call_user_func($func, $fd); } catch (\Exception $e) { @@ -125,7 +126,7 @@ public function add($fd, $flag, $func, $args = null) Server::stopAll(250, $e); } }; - $ioWatcher = \uv_poll_init($this->_eventLoop, $fd); + $ioWatcher = \uv_poll_init($this->_eventLoop, $fd); $real_flag = $flag === self::EV_READ ? \Uv::READABLE : \Uv::WRITABLE; \uv_poll_start($ioWatcher, $real_flag, $ioCallback); $this->_allEvents[$fd_key][$flag] = $ioWatcher; @@ -145,7 +146,8 @@ public function add($fd, $flag, $func, $args = null) */ public function del($fd, $flag) { - switch ($flag) { + switch ($flag) + { case self::EV_READ: case self::EV_WRITE: $fd_key = (int)$fd; @@ -188,11 +190,12 @@ public function del($fd, $flag) */ public function timerCallback($input) { - if (!is_array($input)) return; + if(!is_array($input)) return; $timer_id = $input[4]; - if ($input[2] === self::EV_TIMER_ONCE) { + if ($input[2] === self::EV_TIMER_ONCE) + { $watcher = $this->_eventTimer[$timer_id]; \uv_is_active($watcher) && \uv_timer_stop($watcher); unset($this->_eventTimer[$timer_id]); @@ -214,9 +217,10 @@ public function timerCallback($input) */ public function clearAllTimer() { - if (!is_array($this->_eventTimer)) return; + if(!is_array($this->_eventTimer)) return; - foreach ($this->_eventTimer as $watcher) { + foreach($this->_eventTimer as $watcher) + { \uv_is_active($watcher) && \uv_timer_stop($watcher); } diff --git a/src/Protocols/FastCGI/Request.php b/src/Protocols/FastCGI/Request.php index bf9d582..35e7c31 100644 --- a/src/Protocols/FastCGI/Request.php +++ b/src/Protocols/FastCGI/Request.php @@ -1,5 +1,4 @@ -setScript($script); - $this->setContent($content); + public function __construct($script = '', $content = '') + { + $this->setScript($script); + $this->setContent($content); (self::$_idCounter >= (1 << 16)) && self::$_idCounter = 0; $this->requestId = self::$_idCounter++; - } + } /** * @brief get request id * * @return int */ - public function getRequestId() + public function getRequestId() { return $this->requestId; } @@ -207,9 +205,10 @@ public function getRequestId() * * @return object */ - public function setRole($role = Fcgi::FCGI_RESPONDER) + public function setRole($role = Fcgi::FCGI_RESPONDER) { - if (!is_int($role) || !in_array($role, static::ALLOWED_ROLES)) { + if(!is_int($role) || !in_array($role, static::ALLOWED_ROLES)) + { $role = Fcgi::FCGI_RESPONDER; } @@ -223,7 +222,7 @@ public function setRole($role = Fcgi::FCGI_RESPONDER) * * @return int */ - public function getRole() + public function getRole() { return $this->role; } @@ -235,7 +234,7 @@ public function getRole() * * @return object */ - public function setKeepAlive($status = true) + public function setKeepAlive($status = true) { $this->keepAlive = !is_bool($status) ? true : $status; @@ -247,7 +246,7 @@ public function setKeepAlive($status = true) * * @return boolean */ - public function getKeepAlive() + public function getKeepAlive() { return $this->keepAlive; } @@ -257,10 +256,10 @@ public function getKeepAlive() * * @return string */ - public function getServerSoftware() + public function getServerSoftware() { return $this->serverSoftware; - } + } /** * @brief set server software @@ -269,24 +268,25 @@ public function getServerSoftware() * * @return object */ - public function setServerSoftware($software) - { - if (!empty($software) && \is_string($software)) { + public function setServerSoftware($software) + { + if(!empty($software) && \is_string($software)) + { $this->serverSoftware = $software; } return $this; - } + } /** * @brief get server name * * @return string */ - public function getServerName() + public function getServerName() { return $this->serverName; - } + } /** * @brief set server name @@ -295,24 +295,25 @@ public function getServerName() * * @return object */ - public function setServerName($name) - { - if (!empty($name) && \is_string($name)) { + public function setServerName($name) + { + if(!empty($name) && \is_string($name)) + { $this->serverName = $name; } return $this; - } + } /** * @brief get content type * * @return string */ - public function getContentType() + public function getContentType() { return $this->contentType; - } + } /** * @brief set content type @@ -321,26 +322,27 @@ public function getContentType() * * @return object */ - public function setContentType($type) - { - if (!\is_string($type) || !in_array($type, static::ALLOWED_CONTENT_TYPES)) { + public function setContentType($type) + { + if(!\is_string($type) || !in_array($type, static::ALLOWED_CONTENT_TYPES)) + { $type = static::MIME_URL_ENCODED_FORM_DATA; } - $this->contentType = $type; + $this->contentType = $type; return $this; - } + } /** * @brief get content * * @return string */ - public function getContent() + public function getContent() { return $this->content; - } + } /** * @brief set content @@ -349,9 +351,10 @@ public function getContent() * * @return object */ - public function setContent($content) - { - if (\is_string($content) || \is_array($content)) { + public function setContent($content) + { + if(\is_string($content) || \is_array($content)) + { $this->content = !\is_string($content) ? http_build_query($content) : $content; $this->contentLength = \strlen($this->content); } @@ -367,17 +370,17 @@ public function setContent($content) public function getContentLength() { return $this->contentLength; - } + } /** * @brief get gateway interface * * @return string */ - public function getGatewayInterface() + public function getGatewayInterface() { return $this->gatewayInterface; - } + } /** * @brief set FastCGI script @@ -386,24 +389,25 @@ public function getGatewayInterface() * * @return object */ - public function setScript($filename) - { - if (!empty($filename) && \is_string($filename)) { + public function setScript($filename) + { + if(!empty($filename) && \is_string($filename)) + { $this->script = $filename; } return $this; - } + } /** * @brief get FastCGI script * * @return string */ - public function getScript() + public function getScript() { return $this->script; - } + } /** * @brief set custom params @@ -412,17 +416,18 @@ public function getScript() * * @return object */ - public function setCustomParams($pair) - { - if (!\is_array($pair)) return $this; + public function setCustomParams($pair) + { + if(!\is_array($pair)) return $this; - foreach ($pair as $k => $v) { - if (!\is_string($v)) continue; + foreach($pair as $k => $v) + { + if(!\is_string($v)) continue; $this->customParams[$k] = $v; } return $this; - } + } /** * @brief append custom params @@ -431,26 +436,27 @@ public function setCustomParams($pair) * * @return object */ - public function appendCustomParams($pair) - { - if (\is_array($pair)) { + public function appendCustomParams($pair) + { + if(\is_array($pair)) + { $this->customParams = \array_merge($this->customParams, $pair); } return $this; - } + } /** * @brief reset custom params * * @return object */ - public function resetCustomParams() + public function resetCustomParams() { $this->customParams = []; return $this; - } + } /** * @brief set query string @@ -461,7 +467,8 @@ public function resetCustomParams() */ public function setQueryString($data = '') { - if (\is_string($data) || \is_array($data)) { + if(\is_string($data) || \is_array($data)) + { $this->queryString = !\is_string($data) ? http_build_query($data) : $data; } @@ -486,7 +493,7 @@ public function getQueryString() public function getCustomParams() { return $this->customParams; - } + } /** * @brief get all params @@ -496,7 +503,7 @@ public function getCustomParams() public function getParams() { return \array_merge($this->customParams, $this->getDefaultParams()); - } + } /** * @brief get default params @@ -527,7 +534,8 @@ public function getDefaultParams() */ public function setRequestMethod($method = 'GET') { - if (!\is_string($method) || !in_array(strtoupper($method), static::ALLOWED_REQUEST_METHODS)) { + if(!\is_string($method) || !in_array(strtoupper($method), static::ALLOWED_REQUEST_METHODS)) + { $method = 'GET'; } @@ -541,7 +549,7 @@ public function setRequestMethod($method = 'GET') * * @return string */ - public function getRequestMethod() + public function getRequestMethod() { return $this->requestMethod; } @@ -551,10 +559,10 @@ public function getRequestMethod() * * @return string */ - public function getRequestUri() + public function getRequestUri() { return $this->requestUri; - } + } /** * @brief set request uri @@ -563,12 +571,14 @@ public function getRequestUri() * * @return object */ - public function setRequestUri($uri) - { - if (\is_string($uri)) { + public function setRequestUri($uri) + { + if(\is_string($uri)) + { $this->requestUri = $uri; } return $this; - } + } + } diff --git a/src/Protocols/FastCGI/Response.php b/src/Protocols/FastCGI/Response.php index d19dcf1..31794ff 100644 --- a/src/Protocols/FastCGI/Response.php +++ b/src/Protocols/FastCGI/Response.php @@ -1,5 +1,4 @@ _stdout = $stdout; } @@ -126,7 +124,8 @@ public function getStdout() */ public function setStderr($stderr = '') { - if (\is_string($stderr)) { + if(\is_string($stderr)) + { $this->_stderr = $stderr; } @@ -185,7 +184,8 @@ public function formatOutput() $body = ''; $crlf_pos = \strpos($this->getStdout(), "\r\n\r\n"); - if (false !== $crlf_pos) { + if(false !== $crlf_pos) + { $status = static::STATUS_OK; $head = \substr($this->getStdout(), 0, $crlf_pos); $body = \substr($this->getStdout(), $crlf_pos + 4); @@ -193,21 +193,25 @@ public function formatOutput() $this->_body = $body; $header_lines = \explode(PHP_EOL, $head); - foreach ($header_lines as $line) { - if (preg_match('/([\w-]+):\s*(.*)$/', $line, $matches)) { + foreach($header_lines as $line) + { + if(preg_match('/([\w-]+):\s*(.*)$/', $line, $matches)) + { $name = \trim($matches[1]); $value = \trim($matches[2]); - if ('status' === strtolower($name)) { - $pos = strpos($value, ' '); + if('status' === strtolower($name)) + { + $pos = strpos($value, ' ') ; $status = false !== $pos ? \substr($value, 0, $pos) : static::STATUS_OK; continue; } - if (!array_key_exists($name, $header)) { + if(!array_key_exists($name, $header)) + { $header[$name] = $value; continue; - } + } !\is_array($header[$name]) && $header[$name] = [$header[$name]]; $header[$name][] = $value; @@ -226,3 +230,4 @@ public function formatOutput() return $output; } } + diff --git a/src/Protocols/Fcgi.php b/src/Protocols/Fcgi.php index a723230..0f1ef3a 100644 --- a/src/Protocols/Fcgi.php +++ b/src/Protocols/Fcgi.php @@ -1,5 +1,4 @@ packetLength)) $connection->packetLength = 0; + if(!isset($connection->packetLength)) $connection->packetLength = 0; $data = \unpack("Cversion/Ctype/nrequestId/ncontentLength/CpaddingLength/Creserved", $buffer); - if (false === $data) return 0; + if(false === $data) return 0; $chunk_len = static::FCGI_HEADER_LEN + $data['contentLength'] + $data['paddingLength']; - if ($recv_len < $chunk_len) return 0; + if($recv_len < $chunk_len) return 0; - if (static::FCGI_END_REQUEST != $data['type']) { + if(static::FCGI_END_REQUEST != $data['type']) + { $connection->packetLength += $chunk_len; $next_chunk_len = static::input(\substr($buffer, $chunk_len), $connection); - if (0 == $next_chunk_len) { - // Важно!! Не забываем сбросить на нулевой байт!! + if(0 == $next_chunk_len) + { + //important!! don't forget to reset to zero byte!! $connection->packetLength = 0; return 0; } - } else { + } + else + { $connection->packetLength += $chunk_len; } - // Проверка длины пакета превышает длину пакета MAX или нет - if ($connection->packetLength > $connection->maxPackageSize) { - $data = "Исключение: ошибка пакета. package_length = {$connection->packetLength} "; - $data .= "превышает лимит {$connection->maxPackageSize}" . PHP_EOL; - Server::safeEcho($data); + //check package length exceeds the max package length or not + if($connection->packetLength > $connection->maxPackageSize) + { + $msg = "Exception: recv error package. package_length = {$connection->packetLength} "; + $msg .= "exceeds the limit {$connection->maxPackageSize}" . PHP_EOL; + Server::safeEcho($msg); $connection->close(); return 0; } @@ -259,21 +269,28 @@ public static function input($buffer, TcpConnection $connection) } /** - * @param string $buffer - * @param TcpConnection $connection - * @return array + * @brief decode package + * + * @param string $buffer + * @param TcpConnection $connection + * + * @return array */ public static function decode($buffer, TcpConnection $connection) { $offset = 0; $stdout = $stderr = ''; - do { + do + { $header_buffer = \substr($buffer, $offset, static::FCGI_HEADER_LEN); $data = \unpack("Cversion/Ctype/nrequestId/ncontentLength/CpaddingLength/Creserved", $header_buffer); - if (false === $data) { - $stderr = "Не удалось распаковывать данные заголовка из двоичного буфера"; + //we are not going to throw new \Exception("Failed to unpack header data from the binary buffer."); + //but just break out of the loop to avoid bring much unnecessary TCP connections with TIME_WAIT status + if(false === $data) + { + $stderr = "Failed to unpack header data from the binary buffer"; Server::safeEcho($stderr); $connection->close(); break; @@ -283,55 +300,58 @@ public static function decode($buffer, TcpConnection $connection) $body_buffer = \substr($buffer, $offset + static::FCGI_HEADER_LEN, $chunk_len - static::FCGI_HEADER_LEN); - switch ($data['type']) { + switch($data['type']) + { case static::FCGI_STDOUT: $payload = \unpack("a{$data['contentLength']}contentData/a{$data['paddingLength']}paddingData", $body_buffer); - $stdout .= $payload['contentData']; + $stdout .= $payload['contentData']; break; case static::FCGI_STDERR: $payload = \unpack("a{$data['contentLength']}contentData/a{$data['paddingLength']}paddingData", $body_buffer); - $stderr .= $payload['contentData']; + $stderr .= $payload['contentData']; break; case static::FCGI_END_REQUEST: $payload = \unpack("NappStatus/CprotocolStatus/a3reserved", $body_buffer); $result = static::checkProtocolStatus($payload['protocolStatus']); - if (0 <> $result['status']) { - $stderr = $result['data']; + if(0 <> $result['code']) + { + $stderr = $result['msg']; Server::safeEcho($stderr); $connection->close(); } break; default: - //Пока не поддерживается + //not support yet $payload = ''; break; } $offset += $chunk_len; - } while ($offset < $connection->packetLength); + }while($offset < $connection->packetLength); - // Важно!! Не забываем сбросить на нулевой байт!! + //important!! don't forget to reset to zero byte!! $connection->packetLength = 0; - // Сбор ответа + //build response $response = new Response(); $output = $response->setRequestId($data['requestId'] ?? -1) ->setStdout($stdout) ->setStderr($stderr) ->formatOutput(); - // onResponse - if (!empty($connection->onResponse) && is_callable($connection->onResponse)) { + //trigger user callback as onResponse + if(!empty($connection->onResponse) && is_callable($connection->onResponse)) + { try { \call_user_func($connection->onResponse, $connection, $response); } catch (\Exception $e) { - $data = "Исключение: onResponse: " . $e->getMessage(); - Server::safeEcho($data); + $msg = "Exception: onResponse: " . $e->getMessage(); + Server::safeEcho($msg); $connection->close(); } catch (\Error $e) { - $data = "Исключение: onResponse: " . $e->getMessage(); - Server::safeEcho($data); + $msg = "Exception: onResponse: " . $e->getMessage(); + Server::safeEcho($msg); $connection->close(); } } @@ -349,7 +369,7 @@ public static function decode($buffer, TcpConnection $connection) */ public static function encode(Request $request, TcpConnection $connection) { - if (!$request instanceof Request) return ''; + if(!$request instanceof Request) return ''; static::$_request = $request; @@ -363,10 +383,11 @@ public static function encode(Request $request, TcpConnection $connection) $connection->maxSendBufferSize = TcpConnection::$defaultMaxSendBufferSize * 10; $packet_len = \strlen($packet); - if ($packet_len > $connection->maxSendBufferSize) { - $data = "Исключение: ошибка отправки пакета. package_length = {$packet_len} "; - $data .= "превышает лимит {$connection->maxSendBufferSize}" . PHP_EOL; - Server::safeEcho($data); + if($packet_len > $connection->maxSendBufferSize) + { + $msg = "Exception: send error package. package_length = {$packet_len} "; + $msg .= "exceeds the limit {$connection->maxSendBufferSize}" . PHP_EOL; + Server::safeEcho($msg); $connection->close(); return ''; } @@ -375,27 +396,32 @@ public static function encode(Request $request, TcpConnection $connection) } /** - * @param string $type - * @return string + * @brief pack payload + * + * @param string $type + * + * @return string */ static private function packPayload($type = '') { $payload = ''; - switch ($type) { + switch($type) + { case static::FCGI_BEGIN_REQUEST: $payload = \pack( "nCa5", static::$_request->getRole(), static::$_request->getKeepAlive(), static::FCGI_RESERVED - ); + ); break; case static::FCGI_PARAMS: case static::FCGI_PARAMS_END: $payload = ''; $params = (static::FCGI_PARAMS == $type) ? static::$_request->getParams() : []; - foreach ($params as $name => $value) { + foreach($params as $name => $value) + { $name_len = \strlen($name); $value_len = \strlen($value); $format = [ @@ -404,7 +430,7 @@ static private function packPayload($type = '') "a{$name_len}", "a{$value_len}", ]; - $format = implode('', $format); + $format = implode ('', $format); $payload .= \pack( $format, $name_len > 127 ? ($name_len | 0x80000000) : $name_len, @@ -434,8 +460,11 @@ static private function packPayload($type = '') } /** - * @param string $type - * @return string + * @brief create request packet + * + * @param string $type + * + * @return string */ static public function createPacket($type = '') { @@ -444,12 +473,13 @@ static public function createPacket($type = '') $payload = static::packPayload($type); $total_len = \strlen($payload); - // Не забываем сбросить псевдо-тип записи на нормальный + //don't forget to reset pseudo record type to normal $type == static::FCGI_PARAMS_END && $type = static::FCGI_PARAMS; $type == static::FCGI_STDIN_END && $type = static::FCGI_STDIN; - // Может быть, нужно разделить полезную нагрузку на множество частей - do { + //maybe need to split payload into many chunks + do + { $chunk = \substr($payload, $offset, static::FCGI_MAX_PAYLOAD_LEN); $chunk_len = \strlen($chunk); $remainder = \abs($chunk_len % 8); @@ -460,7 +490,7 @@ static public function createPacket($type = '') static::FCGI_VERSION_1, $type, static::$_request->getRequestId(), - $chunk_len, + $chunk_len, $padding_len, static::FCGI_RESERVED ); @@ -468,38 +498,43 @@ static public function createPacket($type = '') $padding = \pack("a{$padding_len}", static::FCGI_PADDING); $packet .= $header . $chunk . $padding; $offset += $chunk_len; - } while ($offset < $total_len); + }while($offset < $total_len); return $packet; } /** - * @param int $status - * @return array + * @brief check the protocol status from FCGI_END_REQUEST body + * + * @param int $status + * + * @return array */ static public function checkProtocolStatus($status = 0) { - switch ($status) { + switch($status) + { case static::FCGI_REQUEST_COMPLETE: - $data = 'Принято: Запрос заполнен'; + $msg = 'Accepted: request completed ok'; break; case static::FCGI_CANT_MPX_CONN: - $data = 'Отклонено: Сервер FastCGI не поддерживает одновременную обработку'; + $msg = 'Rejected: FastCGI server does not support concurrent processing'; break; case static::FCGI_OVERLOADED: - $data = 'Отклонено: Серверу FastCGI не хватает ресурсов'; + $msg = 'Rejected: FastCGI server run out of resources or reached the limit'; break; case static::FCGI_UNKNOWN_ROLE: - $data = 'Отклонено: Сервер FastCGI не поддерживает указанную роль'; + $msg = 'Rejected: FastCGI server not support the specified role'; break; default: - $data = 'Отклонено: Сервер FastCGI не знает, что случилось'; + $msg = 'Rejected: FastCGI server does not know what happened'; break; } return [ - 'status' => $status, - 'data' => $data, + 'code' => $status, + 'msg' => $msg, ]; } + } diff --git a/src/Protocols/Frame.php b/src/Protocols/Frame.php index ebbac77..d3dda91 100644 --- a/src/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -1,5 +1,4 @@ = 16384) { - $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); + $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } return 0; @@ -140,7 +139,7 @@ public static function input($recv_buffer, TcpConnection $connection) } } if ($length > $connection->maxPackageSize) { - $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); + $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } return $length; diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index f2484be..cd2679a 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -1,5 +1,4 @@ _buffer)) . "\r\n$this->_buffer\r\n"; + return \dechex(\strlen($this->_buffer))."\r\n$this->_buffer\r\n"; } -} +} \ No newline at end of file diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 85e1b68..de63f13 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -1,5 +1,4 @@ _buffer; + $post_encode_string = ''; + $files_encode_string = ''; + $files = []; $boday_position = strpos($buffer, "\r\n\r\n") + 4; $offset = $boday_position + strlen($http_post_boundary) + 2; $max_count = static::$maxFileUploads; while ($max_count-- > 0 && $offset) { - $offset = $this->parseUploadFile($http_post_boundary, $offset); + $offset = $this->parseUploadFile($http_post_boundary, $offset, $post_encode_string, $files_encode_string, $files); + } + if ($post_encode_string) { + parse_str($post_encode_string, $this->_data['post']); + } + + if ($files_encode_string) { + parse_str($files_encode_string, $this->_data['files']); + \array_walk_recursive($this->_data['files'], function (&$value) use ($files) { + $value = $files[$value]; + }); } } @@ -504,7 +515,7 @@ protected function parseUploadFiles($http_post_boundary) * @param $section_start_offset * @return int */ - protected function parseUploadFile($boundary, $section_start_offset) + protected function parseUploadFile($boundary, $section_start_offset, &$post_encode_string, &$files_encode_str, &$files) { $file = []; $boundary = "\r\n$boundary"; @@ -524,7 +535,7 @@ protected function parseUploadFile($boundary, $section_start_offset) if (!\strpos($content_line, ': ')) { return 0; } - [$key, $value] = \explode(': ', $content_line); + list($key, $value) = \explode(': ', $content_line); switch (strtolower($key)) { case "content-disposition": // Is file data. @@ -558,12 +569,7 @@ protected function parseUploadFile($boundary, $section_start_offset) // Parse $_POST. if (\preg_match('/name="(.*?)"$/', $value, $match)) { $k = $match[1]; - $post_str = \urlencode($k) . "=" . \urlencode($boundary_value); - $post = []; - parse_str($post_str, $post); - if ($post) { - $this->_data['post'] = \array_merge_recursive($this->_data['post'], $post); - } + $post_encode_string .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&'; } return $section_end_offset + \strlen($boundary) + 2; } @@ -576,13 +582,8 @@ protected function parseUploadFile($boundary, $section_start_offset) if ($upload_key === false) { return 0; } - $str = \urlencode($upload_key) . "=1"; - $result = []; - \parse_str($str, $result); - \array_walk_recursive($result, function (&$value) use ($file) { - $value = $file; - }); - $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result); + $files_encode_str .= \urlencode($upload_key) . '=' . \count($files) . '&'; + $files[] = $file; return $section_end_offset + \strlen($boundary) + 2; } @@ -659,7 +660,7 @@ public function __destruct() { if (isset($this->_data['files'])) { \clearstatcache(); - \array_walk_recursive($this->_data['files'], function ($value, $key) { + \array_walk_recursive($this->_data['files'], function($value, $key){ if ($key === 'tmp_name') { if (\is_file($value)) { \unlink($value); diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 57a6a03..5ed039e 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -1,5 +1,4 @@ _header[$name] = $value; return $this; } @@ -181,8 +177,7 @@ public function header($name, $value) * @param string $value * @return Response */ - public function withHeader($name, $value) - { + public function withHeader($name, $value) { return $this->header($name, $value); } @@ -192,20 +187,18 @@ public function withHeader($name, $value) * @param array $headers * @return $this */ - public function withHeaders($headers) - { + public function withHeaders($headers) { $this->_header = \array_merge_recursive($this->_header, $headers); return $this; } - + /** * Remove header. * * @param string $name * @return $this */ - public function withoutHeader($name) - { + public function withoutHeader($name) { unset($this->_header[$name]); return $this; } @@ -216,8 +209,7 @@ public function withoutHeader($name) * @param string $name * @return null|array|string */ - public function getHeader($name) - { + public function getHeader($name) { if (!isset($this->_header[$name])) { return null; } @@ -229,8 +221,7 @@ public function getHeader($name) * * @return array */ - public function getHeaders() - { + public function getHeaders() { return $this->_header; } @@ -241,8 +232,7 @@ public function getHeaders() * @param string|null $reason_phrase * @return $this */ - public function withStatus($code, $reason_phrase = null) - { + public function withStatus($code, $reason_phrase = null) { $this->_status = $code; $this->_reason = $reason_phrase; return $this; @@ -253,8 +243,7 @@ public function withStatus($code, $reason_phrase = null) * * @return int */ - public function getStatusCode() - { + public function getStatusCode() { return $this->_status; } @@ -263,8 +252,7 @@ public function getStatusCode() * * @return string */ - public function getReasonPhrase() - { + public function getReasonPhrase() { return $this->_reason; } @@ -274,8 +262,7 @@ public function getReasonPhrase() * @param int $version * @return $this */ - public function withProtocolVersion($version) - { + public function withProtocolVersion($version) { $this->_version = $version; return $this; } @@ -286,8 +273,7 @@ public function withProtocolVersion($version) * @param string $body * @return $this */ - public function withBody($body) - { + public function withBody($body) { $this->_body = $body; return $this; } @@ -297,8 +283,7 @@ public function withBody($body) * * @return string */ - public function rawBody() - { + public function rawBody() { return $this->_body; } @@ -310,8 +295,7 @@ public function rawBody() * @param int $length * @return $this */ - public function withFile($file, $offset = 0, $length = 0) - { + public function withFile($file, $offset = 0, $length = 0) { if (!\is_file($file)) { return $this->withStatus(404)->withBody('

404 Not Found

'); } @@ -390,7 +374,7 @@ protected function createHeadForFile($file_info) if (!isset($headers['Last-Modified'])) { if ($mtime = \filemtime($file)) { - $head .= 'Last-Modified: ' . \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; + $head .= 'Last-Modified: '. \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; } } @@ -442,7 +426,7 @@ public function __toString() if (!isset($headers['Transfer-Encoding'])) { $head .= "Content-Length: $body_len\r\n\r\n"; } else { - return "$head\r\n" . dechex($body_len) . "\r\n{$this->_body}\r\n"; + return "$head\r\n".dechex($body_len)."\r\n{$this->_body}\r\n"; } // The whole http package diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index e80aa86..f049316 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -1,5 +1,4 @@ $maxlifetime) { + if(\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) { \unlink($file); } } @@ -160,9 +155,8 @@ public function gc($maxlifetime) * @param string $session_id * @return string */ - protected static function sessionFile($session_id) - { - return static::$_sessionSavePath . static::$_sessionFilePrefix . $session_id; + protected static function sessionFile($session_id) { + return static::$_sessionSavePath.static::$_sessionFilePrefix.$session_id; } /** @@ -171,10 +165,9 @@ protected static function sessionFile($session_id) * @param string $path * @return string */ - public static function sessionSavePath($path) - { + public static function sessionSavePath($path) { if ($path) { - if ($path[\strlen($path) - 1] !== DIRECTORY_SEPARATOR) { + if ($path[\strlen($path)-1] !== DIRECTORY_SEPARATOR) { $path .= DIRECTORY_SEPARATOR; } static::$_sessionSavePath = $path; @@ -186,4 +179,4 @@ public static function sessionSavePath($path) } } -FileSessionHandler::init(); +FileSessionHandler::init(); \ No newline at end of file diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index c0f6b49..9e55329 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -1,5 +1,4 @@ _redis->get($session_id); } + } diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index 81db50a..2a7fd06 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -1,5 +1,4 @@ onWebSocketClose) || isset($connection->server->onWebSocketClose)) { try { - \call_user_func(isset($connection->onWebSocketClose) ? $connection->onWebSocketClose : $connection->server->onWebSocketClose, $connection); + \call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->server->onWebSocketClose, $connection); } catch (\Exception $e) { Server::stopAll(250, $e); } catch (\Error $e) { @@ -105,14 +102,14 @@ public static function input($buffer, ConnectionInterface $connection) $connection->close("\x88\x02\x03\xe8", true); } return 0; - // Ping package. + // Ping package. case 0x9: break; - // Pong package. + // Pong package. case 0xa: break; - // Wrong opcode. - default: + // Wrong opcode. + default : Server::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n"); $connection->close(); return 0; @@ -125,7 +122,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($head_len > $recv_len) { return 0; } - $pack = \unpack('nn/ntotal_len', $buffer); + $pack = \unpack('nn/ntotal_len', $buffer); $data_len = $pack['total_len']; } else { if ($data_len === 127) { @@ -134,7 +131,7 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } $arr = \unpack('n/N2c', $buffer); - $data_len = $arr['c1'] * 4294967296 + $arr['c2']; + $data_len = $arr['c1']*4294967296 + $arr['c2']; } } $current_frame_length = $head_len + $data_len; @@ -155,7 +152,7 @@ public static function input($buffer, ConnectionInterface $connection) $connection->websocketType = "\x8a"; if (isset($connection->onWebSocketPing) || isset($connection->server->onWebSocketPing)) { try { - \call_user_func(isset($connection->onWebSocketPing) ? $connection->onWebSocketPing : $connection->server->onWebSocketPing, $connection, $ping_data); + \call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->server->onWebSocketPing, $connection, $ping_data); } catch (\Exception $e) { Server::stopAll(250, $e); } catch (\Error $e) { @@ -179,7 +176,7 @@ public static function input($buffer, ConnectionInterface $connection) // Try to emit onWebSocketPong callback. if (isset($connection->onWebSocketPong) || isset($connection->server->onWebSocketPong)) { try { - \call_user_func(isset($connection->onWebSocketPong) ? $connection->onWebSocketPong : $connection->server->onWebSocketPong, $connection, $pong_data); + \call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->server->onWebSocketPong, $connection, $pong_data); } catch (\Exception $e) { Server::stopAll(250, $e); } catch (\Error $e) { @@ -347,20 +344,18 @@ public static function dealHandshake($buffer, TcpConnection $connection) if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->close( - "HTTP/1.1 200 WebSocket\r\nServer: WebCore Server/" . Server::VERSION . "\r\n\r\n

WebSocket


WebCore Server/" . Server::VERSION . "
", - true - ); + $connection->close("HTTP/1.1 200 WebSocket\r\nServer: WebCore Server/".Server::VERSION."\r\n\r\n

WebSocket


WebCore Server/".Server::VERSION."
", + true); return 0; } // Calculation websocket key. $new_key = \base64_encode(\sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n" - . "Upgrade: websocket\r\n" - . "Sec-WebSocket-Version: 13\r\n" - . "Connection: Upgrade\r\n" - . "Sec-WebSocket-Accept: " . $new_key . "\r\n"; + ."Upgrade: websocket\r\n" + ."Sec-WebSocket-Version: 13\r\n" + ."Connection: Upgrade\r\n" + ."Sec-WebSocket-Accept: " . $new_key . "\r\n"; // Websocket data buffer. $connection->websocketDataBuffer = ''; @@ -379,7 +374,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) $has_server_header = false; if (isset($connection->headers)) { - if (\is_array($connection->headers)) { + if (\is_array($connection->headers)) { foreach ($connection->headers as $header) { if (\stripos($header, 'Server:') === 0) { $has_server_header = true; @@ -394,7 +389,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) } } if (!$has_server_header) { - $handshake_message .= "Server: WebCore Server/" . Server::VERSION . "\r\n"; + $handshake_message .= "Server: WebCore Server/".Server::VERSION."\r\n"; } $handshake_message .= "\r\n"; // Send handshake response. @@ -403,7 +398,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) $connection->websocketHandshake = true; // Try to emit onWebSocketConnect callback. - $on_websocket_connect = isset($connection->onWebSocketConnect) ? $connection->onWebSocketConnect : (isset($connection->server->onWebSocketConnect) ? $connection->server->onWebSocketConnect : false); + $on_websocket_connect = isset($connection->onWebSocketConnect) ? $connection->onWebSocketConnect : + (isset($connection->server->onWebSocketConnect) ? $connection->server->onWebSocketConnect : false); if ($on_websocket_connect) { static::parseHttpHeader($buffer); try { @@ -413,8 +409,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) } catch (\Error $e) { Server::stopAll(250, $e); } - if (!empty($_SESSION) && \class_exists('\localzet\LongCore\Lib\Context')) { - $connection->session = \localzet\LongCore\Lib\Context::sessionEncode($_SESSION); + if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) { + $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); } $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); } @@ -436,10 +432,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } // Bad websocket handshake request. - $connection->close( - "HTTP/1.1 200 WebSocket\r\nServer: WebCore Server/" . Server::VERSION . "\r\n\r\n

WebSocket


WebCore Server/" . Server::VERSION . "
", - true - ); + $connection->close("HTTP/1.1 200 WebSocket\r\nServer: WebCore Server/".Server::VERSION."\r\n\r\n

WebSocket


WebCore Server/".Server::VERSION."
", + true); return 0; } @@ -452,17 +446,15 @@ public static function dealHandshake($buffer, TcpConnection $connection) protected static function parseHttpHeader($buffer) { // Parse headers. - list($http_header,) = \explode("\r\n\r\n", $buffer, 2); + list($http_header, ) = \explode("\r\n\r\n", $buffer, 2); $header_data = \explode("\r\n", $http_header); if ($_SERVER) { $_SERVER = array(); } - list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode( - ' ', - $header_data[0] - ); + list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ', + $header_data[0]); unset($header_data[0]); foreach ($header_data as $content) { @@ -475,7 +467,7 @@ protected static function parseHttpHeader($buffer) $value = \trim($value); $_SERVER['HTTP_' . $key] = $value; switch ($key) { - // HTTP_HOST + // HTTP_HOST case 'HOST': $tmp = \explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; @@ -483,7 +475,7 @@ protected static function parseHttpHeader($buffer) $_SERVER['SERVER_PORT'] = $tmp[1]; } break; - // cookie + // cookie case 'COOKIE': \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index f175003..832f094 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -1,5 +1,4 @@ onWebSocketClose)) { @@ -107,19 +105,18 @@ public static function input($buffer, ConnectionInterface $connection) $connection->close(); } return 0; - // Ping package. + // Ping package. case 0x9: break; - // Pong package. + // Pong package. case 0xa: break; - // Wrong opcode. - default: + // Wrong opcode. + default : Server::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n"); $connection->close(); return 0; } - // Calculate packet length. if ($data_len === 126) { if (\strlen($buffer) < 4) { @@ -132,7 +129,7 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } $arr = \unpack('n/N2c', $buffer); - $current_frame_length = $arr['c1'] * 4294967296 + $arr['c2'] + 10; + $current_frame_length = $arr['c1']*4294967296 + $arr['c2'] + 10; } else { $current_frame_length = $data_len + 2; } @@ -168,6 +165,7 @@ public static function input($buffer, ConnectionInterface $connection) } } return 0; + } else if ($opcode === 0xa) { if ($recv_len >= $current_frame_length) { $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); @@ -357,26 +355,27 @@ public static function sendHandshake(TcpConnection $connection) $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. $connection->websocketSecKey = \base64_encode(\md5(\mt_rand(), true)); - $user_header = isset($connection->headers) ? $connection->headers : (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); + $user_header = isset($connection->headers) ? $connection->headers : + (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); $user_header_str = ''; if (!empty($user_header)) { - if (\is_array($user_header)) { - foreach ($user_header as $k => $v) { + if (\is_array($user_header)){ + foreach($user_header as $k=>$v){ $user_header_str .= "$k: $v\r\n"; } } else { $user_header_str .= $user_header; } - $user_header_str = "\r\n" . \trim($user_header_str); + $user_header_str = "\r\n".\trim($user_header_str); } - $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n" . - (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : '') . - "Connection: Upgrade\r\n" . - "Upgrade: websocket\r\n" . - (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . - (isset($connection->WSClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->WSClientProtocol . "\r\n" : '') . - "Sec-WebSocket-Version: 13\r\n" . - "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; + $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". + (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : ''). + "Connection: Upgrade\r\n". + "Upgrade: websocket\r\n". + (isset($connection->websocketOrigin) ? "Origin: ".$connection->websocketOrigin."\r\n":''). + (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). + "Sec-WebSocket-Version: 13\r\n". + "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; @@ -429,7 +428,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) } // Headbeat. if (!empty($connection->websocketPingInterval)) { - $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use ($connection) { + $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){ if (false === $connection->send(\pack('H*', '898000000000'), true)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; @@ -449,13 +448,12 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } - public static function WSSetProtocol($connection, $params) - { - $connection->WSClientProtocol = $params[0]; + public static function WSSetProtocol($connection, $params) { + $connection->WSClientProtocol = $params[0]; } - public static function WSGetServerProtocol($connection) - { - return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null); + public static function WSGetServerProtocol($connection) { + return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null); } + } diff --git a/src/Server.php b/src/Server.php index 7f2b015..5f417e5 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1,5 +1,4 @@ [pid => pid, pid => pid, ..], ..] + * All server processes pid. + * The format is like this [worker_id=>[pid=>pid, pid=>pid, ..], ..] * * @var array */ protected static $_pidMap = array(); /** - * Все рабочие процессы, ожидающие перезапуска. - * В формате [pid => pid, pid => pid]. + * All server processes waiting for restart. + * The format is like this [pid=>pid, pid=>pid]. * * @var array */ protected static $_pidsToRestart = array(); /** - * Карта соотношений PID и ID рабочего процесса. - * В формате [server_id => [0 => $pid, 1 => $pid, ..], ..]. + * Mapping from PID to server process ID. + * The format is like this [worker_id=>[0=>$pid, 1=>$pid, ..], ..]. * * @var array */ protected static $_idMap = array(); /** - * Текущий статус. + * Current status. * * @var int */ protected static $_status = self::STATUS_STARTING; /** - * Максимальная длина имен воркеров. + * Maximum length of the server names. * * @var int */ - protected static $_maxServerNameLength = 12; + protected static $_maxWorkerNameLength = 12; /** - * Максимальная длина имен сокета. + * Maximum length of the socket names. * * @var int */ protected static $_maxSocketNameLength = 12; /** - * Максимальная длина имен процессов пользователя. + * Maximum length of the process user names. * * @var int */ protected static $_maxUserNameLength = 12; /** - * Максимальная длина имен протоколов. + * Maximum length of the Proto names. * * @var int */ protected static $_maxProtoNameLength = 4; /** - * Максимальная длина имен процессов. + * Maximum length of the Processes names. * * @var int */ protected static $_maxProcessesNameLength = 9; /** - * Максимальная длина имен статуса. + * Maximum length of the Status names. * * @var int */ protected static $_maxStatusNameLength = 1; /** - * Файл для хранения информации о состоянии текущего рабочего процесса. + * The file to store status info of current server process. * * @var string */ protected static $_statisticsFile = ''; /** - * Стартовый файл. + * Start file. * * @var string */ @@ -462,24 +458,24 @@ class Server protected static $_OS = \OS_TYPE_LINUX; /** - * Процессы для Windows. + * Processes for windows. * * @var array */ protected static $_processForWindows = array(); /** - * Информация о состоянии текущего рабочего процесса. + * Status info of current server process. * * @var array */ protected static $_globalStatistics = array( 'start_timestamp' => 0, - 'server_exit_info' => array() + 'worker_exit_info' => array() ); /** - * Доступные петли событий. + * Available event loops. * * @var array */ @@ -489,7 +485,7 @@ class Server ); /** - * Встроенные в PHP протоколы. + * PHP built-in protocols. * * @var array */ @@ -501,49 +497,49 @@ class Server ); /** - * Встроенные в PHP типы ошибок. + * PHP built-in error types. * * @var array */ protected static $_errorType = array( - \E_ERROR => 'E_ERROR', // 1 - \E_WARNING => 'E_WARNING', // 2 - \E_PARSE => 'E_PARSE', // 4 - \E_NOTICE => 'E_NOTICE', // 8 - \E_CORE_ERROR => 'E_CORE_ERROR', // 16 - \E_CORE_WARNING => 'E_CORE_WARNING', // 32 - \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 - \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 - \E_USER_ERROR => 'E_USER_ERROR', // 256 - \E_USER_WARNING => 'E_USER_WARNING', // 512 - \E_USER_NOTICE => 'E_USER_NOTICE', // 1024 - \E_STRICT => 'E_STRICT', // 2048 - \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 - \E_DEPRECATED => 'E_DEPRECATED', // 8192 - \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 + \E_ERROR => 'E_ERROR', // 1 + \E_WARNING => 'E_WARNING', // 2 + \E_PARSE => 'E_PARSE', // 4 + \E_NOTICE => 'E_NOTICE', // 8 + \E_CORE_ERROR => 'E_CORE_ERROR', // 16 + \E_CORE_WARNING => 'E_CORE_WARNING', // 32 + \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 + \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 + \E_USER_ERROR => 'E_USER_ERROR', // 256 + \E_USER_WARNING => 'E_USER_WARNING', // 512 + \E_USER_NOTICE => 'E_USER_NOTICE', // 1024 + \E_STRICT => 'E_STRICT', // 2048 + \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 + \E_DEPRECATED => 'E_DEPRECATED', // 8192 + \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 ); /** - * Изящная остановка или нет. + * Graceful stop or not. * * @var bool */ protected static $_gracefulStop = false; /** - * Стандартный выходной поток + * Standard output stream * @var resource */ protected static $_outputStream = null; /** - * Если стандартный выходной поток декорирован + * If $outputStream support decorated * @var bool */ protected static $_outputDecorated = null; /** - * Запуск всех экземпляров движка. + * Run all server instances. * * @return void */ @@ -553,60 +549,57 @@ public static function runAll() static::init(); static::parseCommand(); static::daemonize(); - static::initServers(); + static::initWorkers(); static::installSignal(); static::saveMasterPid(); static::displayUI(); - static::forkServers(); + static::forkWorkers(); static::resetStd(); - static::monitorServers(); + static::monitorWorkers(); } /** - * Проверка sapi. + * Check sapi. * * @return void */ protected static function checkSapiEnv() { - // Только для CLI. + // Only for cli. if (\PHP_SAPI !== 'cli') { - exit("Запускаться только в режиме командной строки \n"); + exit("Only run in command line mode \n"); } - // Если сепаратор системы "\" вместо "/", то это винда - // Не делай так без необходимости, прошу... if (\DIRECTORY_SEPARATOR === '\\') { self::$_OS = \OS_TYPE_WINDOWS; } } /** - * Инициализация. + * Init. * * @return void */ protected static function init() { - // ( ̄y▽ ̄)╭ Собственный обработчик ошибок..... - \set_error_handler(function ($code, $msg, $file, $line) { - Server::safeEcho("$msg в файле $file в строке $line\n"); + \set_error_handler(function($code, $msg, $file, $line){ + Server::safeEcho("$msg in file $file on line $line\n"); }); - // Запущенный файл из обратного пути - $backtrace = \debug_backtrace(); + // Start file. + $backtrace = \debug_backtrace(); static::$_startFile = $backtrace[\count($backtrace) - 1]['file']; - // Уникальный префикс для PID из пути стартового файла (почему бы и нет) + $unique_prefix = \str_replace('/', '_', static::$_startFile); - // PID файл + // Pid file. if (empty(static::$pidFile)) { static::$pidFile = __DIR__ . "/../$unique_prefix.pid"; } - // Логи + // Log file. if (empty(static::$logFile)) { - static::$logFile = __DIR__ . '/../WEBCORE.log'; + static::$logFile = __DIR__ . '/../webcore.log'; } $log_file = (string)static::$logFile; if (!\is_file($log_file)) { @@ -614,24 +607,24 @@ protected static function init() \chmod($log_file, 0622); } - // Статус: Работает + // State. static::$_status = static::STATUS_STARTING; - // Время запуска для статистики + // For statistics. static::$_globalStatistics['start_timestamp'] = \time(); - // Название процесса + // Process title. static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$_startFile); - // Инициализация ID + // Init data for server id. static::initId(); - // Инициализация таймера + // Timer init. Timer::init(); } /** - * Блокировка + * Lock. * * @return void */ @@ -639,13 +632,13 @@ protected static function lock() { $fd = \fopen(static::$_startFile, 'r'); if ($fd && !flock($fd, LOCK_EX)) { - static::log('WEBCORE [' . static::$_startFile . '] уже запущен.'); + static::log('WebCore ['.static::$_startFile.'] already running.'); exit; } } /** - * Разблокировка + * Unlock. * * @return void */ @@ -656,21 +649,20 @@ protected static function unlock() } /** - * Инициализация всех экземпляров + * Init All server instances. * * @return void */ - protected static function initServers() + protected static function initWorkers() { - // Только для Linux if (static::$_OS !== \OS_TYPE_LINUX) { return; } + + static::$_statisticsFile = static::$statusFile ? static::$statusFile : __DIR__ . '/../webcore-' .posix_getpid().'.status'; - static::$_statisticsFile = static::$statusFile ? static::$statusFile : __DIR__ . '/../WEBCORE-' . posix_getpid() . '.status'; - - foreach (static::$_servers as $server) { - // Имя воркера + foreach (static::$_workers as $server) { + // Server name. if (empty($server->name)) { $server->name = 'none'; } @@ -680,7 +672,7 @@ protected static function initServers() $server->user = static::getCurrentUser(); } else { if (\posix_getuid() !== 0 && $server->user !== static::getCurrentUser()) { - static::log('Внимание: Нужен root для смены uid или gid.'); + static::log('Warning: You must have the root privileges to change uid and gid.'); } } @@ -691,7 +683,7 @@ protected static function initServers() $server->status = ' [OK] '; // Get column mapping for UI - foreach (static::getUiColumns() as $column_name => $prop) { + foreach(static::getUiColumns() as $column_name => $prop){ !isset($server->{$prop}) && $server->{$prop} = 'NNNN'; $prop_length = \strlen((string) $server->{$prop}); $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; @@ -706,26 +698,26 @@ protected static function initServers() } /** - * Перезагрузить все воркеры. + * Reload all server instances. * * @return void */ - public static function reloadAllServers() + public static function reloadAllWorkers() { static::init(); - static::initServers(); + static::initWorkers(); static::displayUI(); static::$_status = static::STATUS_RELOADING; } /** - * Получить все воркеры. + * Get all server instances. * * @return array */ - public static function getAllServers() + public static function getAllWorkers() { - return static::$_servers; + return static::$_workers; } /** @@ -742,8 +734,7 @@ public static function getEventLoop() * Get main socket resource * @return resource */ - public function getMainSocket() - { + public function getMainSocket(){ return $this->_mainSocket; } @@ -753,18 +744,18 @@ public function getMainSocket() */ protected static function initId() { - foreach (static::$_servers as $server_id => $server) { + foreach (static::$_workers as $worker_id => $server) { $new_id_map = array(); $server->count = $server->count < 1 ? 1 : $server->count; - for ($key = 0; $key < $server->count; $key++) { - $new_id_map[$key] = isset(static::$_idMap[$server_id][$key]) ? static::$_idMap[$server_id][$key] : 0; + for($key = 0; $key < $server->count; $key++) { + $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0; } - static::$_idMap[$server_id] = $new_id_map; + static::$_idMap[$worker_id] = $new_id_map; } } /** - * Получить Unix-пользователя текущего процесса. + * Get unix user of current porcess. * * @return string */ @@ -775,115 +766,56 @@ protected static function getCurrentUser() } /** - * Отобразить стартовый псевдо-интерфейс + * Display staring UI. * * @return void */ protected static function displayUI() { global $argv; - // Команда -q отключает этот интерфейс if (\in_array('-q', $argv)) { return; } - - // В Linux всё просто!) if (static::$_OS !== \OS_TYPE_LINUX) { - static::safeEcho("---------------------------- ИНФОРМАЦИЯ --------------------------------\r\n"); - static::safeEcho(' WebCore ' . static::VERSION . ' PHP ' . \PHP_VERSION . " \r\n"); - static::safeEcho("------------------------ СПИСОК ВОРКЕРОВ -------------------------------\r\n"); - static::safeEcho("Воркер URL Статус\r\n"); + static::safeEcho("----------------------- WEBCORE -----------------------------\r\n"); + static::safeEcho('WebCore version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); + static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); + static::safeEcho("server listen processes status\r\n"); return; } - // Версии + //show version + $line_version = 'WebCore version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', \STR_PAD_LEFT) . \PHP_VERSION; + $line_version .= \str_pad('Event-Loop:', 22, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL; + !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version)); $total_length = static::getSingleLineTotalLength(); - $line_one = '' . \str_pad(' WebCore Server ', $total_length + \strlen(''), '-', \STR_PAD_BOTH) . '' . \PHP_EOL; - $line_version = '' . \str_pad('WebCore: ' . static::VERSION, intdiv($total_length, 2), ' ', \STR_PAD_BOTH) . \str_pad('PHP: ' . \PHP_VERSION, intdiv($total_length, 2), ' ', \STR_PAD_BOTH) . '' . \PHP_EOL; - $line_two = '' . \str_pad(' СПИСОК ВОРКЕРОВ ', $total_length + \strlen('') + 14, '-', \STR_PAD_BOTH) . '' . \PHP_EOL; + $line_one = '' . \str_pad(' WEBCORE ', $total_length + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL; + $line_two = \str_pad(' WORKERS ' , $total_length + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; static::safeEcho($line_one . $line_version . $line_two); - // ----------------------------------------- WebCore Server ----------------------------------------- - // WebCore: 1.0.0-dev PHP: 8.1.2 - // --------------------------------------- СПИСОК ВОРКЕРОВ --------------------------------------- - - if (!\defined('LINE_VERSIOIN_LENGTH')) \define('LINE_VERSIOIN_LENGTH', \strlen($line_version)); - - $len = []; - $contents = []; - - - // Контент - foreach (static::$_servers as $server) { - $content = ''; - foreach (static::getUiColumns() as $column_name => $prop) { - // $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; - - if ($column_name === 'proto') { - $column_name = 'Протокол'; - $column_len = 8; - } - if ($column_name === 'user') { - $column_name = 'Пользователь'; - $column_len = 12; - } - if ($column_name === 'server') { - $column_name = 'Сервис'; - $column_len = 6; - } - if ($column_name === 'socket') { - $column_name = 'Адрес'; - $column_len = 5; - } - if ($column_name === 'processes') { - $column_name = 'Процессы'; - $column_len = 8; - } - if ($column_name === 'status') { - $column_name = 'Статус'; - $column_len = 6; - } - if (empty($len[$column_name])) { - $len[$column_name] = 15 + $column_len; - } - if ($len[$column_name] < \strlen('| ' . (string) $server->{$prop})) { - $len[$column_name] = \strlen('| ' . (string) $server->{$prop}) + 7; - } - - // $content .= \str_pad('| ' . (string) $server->{$prop}, $len[$column_name] + 4); - $content .= \str_pad("| " . (string) $server->{$prop}, $len[$column_name] - $column_len); - } - $content && $contents[] = $content . \PHP_EOL; - } - - // Заголовок + //Show title $title = ''; - foreach (static::getUiColumns() as $column_name => $prop) { - // 'proto' => 'transport' - // 'user' => 'user' - // 'server' => 'name' - // 'socket' => 'socket' - // 'processes' => 'count' - // 'status' => 'status' - - if ($column_name === 'proto') $column_name = 'Протокол'; - if ($column_name === 'user') $column_name = 'Пользователь'; - if ($column_name === 'server') $column_name = 'Сервис'; - if ($column_name === 'socket') $column_name = 'Адрес'; - if ($column_name === 'processes') $column_name = 'Процессы'; - if ($column_name === 'status') $column_name = 'Статус'; - - $title .= \str_pad("| " . $column_name, $len[$column_name]); + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + //just keep compatible with listen name + $column_name === 'socket' && $column_name = 'listen'; + $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); } - $title && static::safeEcho($title . \PHP_EOL); - foreach ($contents as $c) { - static::safeEcho($c); + //Show content + foreach (static::$_workers as $server) { + $content = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", (string) $server->{$prop}, $matches); + $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; + $content .= \str_pad((string) $server->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + } + $content && static::safeEcho($content . \PHP_EOL); } - - // Show last line + //Show last line $line_last = \str_pad('', static::getSingleLineTotalLength(), '-') . \PHP_EOL; !empty($content) && static::safeEcho($line_last); @@ -896,9 +828,9 @@ protected static function displayUI() $tmpArgv[$index] = 'stop'; } } - static::safeEcho("Введи \"php " . implode(' ', $tmpArgv) . "\" для остановки. Движок запущен.\n\n"); + static::safeEcho("Input \"php ".implode(' ', $tmpArgv)."\" to stop. Start success.\n\n"); } else { - static::safeEcho("Нажми Ctrl+C для остановки. Движок запущен.\n"); + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } } @@ -931,7 +863,7 @@ public static function getSingleLineTotalLength() { $total_length = 0; - foreach (static::getUiColumns() as $column_name => $prop) { + foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; $total_length += static::$$key + static::UI_SAFE_LENGTH; } @@ -956,7 +888,7 @@ protected static function parseCommand() global $argv; // Check argv; $start_file = $argv[0]; - $usage = "Использование: php start.php <команда> [mode]\nКоманды: \nstart\t\tЗапустить WebCore в тестовом режиме.\n\t\tИспользуй флаг -d для запуска в режиме демона.\nstop\t\tОстановка WebCore.\n\t\tИспользуй флаг -g для изящной остановки.\nrestart\t\tПерезапуск всех процессов.\n\t\tИспользуй флаг -d для запуска в режиме демона.\n\t\tИспользуй флаг -g для изящной остановки.\nreload\t\tПерезагрузка кода.\n\t\tИспользуй флаг -g для изящной перезагрузки.\nstatus\t\tСтатус подпроцессов.\n\t\tИспользуй флаг -d для выгрузки статуса в реальном времени.\nconnections\tСписок соединений.\n"; + $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart server in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop server.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet server status.\n\t\tUse mode -d to show live status.\nconnections\tGet server connections.\n"; $available_commands = array( 'start', 'stop', @@ -986,27 +918,27 @@ protected static function parseCommand() $mode_str = ''; if ($command === 'start') { if ($mode === '-d' || static::$daemonize) { - $mode_str = 'в режиме Демона'; + $mode_str = 'in DAEMON mode'; } else { - $mode_str = 'в тестовом режиме'; + $mode_str = 'in DEBUG mode'; } } - static::log("WEBCORE [$start_file] $command $mode_str"); + static::log("WebCore [$start_file] $command $mode_str"); // Get master process PID. $master_pid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; // Master is still alive? if (static::checkMasterIsAlive($master_pid)) { if ($command === 'start') { - static::log("WEBCORE [$start_file] уже запущен"); + static::log("WebCore [$start_file] already running"); exit; } } elseif ($command !== 'start' && $command !== 'restart') { - static::log("WEBCORE [$start_file] не запущен"); + static::log("WebCore [$start_file] not run"); exit; } - $statistics_file = static::$statusFile ? static::$statusFile : __DIR__ . "/../WEBCORE-$master_pid.status"; + $statistics_file = static::$statusFile ? static::$statusFile : __DIR__ . "/../webcore-$master_pid.status"; // execute command. switch ($command) { @@ -1033,7 +965,7 @@ protected static function parseCommand() if ($mode !== '-d') { exit(0); } - static::safeEcho("\nНажми Ctrl+C чтобы выйти.\n\n"); + static::safeEcho("\nPress Ctrl+C to quit.\n\n"); } exit(0); case 'connections': @@ -1045,7 +977,7 @@ protected static function parseCommand() // Waiting amoment. \usleep(500000); // Display statisitcs data from a disk file. - if (\is_readable($statistics_file)) { + if(\is_readable($statistics_file)) { \readfile($statistics_file); } exit(0); @@ -1054,11 +986,11 @@ protected static function parseCommand() if ($mode === '-g') { static::$_gracefulStop = true; $sig = \SIGQUIT; - static::log("WEBCORE [$start_file] останавливается изящно ( ̄y▽ ̄)╭ ..."); + static::log("WebCore [$start_file] is gracefully stopping ..."); } else { static::$_gracefulStop = false; $sig = \SIGINT; - static::log("WEBCORE [$start_file] останавливается ..."); + static::log("WebCore [$start_file] is stopping ..."); } // Send stop signal to master process. $master_pid && \posix_kill($master_pid, $sig); @@ -1071,7 +1003,7 @@ protected static function parseCommand() if ($master_is_alive) { // Timeout? if (!static::$_gracefulStop && \time() - $start_time >= $timeout) { - static::log("WEBCORE [$start_file] ошибка остановки"); + static::log("WebCore [$start_file] stop fail"); exit; } // Waiting amoment. @@ -1079,7 +1011,7 @@ protected static function parseCommand() continue; } // Stop success. - static::log("WEBCORE [$start_file] остановлен"); + static::log("WebCore [$start_file] stop success"); if ($command === 'stop') { exit(0); } @@ -1090,16 +1022,16 @@ protected static function parseCommand() } break; case 'reload': - if ($mode === '-g') { + if($mode === '-g'){ $sig = \SIGUSR2; - } else { + }else{ $sig = \SIGUSR1; } \posix_kill($master_pid, $sig); exit; - default: + default : if (isset($command)) { - static::safeEcho('Неизвестная команда: ' . $command . "\n"); + static::safeEcho('Unknown command: ' . $command . "\n"); } exit($usage); } @@ -1123,8 +1055,8 @@ protected static function formatStatusData($statistics_file) } $status_str = ''; $current_total_request = array(); - $server_info = \unserialize($info[0]); - \ksort($server_info, SORT_NUMERIC); + $worker_info = \unserialize($info[0]); + \ksort($worker_info, SORT_NUMERIC); unset($info[0]); $data_waiting_sort = array(); $read_process_status = false; @@ -1135,8 +1067,8 @@ protected static function formatStatusData($statistics_file) $total_memory = 0; $total_timers = 0; $maxLen1 = static::$_maxSocketNameLength; - $maxLen2 = static::$_maxServerNameLength; - foreach ($info as $key => $value) { + $maxLen2 = static::$_maxWorkerNameLength; + foreach($info as $key => $value) { if (!$read_process_status) { $status_str .= $value . "\n"; if (\preg_match('/^pid.*?memory.*?listening/', $value)) { @@ -1144,13 +1076,13 @@ protected static function formatStatusData($statistics_file) } continue; } - if (\preg_match('/^[0-9]+/', $value, $pid_math)) { + if(\preg_match('/^[0-9]+/', $value, $pid_math)) { $pid = $pid_math[0]; $data_waiting_sort[$pid] = $value; - if (\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $total_memory += \intval(\str_ireplace('M', '', $match[1])); - $maxLen1 = \max($maxLen1, \strlen($match[2])); - $maxLen2 = \max($maxLen2, \strlen($match[3])); + if(\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { + $total_memory += \intval(\str_ireplace('M','',$match[1])); + $maxLen1 = \max($maxLen1,\strlen($match[2])); + $maxLen2 = \max($maxLen2,\strlen($match[3])); $total_connections += \intval($match[4]); $total_fails += \intval($match[5]); $total_timers += \intval($match[6]); @@ -1159,11 +1091,11 @@ protected static function formatStatusData($statistics_file) } } } - foreach ($server_info as $pid => $info) { + foreach($worker_info as $pid => $info) { if (!isset($data_waiting_sort[$pid])) { $status_str .= "$pid\t" . \str_pad('N/A', 7) . " " . \str_pad($info['listen'], static::$_maxSocketNameLength) . " " - . \str_pad($info['name'], static::$_maxServerNameLength) . " " + . \str_pad($info['name'], static::$_maxWorkerNameLength) . " " . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " " . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n"; continue; @@ -1175,16 +1107,16 @@ protected static function formatStatusData($statistics_file) $qps = $current_total_request[$pid] - $total_request_cache[$pid]; $total_qps += $qps; } - $status_str .= $data_waiting_sort[$pid] . " " . \str_pad($qps, 6) . " [idle]\n"; + $status_str .= $data_waiting_sort[$pid]. " " . \str_pad($qps, 6) ." [idle]\n"; } $total_request_cache = $current_total_request; $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; - $status_str .= "Summary\t" . \str_pad($total_memory . 'M', 7) . " " + $status_str .= "Summary\t" . \str_pad($total_memory.'M', 7) . " " . \str_pad('-', $maxLen1) . " " . \str_pad('-', $maxLen2) . " " . \str_pad($total_connections, 11) . " " . \str_pad($total_fails, 9) . " " . \str_pad($total_timers, 7) . " " . \str_pad($total_requests, 13) . " " - . \str_pad($total_qps, 6) . " [Summary] \n"; + . \str_pad($total_qps,6)." [Summary] \n"; return $status_str; } @@ -1277,7 +1209,7 @@ protected static function reinstallSignal() public static function signalHandler($signal) { switch ($signal) { - // Stop. + // Stop. case \SIGINT: case \SIGTERM: case \SIGHUP: @@ -1285,23 +1217,23 @@ public static function signalHandler($signal) static::$_gracefulStop = false; static::stopAll(); break; - // Graceful stop. + // Graceful stop. case \SIGQUIT: static::$_gracefulStop = true; static::stopAll(); break; - // Reload. + // Reload. case \SIGUSR2: case \SIGUSR1: static::$_gracefulStop = $signal === \SIGUSR2; - static::$_pidsToRestart = static::getAllServerPids(); + static::$_pidsToRestart = static::getAllWorkerPids(); static::reload(); break; - // Show status. + // Show status. case \SIGIOT: static::writeStatisticsToStatusFile(); break; - // Show connection status. + // Show connection status. case \SIGIO: static::writeConnectionsStatisticsToStatusFile(); break; @@ -1351,8 +1283,7 @@ public static function resetStd() $handle = \fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - \set_error_handler(function () { - }); + \set_error_handler(function(){}); if ($STDOUT) { \fclose($STDOUT); } @@ -1416,7 +1347,7 @@ protected static function getEventLoopName() } $loop_name = ''; - foreach (static::$_availableEventLoops as $name => $class) { + foreach (static::$_availableEventLoops as $name=>$class) { if (\extension_loaded($name)) { $loop_name = $name; break; @@ -1436,12 +1367,12 @@ protected static function getEventLoopName() * * @return array */ - protected static function getAllServerPids() + protected static function getAllWorkerPids() { $pid_array = array(); - foreach (static::$_pidMap as $server_pid_array) { - foreach ($server_pid_array as $server_pid) { - $pid_array[$server_pid] = $server_pid; + foreach (static::$_pidMap as $worker_pid_array) { + foreach ($worker_pid_array as $worker_pid) { + $pid_array[$worker_pid] = $worker_pid; } } return $pid_array; @@ -1452,12 +1383,12 @@ protected static function getAllServerPids() * * @return void */ - protected static function forkServers() + protected static function forkWorkers() { if (static::$_OS === \OS_TYPE_LINUX) { - static::forkServersForLinux(); + static::forkWorkersForLinux(); } else { - static::forkServersForWindows(); + static::forkWorkersForWindows(); } } @@ -1466,22 +1397,22 @@ protected static function forkServers() * * @return void */ - protected static function forkServersForLinux() + protected static function forkWorkersForLinux() { - foreach (static::$_servers as $server) { + foreach (static::$_workers as $server) { if (static::$_status === static::STATUS_STARTING) { if (empty($server->name)) { $server->name = $server->getSocketName(); } - $server_name_length = \strlen($server->name); - if (static::$_maxServerNameLength < $server_name_length) { - static::$_maxServerNameLength = $server_name_length; + $worker_name_length = \strlen($server->name); + if (static::$_maxWorkerNameLength < $worker_name_length) { + static::$_maxWorkerNameLength = $worker_name_length; } } - while (\count(static::$_pidMap[$server->serverId]) < $server->count) { - static::forkOneServerForLinux($server); + while (\count(static::$_pidMap[$server->workerId]) < $server->count) { + static::forkOneWorkerForLinux($server); } } } @@ -1491,31 +1422,38 @@ protected static function forkServersForLinux() * * @return void */ - protected static function forkServersForWindows() + protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); global $argv; - if (\in_array('-q', $argv) || \count($files) === 1) { - if (\count(static::$_servers) > 1) { - static::safeEcho("@@@ Ошибка: Инициализация мультисервера в одном файле PHP не поддерживается @@@\r\n"); - } elseif (\count(static::$_servers) <= 0) { + if(\in_array('-q', $argv) || \count($files) === 1) + { + if(\count(static::$_workers) > 1) + { + static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); + } + elseif(\count(static::$_workers) <= 0) + { exit("@@@no server inited@@@\r\n\r\n"); } - \reset(static::$_servers); + \reset(static::$_workers); /** @var Server $server */ - $server = current(static::$_servers); + $server = current(static::$_workers); // Display UI. static::safeEcho(\str_pad($server->name, 30) . \str_pad($server->getSocketName(), 36) . \str_pad($server->count, 10) . "[ok]\n"); $server->listen(); $server->run(); exit("@@@child exit@@@\r\n"); - } else { + } + else + { static::$globalEvent = new \localzet\Core\Events\Select(); Timer::init(static::$globalEvent); - foreach ($files as $start_file) { - static::forkOneServerForWindows($start_file); + foreach($files as $start_file) + { + static::forkOneWorkerForWindows($start_file); } } } @@ -1525,12 +1463,13 @@ protected static function forkServersForWindows() * * @return array */ - public static function getStartFilesForWindows() - { + public static function getStartFilesForWindows() { global $argv; $files = array(); - foreach ($argv as $file) { - if (\is_file($file)) { + foreach($argv as $file) + { + if(\is_file($file)) + { $files[$file] = $file; } } @@ -1542,7 +1481,7 @@ public static function getStartFilesForWindows() * * @param string $start_file */ - public static function forkOneServerForWindows($start_file) + public static function forkOneWorkerForWindows($start_file) { $start_file = \realpath($start_file); @@ -1566,19 +1505,24 @@ public static function forkOneServerForWindows($start_file) * check server status for windows. * @return void */ - public static function checkServerStatusForWindows() + public static function checkWorkerStatusForWindows() { - foreach (static::$_processForWindows as $process_data) { + foreach(static::$_processForWindows as $process_data) + { $process = $process_data[0]; $start_file = $process_data[1]; $status = \proc_get_status($process); - if (isset($status['running'])) { - if (!$status['running']) { + if(isset($status['running'])) + { + if(!$status['running']) + { static::safeEcho("process $start_file terminated and try to restart\n"); \proc_close($process); - static::forkOneServerForWindows($start_file); + static::forkOneWorkerForWindows($start_file); } - } else { + } + else + { static::safeEcho("proc_get_status fail\n"); } } @@ -1591,18 +1535,18 @@ public static function checkServerStatusForWindows() * @param self $server * @throws Exception */ - protected static function forkOneServerForLinux(self $server) + protected static function forkOneWorkerForLinux(self $server) { // Get available server id. - $id = static::getId($server->serverId, 0); + $id = static::getId($server->workerId, 0); if ($id === false) { return; } $pid = \pcntl_fork(); // For master process. if ($pid > 0) { - static::$_pidMap[$server->serverId][$pid] = $pid; - static::$_idMap[$server->serverId][$id] = $pid; + static::$_pidMap[$server->workerId][$pid] = $pid; + static::$_idMap[$server->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { \srand(); @@ -1615,14 +1559,14 @@ protected static function forkOneServerForLinux(self $server) } static::$_pidMap = array(); // Remove other listener. - foreach (static::$_servers as $key => $one_server) { - if ($one_server->serverId !== $server->serverId) { - $one_server->unlisten(); - unset(static::$_servers[$key]); + foreach(static::$_workers as $key => $one_worker) { + if ($one_worker->workerId !== $server->workerId) { + $one_worker->unlisten(); + unset(static::$_workers[$key]); } } Timer::delAll(); - static::setProcessTitle(self::$processTitle . ': Процесс ' . $server->name . ' ' . $server->getSocketName()); + static::setProcessTitle(self::$processTitle . ': server process ' . $server->name . ' ' . $server->getSocketName()); $server->setUserAndGroup(); $server->id = $id; $server->run(); @@ -1633,21 +1577,21 @@ protected static function forkOneServerForLinux(self $server) static::log($err); exit(250); } else { - throw new Exception("forkOneServer fail"); + throw new Exception("forkOneWorker fail"); } } /** * Get server id. * - * @param string $server_id + * @param string $worker_id * @param int $pid * * @return integer */ - protected static function getId($server_id, $pid) + protected static function getId($worker_id, $pid) { - return \array_search($pid, static::$_idMap[$server_id]); + return \array_search($pid, static::$_idMap[$worker_id]); } /** @@ -1660,7 +1604,7 @@ public function setUserAndGroup() // Get uid. $user_info = \posix_getpwnam($this->user); if (!$user_info) { - static::log("Внимание: Пользователь {$this->user} не существует"); + static::log("Warning: User {$this->user} not exsits"); return; } $uid = $user_info['uid']; @@ -1668,7 +1612,7 @@ public function setUserAndGroup() if ($this->group) { $group_info = \posix_getgrnam($this->group); if (!$group_info) { - static::log("Внимание: Группа {$this->group} не существует"); + static::log("Warning: Group {$this->group} not exsits"); return; } $gid = $group_info['gid']; @@ -1679,7 +1623,7 @@ public function setUserAndGroup() // Set uid and gid. if ($uid !== \posix_getuid() || $gid !== \posix_getgid()) { if (!\posix_setgid($gid) || !\posix_initgroups($user_info['name'], $gid) || !\posix_setuid($uid)) { - static::log("Внимание: Не удалось сменить gid или uid."); + static::log("Warning: change gid or uid fail."); } } } @@ -1692,8 +1636,7 @@ public function setUserAndGroup() */ protected static function setProcessTitle($title) { - \set_error_handler(function () { - }); + \set_error_handler(function(){}); // >=php 5.5 if (\function_exists('cli_set_process_title')) { \cli_set_process_title($title); @@ -1709,12 +1652,12 @@ protected static function setProcessTitle($title) * * @return void */ - protected static function monitorServers() + protected static function monitorWorkers() { if (static::$_OS === \OS_TYPE_LINUX) { - static::monitorServersForLinux(); + static::monitorWorkersForLinux(); } else { - static::monitorServersForWindows(); + static::monitorWorkersForWindows(); } } @@ -1723,7 +1666,7 @@ protected static function monitorServers() * * @return void */ - protected static function monitorServersForLinux() + protected static function monitorWorkersForLinux() { static::$_status = static::STATUS_RUNNING; while (1) { @@ -1737,33 +1680,44 @@ protected static function monitorServersForLinux() // If a child has already exited. if ($pid > 0) { // Find out which server process exited. - foreach (static::$_pidMap as $server_id => $server_pid_array) { - if (isset($server_pid_array[$pid])) { - $server = static::$_servers[$server_id]; + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + if (isset($worker_pid_array[$pid])) { + $server = static::$_workers[$worker_id]; // Exit status. if ($status !== 0) { - static::log("WEBCORE [" . $server->name . ":$pid] умер со статусом $status"); + static::log("server[{$server->name}:$pid] exit with status $status"); + } + + // onWorkerExit + if ($server->onWorkerExit) { + try { + call_user_func($server->onWorkerExit, $server, $status, $pid); + } catch (\Exception $e) { + static::log("server[{$server->name}] onWorkerExit $e"); + } catch (\Error $e) { + static::log("server[{$server->name}] onWorkerExit $e"); + } } // For Statistics. - if (!isset(static::$_globalStatistics['server_exit_info'][$server_id][$status])) { - static::$_globalStatistics['server_exit_info'][$server_id][$status] = 0; + if (!isset(static::$_globalStatistics['worker_exit_info'][$worker_id][$status])) { + static::$_globalStatistics['worker_exit_info'][$worker_id][$status] = 0; } - ++static::$_globalStatistics['server_exit_info'][$server_id][$status]; + ++static::$_globalStatistics['worker_exit_info'][$worker_id][$status]; // Clear process data. - unset(static::$_pidMap[$server_id][$pid]); + unset(static::$_pidMap[$worker_id][$pid]); // Mark id is available. - $id = static::getId($server_id, $pid); - static::$_idMap[$server_id][$id] = 0; + $id = static::getId($worker_id, $pid); + static::$_idMap[$worker_id][$id] = 0; break; } } // Is still running state then fork a new server process. if (static::$_status !== static::STATUS_SHUTDOWN) { - static::forkServers(); + static::forkWorkers(); // If reloading continue. if (isset(static::$_pidsToRestart[$pid])) { unset(static::$_pidsToRestart[$pid]); @@ -1773,7 +1727,7 @@ protected static function monitorServersForLinux() } // If shutdown state and all child processes exited then master process exit. - if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllServerPids()) { + if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { static::exitAndClearAll(); } } @@ -1784,9 +1738,9 @@ protected static function monitorServersForLinux() * * @return void */ - protected static function monitorServersForWindows() + protected static function monitorWorkersForWindows() { - Timer::add(1, "\\localzet\\Core\\Server::checkServerStatusForWindows"); + Timer::add(1, "\\localzet\\Core\\Server::checkWorkerStatusForWindows"); static::$globalEvent->loop(); } @@ -1798,7 +1752,7 @@ protected static function monitorServersForWindows() */ protected static function exitAndClearAll() { - foreach (static::$_servers as $server) { + foreach (static::$_workers as $server) { $socket_name = $server->getSocketName(); if ($server->transport === 'unix' && $socket_name) { list(, $address) = \explode(':', $socket_name, 2); @@ -1807,7 +1761,7 @@ protected static function exitAndClearAll() } } @\unlink(static::$pidFile); - static::log("WEBCORE [" . \basename(static::$_startFile) . "] остановлен"); + static::log("WebCore [" . \basename(static::$_startFile) . "] has been stopped"); if (static::$onMasterStop) { \call_user_func(static::$onMasterStop); } @@ -1825,7 +1779,7 @@ protected static function reload() if (static::$_masterPid === \posix_getpid()) { // Set reloading state. if (static::$_status !== static::STATUS_RELOADING && static::$_status !== static::STATUS_SHUTDOWN) { - static::log("WEBCORE [" . \basename(static::$_startFile) . "] перезагружается"); + static::log("WebCore [" . \basename(static::$_startFile) . "] reloading"); static::$_status = static::STATUS_RELOADING; // Try to emit onMasterReload callback. if (static::$onMasterReload) { @@ -1848,14 +1802,14 @@ protected static function reload() // Send reload signal to all child processes. $reloadable_pid_array = array(); - foreach (static::$_pidMap as $server_id => $server_pid_array) { - $server = static::$_servers[$server_id]; + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + $server = static::$_workers[$worker_id]; if ($server->reloadable) { - foreach ($server_pid_array as $pid) { + foreach ($worker_pid_array as $pid) { $reloadable_pid_array[$pid] = $pid; } } else { - foreach ($server_pid_array as $pid) { + foreach ($worker_pid_array as $pid) { // Send reload signal to a server process which reloadable is false. \posix_kill($pid, $sig); } @@ -1873,21 +1827,21 @@ protected static function reload() return; } // Continue reload. - $one_server_pid = \current(static::$_pidsToRestart); + $one_worker_pid = \current(static::$_pidsToRestart); // Send reload signal to a server process. - \posix_kill($one_server_pid, $sig); - // Если процесс не выключился после static::$stopTimeout секунд пытаемся убить его. - if (!static::$_gracefulStop) { - Timer::add(static::$stopTimeout, '\posix_kill', array($one_server_pid, \SIGKILL), false); + \posix_kill($one_worker_pid, $sig); + // If the process does not exit after static::$stopTimeout seconds try to kill it. + if(!static::$_gracefulStop){ + Timer::add(static::$stopTimeout, '\posix_kill', array($one_worker_pid, \SIGKILL), false); } - } // Для детей.ов + } // For child processes. else { - \reset(static::$_servers); - $server = \current(static::$_servers); - // Try to emit onServerReload callback. - if ($server->onServerReload) { + \reset(static::$_workers); + $server = \current(static::$_workers); + // Try to emit onWorkerReload callback. + if ($server->onWorkerReload) { try { - \call_user_func($server->onServerReload, $server); + \call_user_func($server->onWorkerReload, $server); } catch (\Exception $e) { static::stopAll(250, $e); } catch (\Error $e) { @@ -1916,18 +1870,18 @@ public static function stopAll($code = 0, $log = '') static::$_status = static::STATUS_SHUTDOWN; // For master process. if (\DIRECTORY_SEPARATOR === '/' && static::$_masterPid === \posix_getpid()) { - static::log("WEBCORE [" . \basename(static::$_startFile) . "] останавливается ..."); - $server_pid_array = static::getAllServerPids(); + static::log("WebCore [" . \basename(static::$_startFile) . "] stopping ..."); + $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. if (static::$_gracefulStop) { $sig = \SIGQUIT; } else { $sig = \SIGINT; } - foreach ($server_pid_array as $server_pid) { - \posix_kill($server_pid, $sig); - if (!static::$_gracefulStop) { - Timer::add(static::$stopTimeout, '\posix_kill', array($server_pid, \SIGKILL), false); + foreach ($worker_pid_array as $worker_pid) { + \posix_kill($worker_pid, $sig); + if(!static::$_gracefulStop){ + Timer::add(static::$stopTimeout, '\posix_kill', array($worker_pid, \SIGKILL), false); } } Timer::add(1, "\\localzet\\Core\\Server::checkIfChildRunning"); @@ -1938,14 +1892,14 @@ public static function stopAll($code = 0, $log = '') } // For child processes. else { // Execute exit. - foreach (static::$_servers as $server) { - if (!$server->stopping) { + foreach (static::$_workers as $server) { + if(!$server->stopping){ $server->stop(); $server->stopping = true; } } if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { - static::$_servers = array(); + static::$_workers = array(); if (static::$globalEvent) { static::$globalEvent->destroy(); } @@ -1953,6 +1907,7 @@ public static function stopAll($code = 0, $log = '') try { exit($code); } catch (Exception $e) { + } } } @@ -1963,10 +1918,10 @@ public static function stopAll($code = 0, $log = '') */ public static function checkIfChildRunning() { - foreach (static::$_pidMap as $server_id => $server_pid_array) { - foreach ($server_pid_array as $pid => $server_pid) { + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + foreach ($worker_pid_array as $pid => $worker_pid) { if (!\posix_kill($pid, 0)) { - unset(static::$_pidMap[$server_id][$pid]); + unset(static::$_pidMap[$worker_id][$pid]); } } } @@ -2001,91 +1956,58 @@ protected static function writeStatisticsToStatusFile() { // For master process. if (static::$_masterPid === \posix_getpid()) { - $all_server_info = array(); - foreach (static::$_pidMap as $server_id => $pid_array) { - /** @var /localzet\Core/Server $server */ - $server = static::$_servers[$server_id]; - foreach ($pid_array as $pid) { - $all_server_info[$pid] = array('name' => $server->name, 'listen' => $server->getSocketName()); + $all_worker_info = array(); + foreach(static::$_pidMap as $worker_id => $pid_array) { + /** @var /localzet/Core/Server $server */ + $server = static::$_workers[$worker_id]; + foreach($pid_array as $pid) { + $all_worker_info[$pid] = array('name' => $server->name, 'listen' => $server->getSocketName()); } } - \file_put_contents(static::$_statisticsFile, \serialize($all_server_info) . "\n", \FILE_APPEND); - $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2, 2, 2)) : array('-', '-', '-'); - \file_put_contents( - static::$_statisticsFile, - "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", - \FILE_APPEND - ); - \file_put_contents( - static::$_statisticsFile, - 'WEBCORE version:' . static::VERSION . " PHP version:" . \PHP_VERSION . "\n", - \FILE_APPEND - ); - \file_put_contents( - static::$_statisticsFile, - 'start time:' . \date( - 'Y-m-d H:i:s', - static::$_globalStatistics['start_timestamp'] - ) . ' run ' . \floor((\time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", - FILE_APPEND - ); + \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); + $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2,2,2)) : array('-', '-', '-'); + \file_put_contents(static::$_statisticsFile, + "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + 'WebCore version:' . static::VERSION . " PHP version:" . \PHP_VERSION . "\n", \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, 'start time:' . \date('Y-m-d H:i:s', + static::$_globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", + FILE_APPEND); $load_str = 'load average: ' . \implode(", ", $loadavg); - \file_put_contents( - static::$_statisticsFile, - \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", - \FILE_APPEND - ); - \file_put_contents( - static::$_statisticsFile, - \count(static::$_pidMap) . ' servers ' . \count(static::getAllServerPids()) . " processes\n", - \FILE_APPEND - ); - \file_put_contents( - static::$_statisticsFile, - \str_pad('server_name', static::$_maxServerNameLength) . " exit_status exit_count\n", - \FILE_APPEND - ); - foreach (static::$_pidMap as $server_id => $server_pid_array) { - $server = static::$_servers[$server_id]; - if (isset(static::$_globalStatistics['server_exit_info'][$server_id])) { - foreach (static::$_globalStatistics['server_exit_info'][$server_id] as $server_exit_status => $server_exit_count) { - \file_put_contents( - static::$_statisticsFile, - \str_pad($server->name, static::$_maxServerNameLength) . " " . \str_pad( - $server_exit_status, - 16 - ) . " $server_exit_count\n", - \FILE_APPEND - ); + \file_put_contents(static::$_statisticsFile, + \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + \count(static::$_pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", + \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + \str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND); + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + $server = static::$_workers[$worker_id]; + if (isset(static::$_globalStatistics['worker_exit_info'][$worker_id])) { + foreach (static::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { + \file_put_contents(static::$_statisticsFile, + \str_pad($server->name, static::$_maxWorkerNameLength) . " " . \str_pad($worker_exit_status, + 16) . " $worker_exit_count\n", \FILE_APPEND); } } else { - \file_put_contents( - static::$_statisticsFile, - \str_pad($server->name, static::$_maxServerNameLength) . " " . \str_pad(0, 16) . " 0\n", - \FILE_APPEND - ); + \file_put_contents(static::$_statisticsFile, + \str_pad($server->name, static::$_maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n", + \FILE_APPEND); } } - \file_put_contents( - static::$_statisticsFile, + \file_put_contents(static::$_statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", - \FILE_APPEND - ); - \file_put_contents( - static::$_statisticsFile, - "pid\tmemory " . \str_pad('listening', static::$_maxSocketNameLength) . " " . \str_pad( - 'server_name', - static::$_maxServerNameLength - ) . " connections " . \str_pad('send_fail', 9) . " " - . \str_pad('timers', 8) . \str_pad('total_request', 13) . " qps status\n", - \FILE_APPEND - ); + \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + "pid\tmemory " . \str_pad('listening', static::$_maxSocketNameLength) . " " . \str_pad('worker_name', + static::$_maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " + . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", \FILE_APPEND); \chmod(static::$_statisticsFile, 0722); - foreach (static::getAllServerPids() as $server_pid) { - \posix_kill($server_pid, \SIGIOT); + foreach (static::getAllWorkerPids() as $worker_pid) { + \posix_kill($worker_pid, \SIGIOT); } return; } @@ -2095,18 +2017,18 @@ protected static function writeStatisticsToStatusFile() if (\function_exists('gc_mem_caches')) { \gc_mem_caches(); } - \reset(static::$_servers); + \reset(static::$_workers); /** @var \localzet\Core\Server $server */ - $server = current(static::$_servers); - $server_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(false) / (1024 * 1024), 2) . "M", 7) + $server = current(static::$_workers); + $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(false) / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($server->getSocketName(), static::$_maxSocketNameLength) . " " - . \str_pad(($server->name === $server->getSocketName() ? 'none' : $server->name), static::$_maxServerNameLength) + . \str_pad(($server->name === $server->getSocketName() ? 'none' : $server->name), static::$_maxWorkerNameLength) . " "; - $server_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) + $worker_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; - \file_put_contents(static::$_statisticsFile, $server_status_str, \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, $worker_status_str, \FILE_APPEND); } /** @@ -2118,40 +2040,41 @@ protected static function writeConnectionsStatisticsToStatusFile() { // For master process. if (static::$_masterPid === \posix_getpid()) { - \file_put_contents(static::$_statisticsFile, "------------------------------------------------------------------------- WEBWEBCORE CONNECTION STATUS ------------------------------------------------------------------------------------\n", \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WEBCORE CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND); \file_put_contents(static::$_statisticsFile, "PID Server CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND); \chmod(static::$_statisticsFile, 0722); - foreach (static::getAllServerPids() as $server_pid) { - \posix_kill($server_pid, \SIGIO); + foreach (static::getAllWorkerPids() as $worker_pid) { + \posix_kill($worker_pid, \SIGIO); } return; } // For child processes. - $bytes_format = function ($bytes) { - if ($bytes > 1024 * 1024 * 1024 * 1024) { - return round($bytes / (1024 * 1024 * 1024 * 1024), 1) . "TB"; + $bytes_format = function($bytes) + { + if($bytes > 1024*1024*1024*1024) { + return round($bytes/(1024*1024*1024*1024), 1)."TB"; } - if ($bytes > 1024 * 1024 * 1024) { - return round($bytes / (1024 * 1024 * 1024), 1) . "GB"; + if($bytes > 1024*1024*1024) { + return round($bytes/(1024*1024*1024), 1)."GB"; } - if ($bytes > 1024 * 1024) { - return round($bytes / (1024 * 1024), 1) . "MB"; + if($bytes > 1024*1024) { + return round($bytes/(1024*1024), 1)."MB"; } - if ($bytes > 1024) { - return round($bytes / (1024), 1) . "KB"; + if($bytes > 1024) { + return round($bytes/(1024), 1)."KB"; } - return $bytes . "B"; + return $bytes."B"; }; $pid = \posix_getpid(); $str = ''; - \reset(static::$_servers); - $current_server = current(static::$_servers); - $default_server_name = $current_server->name; + \reset(static::$_workers); + $current_worker = current(static::$_workers); + $default_worker_name = $current_worker->name; /** @var \localzet\Core\Server $server */ - foreach (TcpConnection::$connections as $connection) { + foreach(TcpConnection::$connections as $connection) { /** @var \localzet\Core\Connection\TcpConnection $connection */ $transport = $connection->transport; $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; @@ -2167,19 +2090,19 @@ protected static function writeConnectionsStatisticsToStatusFile() $protocol = $connection->protocol ? $connection->protocol : $connection->transport; $pos = \strrpos($protocol, '\\'); if ($pos) { - $protocol = \substr($protocol, $pos + 1); + $protocol = \substr($protocol, $pos+1); } if (\strlen($protocol) > 15) { $protocol = \substr($protocol, 0, 13) . '..'; } - $server_name = isset($connection->server) ? $connection->server->name : $default_server_name; - if (\strlen($server_name) > 14) { - $server_name = \substr($server_name, 0, 12) . '..'; + $worker_name = isset($connection->server) ? $connection->server->name : $default_worker_name; + if (\strlen($worker_name) > 14) { + $worker_name = \substr($worker_name, 0, 12) . '..'; } - $str .= \str_pad($pid, 9) . \str_pad($server_name, 16) . \str_pad($id, 10) . \str_pad($transport, 8) + $str .= \str_pad($pid, 9) . \str_pad($worker_name, 16) . \str_pad($id, 10) . \str_pad($transport, 8) . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recv_q, 13) . \str_pad($send_q, 13) . \str_pad($bytes_read, 13) . \str_pad($bytes_written, 13) . ' ' - . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) . "\n"; + . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) ."\n"; } if ($str) { \file_put_contents(static::$_statisticsFile, $str, \FILE_APPEND); @@ -2194,16 +2117,15 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN !== static::$_status) { - $error_msg = static::$_OS === \OS_TYPE_LINUX ? 'WEBCORE [' . \posix_getpid() . '] процесс прерван' : ' WebCore процесс прерван'; + $error_msg = static::$_OS === \OS_TYPE_LINUX ? 'Server['. \posix_getpid() .'] process terminated' : 'Server process terminated'; $errors = error_get_last(); - if ( - $errors && ($errors['type'] === \E_ERROR || + if ($errors && ($errors['type'] === \E_ERROR || $errors['type'] === \E_PARSE || $errors['type'] === \E_CORE_ERROR || $errors['type'] === \E_COMPILE_ERROR || $errors['type'] === \E_RECOVERABLE_ERROR) ) { - $error_msg .= ' с ошибкой: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} в {$errors['file']} на {$errors['line']} строке\""; + $error_msg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; } static::log($error_msg); } @@ -2217,7 +2139,7 @@ public static function checkErrors() */ protected static function getErrorType($type) { - if (isset(self::$_errorType[$type])) { + if(isset(self::$_errorType[$type])) { return self::$_errorType[$type]; } @@ -2287,6 +2209,7 @@ private static function outputStream($stream = null) return false; } if (($stat['mode'] & 0170000) === 0100000) { + // file static::$_outputDecorated = false; } else { static::$_outputDecorated = @@ -2298,22 +2221,24 @@ private static function outputStream($stream = null) } /** + * Construct. + * * @param string $socket_name * @param array $context_option */ public function __construct($socket_name = '', array $context_option = array()) { - // Сохранить все экземпляры - $this->serverId = \spl_object_hash($this); - static::$_servers[$this->serverId] = $this; - static::$_pidMap[$this->serverId] = array(); + // Save all server instances. + $this->workerId = \spl_object_hash($this); + static::$_workers[$this->workerId] = $this; + static::$_pidMap[$this->workerId] = array(); - // Получить путь из обратного пути - $backtrace = \debug_backtrace(); + // Get autoload root path. + $backtrace = \debug_backtrace(); $this->_autoloadRootPath = \dirname($backtrace[0]['file']); Autoloader::setRootPath($this->_autoloadRootPath); - // Контекст сокета + // Context for socket. if ($socket_name) { $this->_socketName = $socket_name; if (!isset($context_option['socket']['backlog'])) { @@ -2335,7 +2260,7 @@ public function __construct($socket_name = '', array $context_option = array()) /** - * Прослушка + * Listen. * * @throws Exception */ @@ -2345,7 +2270,7 @@ public function listen() return; } - // Автозагрузка + // Autoload. Autoloader::setRootPath($this->_autoloadRootPath); if (!$this->_mainSocket) { @@ -2381,8 +2306,7 @@ public function listen() // Try to open keepalive for tcp and disable Nagle algorithm. if (\function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { - \set_error_handler(function () { - }); + \set_error_handler(function(){}); $socket = \socket_import_stream($this->_mainSocket); \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); \socket_set_option($socket, \SOL_TCP, \TCP_NODELAY, 1); @@ -2401,12 +2325,10 @@ public function listen() * * @return void */ - public function unlisten() - { + public function unlisten() { $this->pauseAccept(); if ($this->_mainSocket) { - \set_error_handler(function () { - }); + \set_error_handler(function(){}); \fclose($this->_mainSocket); \restore_error_handler(); $this->_mainSocket = null; @@ -2418,8 +2340,7 @@ public function unlisten() * * @throws Exception */ - protected function parseSocketAddress() - { + protected function parseSocketAddress() { if (!$this->_socketName) { return; } @@ -2428,16 +2349,16 @@ protected function parseSocketAddress() // Check application layer protocol class. if (!isset(static::$_builtinTransports[$scheme])) { $scheme = \ucfirst($scheme); - $this->protocol = \substr($scheme, 0, 1) === '\\' ? $scheme : 'Protocols\\' . $scheme; + $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : 'Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { $this->protocol = "localzet\\Core\\Protocols\\$scheme"; if (!\class_exists($this->protocol)) { - throw new Exception("Класс \\Protocols\\$scheme не существует"); + throw new Exception("class \\Protocols\\$scheme not exist"); } } if (!isset(static::$_builtinTransports[$this->transport])) { - throw new Exception('Некорректный server->transport ' . \var_export($this->transport, true)); + throw new Exception('Bad server->transport ' . \var_export($this->transport, true)); } } else { $this->transport = $scheme; @@ -2518,16 +2439,15 @@ public function run() // Set an empty onMessage callback. if (empty($this->onMessage)) { - $this->onMessage = function () { - }; + $this->onMessage = function () {}; } \restore_error_handler(); - // Try to emit onServerStart callback. - if ($this->onServerStart) { + // Try to emit onWorkerStart callback. + if ($this->onWorkerStart) { try { - \call_user_func($this->onServerStart, $this); + \call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { // Avoid rapid infinite loop exit. sleep(1); @@ -2539,7 +2459,7 @@ public function run() } } - // Главный цикл. + // Main loop. static::$globalEvent->loop(); } @@ -2550,10 +2470,10 @@ public function run() */ public function stop() { - // Try to emit onServerStop callback. - if ($this->onServerStop) { + // Try to emit onWorkerStop callback. + if ($this->onWorkerStop) { try { - \call_user_func($this->onServerStop, $this); + \call_user_func($this->onWorkerStop, $this); } catch (\Exception $e) { static::stopAll(250, $e); } catch (\Error $e) { @@ -2562,7 +2482,7 @@ public function stop() } // Remove listener for server socket. $this->unlisten(); - // Закрываем все соединения + // Close all connections for the server. if (!static::$_gracefulStop) { foreach ($this->connections as $connection) { $connection->close(); @@ -2581,8 +2501,7 @@ public function stop() public function acceptConnection($socket) { // Accept a connection on server socket. - \set_error_handler(function () { - }); + \set_error_handler(function(){}); $new_socket = \stream_socket_accept($socket, 0, $remote_address); \restore_error_handler(); @@ -2623,8 +2542,7 @@ public function acceptConnection($socket) */ public function acceptUdpConnection($socket) { - \set_error_handler(function () { - }); + \set_error_handler(function(){}); $recv_buffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); \restore_error_handler(); if (false === $recv_buffer || empty($remote_address)) { @@ -2700,3 +2618,4 @@ protected static function checkMasterIsAlive($master_pid) return stripos($content, static::$processTitle) !== false || stripos($content, 'php') !== false; } } + diff --git a/src/Timer.php b/src/Timer.php index 7a72df4..2586296 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -1,5 +1,4 @@ [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], @@ -39,21 +37,21 @@ class Timer protected static $_tasks = array(); /** - * Событие + * event * * @var EventInterface */ protected static $_event = null; /** - * ID Таймера + * timer id * * @var int */ protected static $_timerId = 0; /** - * Статус таймера + * timer status * [ * timer_id1 => bool, * timer_id2 => bool, @@ -65,7 +63,7 @@ class Timer protected static $_status = array(); /** - * Инициализация + * Init. * * @param EventInterface $event * @return void @@ -82,7 +80,7 @@ public static function init($event = null) } /** - * Обработчик сигнала + * ALARM signal handler. * * @return void */ @@ -95,7 +93,7 @@ public static function signalHandle() } /** - * Добавить таймер. + * Add a timer. * * @param float $time_interval * @param callable $func @@ -106,7 +104,7 @@ public static function signalHandle() public static function add($time_interval, $func, $args = array(), $persistent = true) { if ($time_interval <= 0) { - Server::safeEcho(new Exception("Отрицательный интервал для таймера")); + Server::safeEcho(new Exception("bad time_interval")); return false; } @@ -115,16 +113,16 @@ public static function add($time_interval, $func, $args = array(), $persistent = } if (self::$_event) { - return self::$_event->add( - $time_interval, - $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, - $func, - $args - ); + return self::$_event->add($time_interval, + $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); + } + + if (!Server::getAllWorkers()) { + return; } if (!\is_callable($func)) { - Server::safeEcho(new Exception("Некорректный callback")); + Server::safeEcho(new Exception("not callable")); return false; } @@ -146,7 +144,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = /** - * ТИК (или ТАК, кому как нравится) + * Tick. * * @return void */ @@ -169,9 +167,9 @@ public static function tick() } catch (\Exception $e) { Server::safeEcho($e); } - if ($persistent && !empty(self::$_status[$index])) { + if($persistent && !empty(self::$_status[$index])) { $new_run_time = \time() + $time_interval; - if (!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array(); + if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array(); self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval); } } @@ -192,17 +190,18 @@ public static function del($timer_id) return self::$_event->del($timer_id, EventInterface::EV_TIMER); } - foreach (self::$_tasks as $run_time => $task_data) { - if (array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]); + foreach(self::$_tasks as $run_time => $task_data) + { + if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]); } - if (array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]); + if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]); return true; } /** - * Удалить все таймеры. + * Remove all timers. * * @return void */