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

Little patch for Socket 1.0.x - Working on my nRelay Project. #53

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 48 additions & 0 deletions .gitignore
@@ -0,0 +1,48 @@
### Debug folder ###
debug/

### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath

# External tool builders
.externalToolBuilders/

# Locally stored "Eclipse launch configurations"
*.launch

# CDT-specific
.cproject

# PDT-specific
.buildpath

# sbteclipse plugin
.target

# TeXlipse plugin
.texlipse


### SublimeText ###
# workspace files are user-specific
*.sublime-workspace

# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project

#sftp configuration file
sftp-config.json
Copy link
Contributor

Choose a reason for hiding this comment

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

All these have nothing to do in a .gitignore (project wise), it should be in your global .gitignore. Otherwise, we should support everything... And I don't think that this is really possible. :D



99 changes: 47 additions & 52 deletions lib/ElephantIO/Client.php
Expand Up @@ -2,22 +2,31 @@

namespace ElephantIO;

require(__DIR__."/Payload.php");
Copy link
Contributor

Choose a reason for hiding this comment

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

This shouldn't be needed, as composer autoloads it.

/**
* ElephantIOClient is a rough implementation of socket.io protocol.
* It should ease you dealing with a socket.io server.
*
* @author Ludovic Barreca <ludovic@balloonup.com>
*/
class Client {
const TYPE_DISCONNECT = 0;
const TYPE_CONNECT = 1;
const TYPE_HEARTBEAT = 2;
const TYPE_MESSAGE = 3;
const TYPE_JSON_MESSAGE = 4;
const TYPE_EVENT = 5;
const TYPE_ACK = 6;
const TYPE_ERROR = 7;
const TYPE_NOOP = 8;
// Engine IO message types
const EIO_OPEN = 0;
const EIO_CLOSE = 1;
const EIO_PING = 2;
const EIO_PONG = 3;
const EIO_MESSAGE = 4;
const EIO_UPGRADE = 5;
const EIO_NOOP = 6;

// Socket IO message types
const SIO_CONNECT = 0;
const SIO_DISCONNECT = 1;
const SIO_EVENT = 2;
const SIO_ACK = 3;
const SIO_ERROR = 4;
const SIO_BINARY_EVENT = 5;
const SIO_BINARY_ACK = 6;

private $socketIOUrl;
private $serverHost;
Expand All @@ -34,7 +43,7 @@ class Client {
private $handshakeQuery = '';

public function __construct($socketIOUrl, $socketIOPath = 'socket.io', $protocol = 1, $read = true, $checkSslPeer = true, $debug = false) {
$this->socketIOUrl = $socketIOUrl.'/'.$socketIOPath.'/'.(string)$protocol;
$this->socketIOUrl = $socketIOUrl.'/'.$socketIOPath.'/?transport=polling&b64=1'; //.(string)$protocol;
$this->read = $read;
$this->debug = $debug;
$this->parseUrl();
Expand All @@ -49,7 +58,6 @@ public function __construct($socketIOUrl, $socketIOPath = 'socket.io', $protocol
*/
public function setHandshakeQuery(array $query) {
$this->handshakeQuery = '?' . http_build_query($query);

return $this;
}

Expand Down Expand Up @@ -79,7 +87,7 @@ public function init($keepalive = false) {
public function keepAlive() {
while (is_resource($this->fd)) {
if ($this->session['heartbeat_timeout'] > 0 && $this->session['heartbeat_timeout']+$this->heartbeatStamp-5 < time()) {
$this->send(self::TYPE_HEARTBEAT);
$this->send(self::EIO_PING);
$this->heartbeatStamp = time();
}

Expand All @@ -90,7 +98,7 @@ public function keepAlive() {

$res = $this->read();
$sess = explode(':', $res);
if ((int)$sess[0] === self::TYPE_EVENT) {
if ((int)$sess[0] === self::EIO_MESSAGE) {
unset($sess[0], $sess[1], $sess[2]);

$response = json_decode(implode(':', $sess), true);
Expand Down Expand Up @@ -175,31 +183,34 @@ public function on($event, $callback) {
* Send message to the websocket
*
* @access public
* @param int $type
* @param int $id
* @param int $eioCode
* @param int $sioCode
* @param int $endpoint
* @param string $message
* @return ElephantIO\Client
*/
public function send($type, $id = null, $endpoint = null, $message = null) {
if (!is_int($type) || $type > 8) {
public function send($eioCode, $sioCode = self::SIO_EVENT, $endpoint = null, $message = null) {
if (!is_int($eioCode) || $eioCode > 8) {
throw new \InvalidArgumentException('ElephantIOClient::send() type parameter must be an integer strictly inferior to 9.');
}

$raw_message = $type.':'.$id.':'.$endpoint.':'.$message;
$raw_message = $eioCode.$sioCode.$message;

$payload = new Payload();
$payload->setOpcode(Payload::OPCODE_TEXT)
->setMask(true)
->setPayload($raw_message);
->setMask(true)
->setPayload($raw_message);
$encoded = $payload->encodePayload();

fwrite($this->fd, $encoded);

// wait 100ms before closing connexion
usleep(100*1000);
if ($this->read) {
if ($this->read() != '1::') {
Copy link

Choose a reason for hiding this comment

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

I think '1::' is socket.io v0.9 format. In my case, server responded "40" to client message "52".

throw new \Exception('Socket.io did not send connect response. Aborting...');
} else {
$this->stdout('info', 'Server report us as connected !');
}
}

$this->stdout('debug', 'Sent '.$raw_message);

return $this;
}

Expand All @@ -214,11 +225,7 @@ public function send($type, $id = null, $endpoint = null, $message = null) {
* @todo work on callbacks
*/
public function emit($event, $args, $endpoint = null, $callback = null) {
return $this->send(self::TYPE_EVENT, null, $endpoint, json_encode(array(
'name' => $event,
'args' => $args,
)
));
return $this->send(self::EIO_MESSAGE, self::SIO_EVENT, $endpoint, '["'.$event.'",'.json_encode($args).']');
}

/**
Expand All @@ -229,7 +236,7 @@ public function emit($event, $args, $endpoint = null, $callback = null) {
public function close()
{
if (is_resource($this->fd)) {
$this->send(self::TYPE_DISCONNECT);
$this->send(self::EIO_CLOSE);
fclose($this->fd);

return true;
Expand Down Expand Up @@ -324,16 +331,17 @@ private function handshake() {
}

$res = curl_exec($ch);

if ($res === false || $res === '') {
throw new \Exception(curl_error($ch));
}

$sess = explode(':', $res);
$this->session['sid'] = $sess[0];
$this->session['heartbeat_timeout'] = $sess[1];
$this->session['connection_timeout'] = $sess[2];
$this->session['supported_transports'] = array_flip(explode(',', $sess[3]));
curl_close($ch);

$sess = json_decode(substr($res, strpos($res,"{"), strrpos($res,"}")));
$this->session['sid'] = $sess->sid;
$this->session['heartbeat_timeout'] = $sess->pingInterval;
$this->session['connection_timeout'] = $sess->pingTimeout;
$this->session['supported_transports'] = array_flip($sess->upgrades);

if (!isset($this->session['supported_transports']['websocket'])) {
throw new \Exception('This socket.io server do not support websocket protocol. Terminating connection...');
Expand All @@ -356,17 +364,14 @@ private function connect() {
}

$key = $this->generateKey();

$out = "GET ".$this->serverPath."/websocket/".$this->session['sid']." HTTP/1.1\r\n";
$out = "GET ".$this->serverPath."?transport=websocket&sid=".$this->session['sid']." HTTP/1.1\r\n";
$out .= "Host: ".$this->serverHost."\r\n";
$out .= "Upgrade: WebSocket\r\n";
$out .= "Connection: Upgrade\r\n";
$out .= "Sec-WebSocket-Key: ".$key."\r\n";
$out .= "Sec-WebSocket-Version: 13\r\n";
$out .= "Origin: *\r\n\r\n";

fwrite($this->fd, $out);

$res = fgets($this->fd);

if ($res === false) {
Expand All @@ -381,16 +386,7 @@ private function connect() {
$res = trim(fgets($this->fd));
if ($res === '') break;
}

if ($this->read) {
if ($this->read() != '1::') {
throw new \Exception('Socket.io did not send connect response. Aborting...');
} else {
$this->stdout('info', 'Server report us as connected !');
}
}

// $this->send(self::TYPE_CONNECT);
$this->send(self::EIO_UPGRADE);
$this->heartbeatStamp = time();
}

Expand All @@ -402,7 +398,6 @@ private function connect() {
*/
private function parseUrl() {
$url = parse_url($this->socketIOUrl);

$this->serverPath = $url['path'];
$this->serverHost = $url['host'];
$this->serverPort = isset($url['port']) ? $url['port'] : null;
Expand Down