Skip to content
This repository has been archived by the owner on Aug 25, 2022. It is now read-only.

Add Socket.IO v2 support #152

Merged
merged 4 commits into from
May 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function initialize($keepAlive = false)
/**
* Reads a message from the socket
*
* @return MessageInterface Message read from the socket
* @return string Message read from the socket
*/
public function read()
{
Expand All @@ -89,6 +89,9 @@ public function read()
/**
* Emits a message through the engine
*
* @param string $event
* @param array $args
*
* @return $this
*/
public function emit($event, array $args)
Expand Down
5 changes: 4 additions & 1 deletion src/Engine/AbstractSocketIO.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace ElephantIO\Engine;

use DomainException;
use ElephantIO\Engine\SocketIO\Session;
use RuntimeException;

use Psr\Log\LoggerInterface;
Expand All @@ -37,7 +38,7 @@ abstract class AbstractSocketIO implements EngineInterface
/** @var array cookies received during handshake */
protected $cookies = [];

/** @var string[] Session information */
/** @var Session Session information */
protected $session;

/** @var mixed[] Array of options for the engine */
Expand Down Expand Up @@ -190,6 +191,8 @@ public function getName()
/**
* Parse an url into parts we may expect
*
* @param string $url
*
* @return string[] information on the given URL
*/
protected function parseUrl($url)
Expand Down
7 changes: 6 additions & 1 deletion src/Engine/SocketIO/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ public function __construct($id, $interval, $timeout, array $upgrades)
'interval' => $interval];
}

/** The property should not be modified, hence the private accessibility on them */
/**
* The property should not be modified, hence the private accessibility on them
*
* @param string $prop
* @return mixed
*/
public function __get($prop)
{
static $list = ['id', 'upgrades'];
Expand Down
2 changes: 1 addition & 1 deletion src/Engine/SocketIO/Version0X.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function connect()
$this->stream = stream_socket_client($host, $errors[0], $errors[1], $this->options['timeout'], STREAM_CLIENT_CONNECT, stream_context_create($this->context));

if (!is_resource($this->stream)) {
throw new SocketException($error[0], $error[1]);
throw new SocketException($errors[0], $errors[1]);
}

stream_set_timeout($this->stream, $this->options['timeout']);
Expand Down
28 changes: 21 additions & 7 deletions src/Engine/SocketIO/Version1X.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ protected function handshake()
throw new ServerConnectionFailureException;
}

$decoded = json_decode(substr($result, strpos($result, '{')), true);
$open_curly_at = strpos($result, '{');
$todecode = substr($result, $open_curly_at, strrpos($result, '}')-$open_curly_at+1);
$decoded = json_decode($todecode, true);

if (!in_array('websocket', $decoded['upgrades'])) {
throw new UnsupportedTransportException('websocket');
Expand All @@ -184,16 +186,27 @@ protected function handshake()
$this->session = new Session($decoded['sid'], $decoded['pingInterval'], $decoded['pingTimeout'], $decoded['upgrades']);
}

/** Upgrades the transport to WebSocket */
private function upgradeTransport()
/**
* Upgrades the transport to WebSocket
*
* FYI:
* Version "2" is used for the EIO param by socket.io v1
* Version "3" is used by socket.io v2
*/
protected function upgradeTransport()
{
$query = ['sid' => $this->session->id,
'EIO' => $this->options['version'],
'use_b64' => $this->options['use_b64'],
'transport' => static::TRANSPORT_WEBSOCKET];

if ($this->options['version'] === 2)
$query['use_b64'] = $this->options['use_b64'];

$url = sprintf('/%s/?%s', trim($this->url['path'], '/'), http_build_query($query));
$key = base64_encode(sha1(uniqid(mt_rand(), true), true));
$hash = sha1(uniqid(mt_rand(), true), true);
if ($this->options['version'] !== 2)
$hash = substr($hash, 0, 16);
$key = base64_encode($hash);

$origin = '*';
$headers = isset($this->context['headers']) ? (array) $this->context['headers'] : [] ;
Expand All @@ -208,7 +221,7 @@ private function upgradeTransport()
}

$request = "GET {$url} HTTP/1.1\r\n"
. "Host: {$this->url['host']}\r\n"
. "Host: {$this->url['host']}:{$this->url['port']}\r\n"
. "Upgrade: WebSocket\r\n"
. "Connection: Upgrade\r\n"
. "Sec-WebSocket-Key: {$key}\r\n"
Expand All @@ -234,7 +247,8 @@ private function upgradeTransport()
$this->write(EngineInterface::UPGRADE);

//remove message '40' from buffer, emmiting by socket.io after receiving EngineInterface::UPGRADE
$this->read();
if ($this->options['version'] === 2)
$this->read();
}
}

55 changes: 55 additions & 0 deletions src/Engine/SocketIO/Version2X.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of the Elephant.io package
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*
* @copyright Wisembly
* @license http://www.opensource.org/licenses/MIT-License MIT License
*/

namespace ElephantIO\Engine\SocketIO;

use DomainException;
use InvalidArgumentException;
use UnexpectedValueException;

use Psr\Log\LoggerInterface;

use ElephantIO\EngineInterface;
use ElephantIO\Payload\Encoder;
use ElephantIO\Engine\AbstractSocketIO;

use ElephantIO\Exception\SocketException;
use ElephantIO\Exception\UnsupportedTransportException;
use ElephantIO\Exception\ServerConnectionFailureException;

/**
* Implements the dialog with Socket.IO version 2.x
*
* Based on the work of Mathieu Lallemand (@lalmat)
*
* @author Baptiste Clavié <baptiste@wisembly.com>
* @link https://tools.ietf.org/html/rfc6455#section-5.2 Websocket's RFC
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comment is not right

class Version2X extends Version1X
{

/** {@inheritDoc} */
public function getName()
{
return 'SocketIO Version 2.X';
}

/** {@inheritDoc} */
protected function getDefaultOptions()
{
$defaults = parent::getDefaultOptions();

$defaults['version'] = 3;

return $defaults;
}
}

3 changes: 2 additions & 1 deletion src/Payload/Encoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@
class Encoder extends AbstractPayload
{
private $data;
/** @var string */
private $payload;

/**
* @param string $data data to encode
* @param integer $opcode OpCode to use (one of AbstractPayload's constant)
* @param integer $opCode OpCode to use (one of AbstractPayload's constant)
* @param bool $mask Should we use a mask ?
*/
public function __construct($data, $opCode, $mask)
Expand Down