diff --git a/src/Engine/Engine.php b/src/Engine/Engine.php index 68ba7d9..14903f2 100644 --- a/src/Engine/Engine.php +++ b/src/Engine/Engine.php @@ -30,13 +30,13 @@ class Engine extends Emitter 'Bad request' ]; - const ERROR_UNKNOWN_TRANSPORT = 0; + private const ERROR_UNKNOWN_TRANSPORT = 0; - const ERROR_UNKNOWN_SID = 1; + private const ERROR_UNKNOWN_SID = 1; - const ERROR_BAD_HANDSHAKE_METHOD = 2; + private const ERROR_BAD_HANDSHAKE_METHOD = 2; - const ERROR_BAD_REQUEST = 3; + private const ERROR_BAD_REQUEST = 3; public function __construct($opts = []) { @@ -48,6 +48,7 @@ public function __construct($opts = []) 'allowUpgrades', 'allowRequest' ]; + foreach ($ops_map as $key) { if (isset($opts[$key])) { $this->$key = $opts[$key]; @@ -61,7 +62,7 @@ public function __destruct() Debug::debug('Engine __destruct'); } - public function handleRequest($req, $res) + public function handleRequest(object $req, object $res) { $this->prepare($req); $req->res = $res; @@ -71,7 +72,7 @@ public function handleRequest($req, $res) /** * @throws Exception */ - public function dealRequest($err, $success, $req) + public function dealRequest($err, bool $success, object $req) { if (! $success) { self::sendErrorMessage($req, $req->res, $err); @@ -85,7 +86,7 @@ public function dealRequest($err, $success, $req) } } - protected function sendErrorMessage($req, $res, $code) + protected function sendErrorMessage(object $req, object $res, string $code): void { $headers = ['Content-Type' => 'application/json']; if (isset($req->headers['origin'])) { @@ -106,7 +107,7 @@ protected function sendErrorMessage($req, $res, $code) ); } - protected function verify($req, $res, $upgrade, $fn) + protected function verify(object $req, object $res, bool $upgrade, callable $fn) { if (! isset($req->_query['transport']) || ! isset(self::$allowTransports[$req->_query['transport']])) { return call_user_func($fn, self::ERROR_UNKNOWN_TRANSPORT, false, $req, $res); @@ -129,7 +130,7 @@ protected function verify($req, $res, $upgrade, $fn) call_user_func($fn, null, true, $req, $res); } - public function checkRequest($req, $res, $fn) + public function checkRequest(object $req, object $res, callable $fn) { if ($this->origins === "*:*" || empty($this->origins)) { return call_user_func($fn, null, true, $req, $res); @@ -158,7 +159,6 @@ public function checkRequest($req, $res, $fn) $allow_origin === $parts['scheme'] . '://' . $parts['host'] . ':*' || $allow_origin === '*:' . $parts['port']; if ($ok) { - // 只需要有一个白名单通过,则都通过 return call_user_func($fn, null, true, $req, $res); } } @@ -166,7 +166,7 @@ public function checkRequest($req, $res, $fn) call_user_func($fn, null, false, $req, $res); } - protected function prepare($req) + protected function prepare(object $req) { if (! isset($req->_query)) { $info = parse_url($req->url); @@ -179,7 +179,7 @@ protected function prepare($req) /** * @throws Exception */ - public function handshake($transport, $req) + public function handshake(string $transport, object $req) { $id = bin2hex(pack('d', microtime(true)) . pack('N', function_exists('random_int') ? random_int(1, 100000000) : rand(1, 100000000))); if ($transport == 'websocket') { @@ -203,18 +203,18 @@ public function handshake($transport, $req) $this->emit('connection', $socket); } - public function onSocketClose($id) + public function onSocketClose($id): void { unset($this->clients[$id]); } - public function attach($worker) + public function attach($worker): void { $this->server = $worker; $worker->onConnect = [$this, 'onConnect']; } - public function onConnect($connection) + public function onConnect(object $connection): void { $connection->onRequest = [$this, 'handleRequest']; $connection->onWebSocketConnect = [$this, 'onWebSocketConnect']; @@ -237,7 +237,7 @@ public function onConnect($connection) }; } - public function onWebSocketConnect($connection, $req, $res) + public function onWebSocketConnect($connection, object $req, object $res): void { $this->prepare($req); $this->verify($req, $res, true, [$this, 'dealWebSocketConnect']); @@ -246,7 +246,7 @@ public function onWebSocketConnect($connection, $req, $res) /** * @throws Exception */ - public function dealWebSocketConnect($err, $success, $req, $res) + public function dealWebSocketConnect($err, bool $success, object $req, object $res): void { if (! $success) { self::sendErrorMessage($req, $res, $err); diff --git a/src/Engine/Parser.php b/src/Engine/Parser.php index 503813b..3023eb7 100644 --- a/src/Engine/Parser.php +++ b/src/Engine/Parser.php @@ -43,32 +43,15 @@ public static function encodePacket($packet): string return self::$packets[$packet['type']] . $data; } - - /** - * Encodes a packet with binary data in a base64 string - * - * @param {Object} packet, has `type` and `data` - * @return string {String} base64 encoded message - */ - public static function encodeBase64Packet($packet): string - { - return 'b' . self::$packets[$packet['type']] . base64_encode($packet['data']); - } - /** * Decodes a packet. Data also available as an ArrayBuffer if requested. * - * @param $data - * @param null $binaryType - * @param bool $utf8decode * @return array|string[] {Object} with `type` and `data` (if any) - * @api private */ - public static function decodePacket($data, $binaryType = null, $utf8decode = true) + public static function decodePacket(string $data): array { - // String data todo check if (typeof data == 'string' || data === undefined) if ($data[0] === 'b') { - return self::decodeBase64Packet(substr($data, 1), $binaryType); + return self::decodeBase64Packet(substr($data, 1)); } $type = $data[0]; @@ -87,13 +70,12 @@ public static function decodePacket($data, $binaryType = null, $utf8decode = tru * Decodes a packet encoded in a base64 string. * * @param $msg - * @param $binaryType * @return array {Object} with `type` and `data` (if any) */ - public static function decodeBase64Packet($msg, $binaryType) + public static function decodeBase64Packet($msg): array { $type = self::$packetsList[$msg[0]]; - $data = base64_decode(substr($data, 1)); + $data = base64_decode(substr($msg, 1)); return ['type' => $type, 'data' => $data]; } @@ -124,12 +106,12 @@ public static function encodePayload($packets, $supportsBinary = null): string $results = ''; foreach ($packets as $msg) { - $results .= self::encodeOne($msg, $supportsBinary); + $results .= self::encodeOne($msg); } return $results; } - public static function encodeOne($packet, $supportsBinary = null, $result = null): string + public static function encodeOne($packet): string { $message = self::encodePacket($packet); return strlen($message) . ':' . $message; @@ -165,10 +147,10 @@ public static function decodePayload($data, $binaryType = null) return self::$err; } - $msg = substr($data, $i + 1/*, $n*/); + $msg = substr($data, $i + 1); if (isset($msg[0])) { - $packet = self::decodePacket($msg, $binaryType); + $packet = self::decodePacket($msg); if (self::$err['type'] == $packet['type'] && self::$err['data'] == $packet['data']) { // parser error in individual packet - ignoring payload @@ -215,7 +197,6 @@ public static function encodePayloadAsBinary($packets): string public static function encodeOneAsBinary($p): string { - // todo is string or arraybuf $packet = self::encodePacket($p); $encodingLength = '' . strlen($packet); $sizeBuffer = chr(0); @@ -257,7 +238,7 @@ public static function decodePayloadAsBinary($data, $binaryType = null): array } $bufferTail = substr($bufferTail, strlen($strLen) + 1); - $msgLength = intval($strLen, 10); + $msgLength = intval($strLen); $msg = substr($bufferTail, 1, $msgLength + 1); $buffers[] = $msg; @@ -265,7 +246,7 @@ public static function decodePayloadAsBinary($data, $binaryType = null): array } $packets = []; foreach ($buffers as $i => $buffer) { - $packets[] = self::decodePacket($buffer, $binaryType); + $packets[] = self::decodePacket($buffer); } return $packets; } diff --git a/src/Engine/Socket.php b/src/Engine/Socket.php index 3e7c08b..760d8b1 100644 --- a/src/Engine/Socket.php +++ b/src/Engine/Socket.php @@ -40,7 +40,7 @@ public function __destruct() Debug::debug('Engine/Socket __destruct'); } - public function maybeUpgrade($transport) + public function maybeUpgrade(object $transport): void { $this->upgrading = true; $this->upgradeTimeoutTimer = Timer::add( @@ -56,7 +56,7 @@ public function maybeUpgrade($transport) $this->once('close', [$this, 'onUpgradeTransportClose']); } - public function onUpgradePacket($packet) + public function onUpgradePacket(array $packet): void { if (empty($this->upgradeTransport)) { $this->onError('upgradeTransport empty'); @@ -82,15 +82,13 @@ public function onUpgradePacket($packet) $this->transport->close([$this, 'onClose']); } } else { - if (! empty($this->upgradeTransport)) { - $this->upgradeCleanup(); - $this->upgradeTransport->close(); - $this->upgradeTransport = null; - } + $this->upgradeCleanup(); + $this->upgradeTransport->close(); + $this->upgradeTransport = null; } } - public function upgradeCleanup() + public function upgradeCleanup(): void { $this->upgrading = false; Timer::del($this->checkIntervalTimer); @@ -103,12 +101,12 @@ public function upgradeCleanup() $this->removeListener('close', [$this, 'onUpgradeTransportClose']); } - public function onUpgradeTransportClose() + public function onUpgradeTransportClose(): void { $this->onUpgradeTransportError('transport closed'); } - public function onUpgradeTransportError($err) + public function onUpgradeTransportError($err): void { $this->upgradeCleanup(); if ($this->upgradeTransport) { @@ -117,7 +115,7 @@ public function onUpgradeTransportError($err) } } - public function upgradeTimeoutCallback($transport) + public function upgradeTimeoutCallback(object $transport): void { $this->upgradeCleanup(); if ('open' === $transport->readyState) { @@ -125,7 +123,7 @@ public function upgradeTimeoutCallback($transport) } } - public function setTransport($transport) + public function setTransport(object $transport) { $this->transport = $transport; $this->transport->once('error', [$this, 'onError']); @@ -136,11 +134,10 @@ public function setTransport($transport) $this->setupSendCallback(); } - public function onOpen() + public function onOpen(): void { $this->readyState = 'open'; - // sends an `open` packet $this->transport->sid = $this->id; $this->sendPacket( 'open', @@ -158,7 +155,7 @@ public function onOpen() $this->setPingTimeout(); } - public function onPacket($packet) + public function onPacket(array $packet) { if ('open' === $this->readyState) { // export packet event @@ -185,19 +182,19 @@ public function onPacket($packet) } } - public function check() + public function check(): void { if ('polling' == $this->transport->name && $this->transport->writable) { $this->transport->send([['type' => 'noop']]); } } - public function onError($err) + public function onError($err): void { $this->onClose('transport error', $err); } - public function setPingTimeout() + public function setPingTimeout(): void { if ($this->pingTimeoutTimer) { Timer::del($this->pingTimeoutTimer); @@ -210,20 +207,19 @@ public function setPingTimeout() ); } - public function pingTimeoutCallback() + public function pingTimeoutCallback(): void { $this->transport->close(); $this->onClose('ping timeout'); } - - public function clearTransport() + public function clearTransport(): void { $this->transport->close(); Timer::del($this->pingTimeoutTimer); } - public function onClose($reason = '', $description = null) + public function onClose(string $reason = '', ?string $description = null): void { if ('closed' !== $this->readyState) { Timer::del($this->pingTimeoutTimer); @@ -257,18 +253,18 @@ public function onClose($reason = '', $description = null) } } - public function send($data, $options, $callback): Socket + public function send($data, $options, ?callable $callback): Socket { $this->sendPacket('message', $data, $callback); return $this; } - public function write($data, $options = [], $callback = null): Socket + public function write($data, ?array $options = [], ?callable $callback = null): Socket { return $this->send($data, $options, $callback); } - public function sendPacket($type, $data = null, $callback = null) + public function sendPacket(string $type, $data = null, $callback = null): void { if ('closing' !== $this->readyState) { $packet = [ @@ -288,7 +284,7 @@ public function sendPacket($type, $data = null, $callback = null) } } - public function flush() + public function flush(): void { if ('closed' !== $this->readyState && $this->transport->writable && $this->writeBuffer @@ -319,7 +315,7 @@ public function getAvailableUpgrades(): array return ['websocket']; } - public function close() + public function close(): void { if ('open' !== $this->readyState) { return; @@ -335,19 +331,18 @@ public function close() $this->closeTransport(); } - public function closeTransport() + public function closeTransport(): void { - //todo onClose.bind(this, 'forced close')); $this->transport->close([$this, 'onClose']); } - public function setupSendCallback() + public function setupSendCallback(): void { //the message was sent successfully, execute the callback $this->transport->on('drain', [$this, 'onDrainCallback']); } - public function onDrainCallback() + public function onDrainCallback(): void { if ($this->sentCallbackFn) { $seqFn = array_shift($this->sentCallbackFn); diff --git a/src/Engine/Transport.php b/src/Engine/Transport.php index fb48e64..09f07a5 100644 --- a/src/Engine/Transport.php +++ b/src/Engine/Transport.php @@ -31,14 +31,14 @@ public function onRequest($req) $this->req = $req; } - public function close($fn = null) + public function close(?callable $fn = null): void { $this->readyState = 'closing'; - $fn = $fn ? $fn : [$this, 'noop']; + $fn = $fn ?: [$this, 'noop']; $this->doClose($fn); } - public function onError($msg, $desc = '') + public function onError(string $msg, string $desc = '') { if ($this->listeners('error')) { $err = [ @@ -51,7 +51,7 @@ public function onError($msg, $desc = '') } } - public function onPacket($packet) + public function onPacket($packet): void { $this->emit('packet', $packet); } @@ -69,9 +69,10 @@ public function onClose() $this->removeAllListeners(); } - public function destroy() + public function destroy(): void { - $this->req = $this->res = null; + $this->req = null; + $this->res = null; $this->readyState = 'closed'; $this->removeAllListeners(); $this->shouldClose = null; diff --git a/src/Engine/Transports/Polling.php b/src/Engine/Transports/Polling.php index 028165f..bb8a50b 100644 --- a/src/Engine/Transports/Polling.php +++ b/src/Engine/Transports/Polling.php @@ -11,6 +11,9 @@ class Polling extends Transport public $chunks = ''; public $shouldClose = null; public $writable = false; + public $supportsBinary = null; + public $dataRes = null; + public $dataReq = null; public function onRequest($req) { @@ -26,11 +29,9 @@ public function onRequest($req) } } - public function onPollRequest($req, $res) + public function onPollRequest(object $req, object $res): void { if ($this->req) { - echo('request overlap'); - // assert: this.res, '.req and .res should be (un)set together' $this->onError('overlap from client'); $res->writeHead(500); return; @@ -45,32 +46,29 @@ public function onPollRequest($req, $res) $this->writable = true; $this->emit('drain'); - // if we're still writable but had a pending close, trigger an empty send if ($this->writable && $this->shouldClose) { echo('triggering empty send to append close packet'); $this->send([['type' => 'noop']]); } } - public function pollRequestOnClose() + public function pollRequestOnClose(): void { $this->onError('poll connection closed prematurely'); $this->pollRequestClean(); } - public function pollRequestClean() + public function pollRequestClean(): void { if (isset($this->req)) { - $this->req->res = null; - $this->req->onClose = $this->req->cleanup = null; - $this->req = $this->res = null; + $this->req = null; + $this->res = null; } } - public function onDataRequest($req, $res) + public function onDataRequest($req, $res): void { if (isset($this->dataReq)) { - // assert: this.dataRes, '.dataReq and .dataRes should be (un)set together' $this->onError('data request overlap from client'); $res->writeHead(500); return; @@ -83,26 +81,25 @@ public function onDataRequest($req, $res) $req->onEnd = [$this, 'dataRequestOnEnd']; } - public function dataRequestCleanup() + public function dataRequestCleanup(): void { $this->chunks = ''; - $this->dataReq->res = null; - $this->dataReq->onClose = $this->dataReq->onData = $this->dataReq->onEnd = null; - $this->dataReq = $this->dataRes = null; + $this->dataReq = null; + $this->dataRes = null; } - public function dataRequestOnClose() + public function dataRequestOnClose(): void { $this->dataRequestCleanup(); $this->onError('data request connection closed prematurely'); } - public function dataRequestOnData($req, $data) + public function dataRequestOnData($req, $data): void { $this->chunks .= $data; } - public function dataRequestOnEnd() + public function dataRequestOnEnd(): void { $this->onData($this->chunks); @@ -137,13 +134,12 @@ public function onData($data) public function onClose() { if ($this->writable) { - // close pending poll request $this->send([['type' => 'noop']]); } parent::onClose(); } - public function send($packets) + public function send($packets): void { $this->writable = false; if ($this->shouldClose) { @@ -156,7 +152,7 @@ public function send($packets) $this->write($data); } - public function write($data) + public function write($data): void { $this->doWrite($data); if (! empty($this->req->cleanup)) { @@ -164,7 +160,7 @@ public function write($data) } } - public function doClose($fn) + public function doClose(callable $fn): void { if (! empty($this->dataReq)) { $this->dataReq->destroy(); diff --git a/src/Engine/Transports/PollingJsonp.php b/src/Engine/Transports/PollingJsonp.php index 5329c1a..0db5e2a 100644 --- a/src/Engine/Transports/PollingJsonp.php +++ b/src/Engine/Transports/PollingJsonp.php @@ -12,8 +12,7 @@ class PollingJsonp extends Polling public function __construct($req) { - $j = isset($req->_query['j']) ? preg_replace('/[^0-9]/', '', $req->_query['j']) : ''; - $this->head = "___eio[ $j ]("; + $this->head = '___eio[' . (isset($req['_query']['j']) ? preg_replace('/[^0-9]/', '', $req['_query']['j']) : '') . ']('; Debug::debug('PollingJsonp __construct'); } @@ -30,11 +29,10 @@ public function onData($data) call_user_func([$this, 'parent::onData'], preg_replace('/\\\\n/', '\\n', $data)); } - public function doWrite($data) + public function doWrite($data): void { $js = json_encode($data); - // prepare response $data = $this->head . $js . $this->foot; // explicit UTF-8 is required for pages not served under utf @@ -47,11 +45,11 @@ public function doWrite($data) echo new Exception('empty $this->res'); return; } - $this->res->writeHead(200, '', $this->headers($this->req, $headers)); + $this->res->writeHead(200, '', $this->headers($headers)); $this->res->end($data); } - public function headers($req, $headers = []) + public function headers(array $headers = []): array { $listeners = $this->listeners('headers'); foreach ($listeners as $listener) { diff --git a/src/Engine/Transports/PollingXHR.php b/src/Engine/Transports/PollingXHR.php index 73f9140..7ce3ecc 100644 --- a/src/Engine/Transports/PollingXHR.php +++ b/src/Engine/Transports/PollingXHR.php @@ -47,7 +47,7 @@ public function doWrite($data) $this->res->end($data); } - public function headers($req, $headers = []) + public function headers(object $req, array $headers = []): array { if (isset($req->headers['origin'])) { $headers['Access-Control-Allow-Credentials'] = 'true'; diff --git a/src/Engine/Transports/WebSocket.php b/src/Engine/Transports/WebSocket.php index b118e05..fbaeaac 100644 --- a/src/Engine/Transports/WebSocket.php +++ b/src/Engine/Transports/WebSocket.php @@ -28,17 +28,17 @@ public function __destruct() Debug::debug('WebSocket __destruct'); } - public function onData2($connection, $data) + public function onData2($connection, $data): void { call_user_func([$this, 'parent::onData'], $data); } - public function onError2($conection, $code, $msg) + public function onError2($conection, $code, $msg): void { call_user_func([$this, 'parent::onClose'], $code, $msg); } - public function send($packets) + public function send(array $packets): void { foreach ($packets as $packet) { $data = Parser::encodePacket($packet); @@ -49,7 +49,7 @@ public function send($packets) } } - public function doClose($fn = null) + public function doClose(callable $fn = null): void { if ($this->socket) { $this->socket->close();