mirror of https://github.com/axmolengine/axmol.git
[v3-update-sio] updates SocketIO network extension to support v1.x socket.io servers as well as maintain backwards compat. for 0.9.x servers
Signed-off-by: Chris Hannon <himynameschris@gmail.com>
This commit is contained in:
parent
9bde2f5bb6
commit
5af28838d2
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2013 Chris Hannon
|
||||
Copyright (c) 2013-2014 Chukong Technologies Inc.
|
||||
Copyright (c) 2015 Chris Hannon http://www.channon.us
|
||||
Copyright (c) 2013-2015 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
|
@ -36,12 +36,319 @@
|
|||
#include "WebSocket.h"
|
||||
#include "HttpClient.h"
|
||||
|
||||
#include "json/rapidjson.h"
|
||||
#include "json/document.h"
|
||||
#include "json/stringbuffer.h"
|
||||
#include "json/writer.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
namespace network {
|
||||
|
||||
//class declarations
|
||||
|
||||
class SocketIOPacketV10x;
|
||||
|
||||
class SocketIOPacket
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
V09x,
|
||||
V10x
|
||||
}SocketIOVersion;
|
||||
|
||||
SocketIOPacket();
|
||||
virtual ~SocketIOPacket();
|
||||
void initWithType(std::string packetType);
|
||||
void initWithTypeIndex(int index);
|
||||
|
||||
std::string toString();
|
||||
virtual int typeAsNumber();
|
||||
std::string typeForIndex(int index);
|
||||
|
||||
void setEndpoint(std::string endpoint){ _endpoint = endpoint; };
|
||||
std::string getEndpoint(){ return _endpoint; };
|
||||
void setEvent(std::string event){ _name = event; };
|
||||
std::string getEvent(){ return _name; };
|
||||
|
||||
void addData(std::string data);
|
||||
std::vector<std::string> getData(){ return _args; };
|
||||
virtual std::string stringify();
|
||||
|
||||
static SocketIOPacket * createPacketWithType(std::string type, SocketIOPacket::SocketIOVersion version);
|
||||
static SocketIOPacket * createPacketWithTypeIndex(int type, SocketIOPacket::SocketIOVersion version);
|
||||
protected:
|
||||
std::string _pId;//id message
|
||||
std::string _ack;//
|
||||
std::string _name;//event name
|
||||
std::vector<std::string> _args;//we will be using a vector of strings to store multiple data
|
||||
std::string _endpoint;//
|
||||
std::string _endpointseperator;//socket.io 1.x requires a ',' between endpoint and payload
|
||||
std::string _type;//message type
|
||||
std::string _separator;//for stringify the object
|
||||
std::vector<std::string> _types;//types of messages
|
||||
};
|
||||
|
||||
class SocketIOPacketV10x : public SocketIOPacket
|
||||
{
|
||||
public:
|
||||
SocketIOPacketV10x();
|
||||
virtual ~SocketIOPacketV10x();
|
||||
int typeAsNumber();
|
||||
std::string stringify();
|
||||
private:
|
||||
std::vector<std::string> _typesMessage;
|
||||
};
|
||||
|
||||
SocketIOPacket::SocketIOPacket()
|
||||
{
|
||||
_type = "";//message type
|
||||
_separator = ":";//for stringify the object
|
||||
_endpointseperator = "";//socket.io 1.x requires a ',' between endpoint and payload
|
||||
_pId = "";//id message
|
||||
_ack = "";//
|
||||
_name = "";//event name
|
||||
_endpoint = "";//
|
||||
_types.push_back("disconnect");
|
||||
_types.push_back("connect");
|
||||
_types.push_back("heartbeat");
|
||||
_types.push_back("message");
|
||||
_types.push_back("json");
|
||||
_types.push_back("event");
|
||||
_types.push_back("ack");
|
||||
_types.push_back("error");
|
||||
_types.push_back("noop");
|
||||
}
|
||||
|
||||
SocketIOPacket::~SocketIOPacket()
|
||||
{
|
||||
_types.clear();
|
||||
_type = "";
|
||||
_pId = "";
|
||||
_name = "";
|
||||
_ack = "";
|
||||
_endpoint = "";
|
||||
}
|
||||
|
||||
void SocketIOPacket::initWithType(std::string packetType)
|
||||
{
|
||||
_type = packetType;
|
||||
}
|
||||
void SocketIOPacket::initWithTypeIndex(int index)
|
||||
{
|
||||
_type = _types.at(index);
|
||||
}
|
||||
|
||||
std::string SocketIOPacket::toString()
|
||||
{
|
||||
std::stringstream encoded;
|
||||
encoded << this->typeAsNumber();
|
||||
encoded << this->_separator;
|
||||
|
||||
std::string pIdL = _pId;
|
||||
if (_ack == "data")
|
||||
{
|
||||
pIdL += "+";
|
||||
}
|
||||
|
||||
// Do not write pid for acknowledgements
|
||||
if (_type != "ack")
|
||||
{
|
||||
encoded << pIdL;
|
||||
}
|
||||
encoded << this->_separator;
|
||||
|
||||
// Add the endpoint for the namespace to be used if not the default namespace "" or "/", and as long as it is not an ACK, heartbeat, or disconnect packet
|
||||
if (_endpoint != "/" && _endpoint != "" && _type != "ack" && _type != "heartbeat" && _type != "disconnect") {
|
||||
encoded << _endpoint << _endpointseperator;
|
||||
}
|
||||
encoded << this->_separator;
|
||||
|
||||
|
||||
if (_args.size() != 0)
|
||||
{
|
||||
std::string ackpId = "";
|
||||
// This is an acknowledgement packet, so, prepend the ack pid to the data
|
||||
if (_type == "ack")
|
||||
{
|
||||
ackpId += pIdL + "+";
|
||||
}
|
||||
|
||||
encoded << ackpId << this->stringify();
|
||||
}
|
||||
|
||||
return encoded.str();
|
||||
}
|
||||
int SocketIOPacket::typeAsNumber()
|
||||
{
|
||||
int num = 0;
|
||||
std::vector<std::string>::iterator item = std::find(_types.begin(), _types.end(), _type);
|
||||
if (item != _types.end())
|
||||
{
|
||||
num = item - _types.begin();
|
||||
}
|
||||
return num;
|
||||
}
|
||||
std::string SocketIOPacket::typeForIndex(int index)
|
||||
{
|
||||
return _types.at(index);
|
||||
}
|
||||
|
||||
void SocketIOPacket::addData(std::string data)
|
||||
{
|
||||
|
||||
this->_args.push_back(data);
|
||||
|
||||
}
|
||||
|
||||
std::string SocketIOPacket::stringify()
|
||||
{
|
||||
|
||||
std::string outS;
|
||||
if (_type == "message") {
|
||||
outS = _args[0];
|
||||
}
|
||||
else {
|
||||
|
||||
rapidjson::StringBuffer s;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(s);
|
||||
|
||||
writer.StartObject();
|
||||
writer.String("name");
|
||||
writer.String(_name.c_str());
|
||||
|
||||
writer.String("args");
|
||||
|
||||
writer.StartArray();
|
||||
|
||||
for (int i = 0; i < _args.size(); i++) {
|
||||
writer.String(_args[i].c_str());
|
||||
}
|
||||
|
||||
writer.EndArray();
|
||||
writer.EndObject();
|
||||
|
||||
outS = s.GetString();
|
||||
|
||||
log("create args object: %s:", outS.c_str());
|
||||
}
|
||||
|
||||
return outS;
|
||||
}
|
||||
|
||||
SocketIOPacketV10x::SocketIOPacketV10x()
|
||||
{
|
||||
_separator = ":";
|
||||
_type = "";//message type
|
||||
_separator = "";//for stringify the object
|
||||
_endpointseperator = ",";
|
||||
_pId = "";//id message
|
||||
_ack = "";//
|
||||
_name = "";//event name
|
||||
_endpoint = "";//
|
||||
_types.push_back("disconnected");
|
||||
_types.push_back("connected");
|
||||
_types.push_back("heartbeat");
|
||||
_types.push_back("pong");
|
||||
_types.push_back("message");
|
||||
_types.push_back("upgrade");
|
||||
_types.push_back("noop");
|
||||
_typesMessage.push_back("connect");
|
||||
_typesMessage.push_back("disconnect");
|
||||
_typesMessage.push_back("event");
|
||||
_typesMessage.push_back("ack");
|
||||
_typesMessage.push_back("error");
|
||||
_typesMessage.push_back("binarevent");
|
||||
_typesMessage.push_back("binaryack");
|
||||
}
|
||||
|
||||
int SocketIOPacketV10x::typeAsNumber()
|
||||
{
|
||||
int num = 0;
|
||||
std::vector<std::string>::iterator item = std::find(_typesMessage.begin(), _typesMessage.end(), _type);
|
||||
if (item != _typesMessage.end())
|
||||
{//it's a message
|
||||
num = item - _typesMessage.begin();
|
||||
num += 40;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = std::find(_types.begin(), _types.end(), _type);
|
||||
num += item - _types.begin();
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
std::string SocketIOPacketV10x::stringify()
|
||||
{
|
||||
|
||||
std::string outS;
|
||||
|
||||
rapidjson::StringBuffer s;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(s);
|
||||
|
||||
writer.StartArray();
|
||||
writer.String(_name.c_str());
|
||||
|
||||
for (int i = 0; i < _args.size(); i++) {
|
||||
writer.String(_args[i].c_str());
|
||||
}
|
||||
|
||||
writer.EndArray();
|
||||
|
||||
outS = s.GetString();
|
||||
|
||||
log("create args object: %s:", outS.c_str());
|
||||
|
||||
return outS;
|
||||
|
||||
}
|
||||
|
||||
SocketIOPacketV10x::~SocketIOPacketV10x()
|
||||
{
|
||||
_types.clear();
|
||||
_typesMessage.clear();
|
||||
_type = "";
|
||||
_pId = "";
|
||||
_name = "";
|
||||
_ack = "";
|
||||
_endpoint = "";
|
||||
}
|
||||
|
||||
SocketIOPacket * SocketIOPacket::createPacketWithType(std::string type, SocketIOPacket::SocketIOVersion version)
|
||||
{
|
||||
SocketIOPacket *ret;
|
||||
switch (version)
|
||||
{
|
||||
case SocketIOPacket::V09x:
|
||||
ret = new SocketIOPacket;
|
||||
break;
|
||||
case SocketIOPacket::V10x:
|
||||
ret = new SocketIOPacketV10x;
|
||||
break;
|
||||
}
|
||||
ret->initWithType(type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
SocketIOPacket * SocketIOPacket::createPacketWithTypeIndex(int type, SocketIOPacket::SocketIOVersion version)
|
||||
{
|
||||
SocketIOPacket *ret;
|
||||
switch (version)
|
||||
{
|
||||
case SocketIOPacket::V09x:
|
||||
ret = new SocketIOPacket;
|
||||
break;
|
||||
case SocketIOPacket::V10x:
|
||||
return new SocketIOPacketV10x;
|
||||
break;
|
||||
}
|
||||
ret->initWithTypeIndex(type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The implementation of the socket.io connection
|
||||
* Clients/endpoints may share the same impl to accomplish multiplexing on the same websocket
|
||||
|
@ -54,6 +361,7 @@ private:
|
|||
int _port, _heartbeat, _timeout;
|
||||
std::string _host, _sid, _uri;
|
||||
bool _connected;
|
||||
SocketIOPacket::SocketIOVersion _version;
|
||||
|
||||
WebSocket *_ws;
|
||||
|
||||
|
@ -85,6 +393,7 @@ public:
|
|||
void disconnectFromEndpoint(const std::string& endpoint);
|
||||
|
||||
void send(std::string endpoint, std::string s);
|
||||
void send(SocketIOPacket *packet);
|
||||
void emit(std::string endpoint, std::string eventname, std::string args);
|
||||
|
||||
|
||||
|
@ -119,7 +428,7 @@ void SIOClientImpl::handshake()
|
|||
log("SIOClientImpl::handshake() called");
|
||||
|
||||
std::stringstream pre;
|
||||
pre << "http://" << _uri << "/socket.io/1";
|
||||
pre << "http://" << _uri << "/socket.io/1/?EIO=2&transport=polling&b64=true";
|
||||
|
||||
HttpRequest* request = new (std::nothrow) HttpRequest();
|
||||
request->setUrl(pre.str().c_str());
|
||||
|
@ -168,6 +477,7 @@ void SIOClientImpl::handshakeResponse(HttpClient *sender, HttpResponse *response
|
|||
|
||||
std::vector<char> *buffer = response->getResponseData();
|
||||
std::stringstream s;
|
||||
s.str("");
|
||||
|
||||
for (unsigned int i = 0; i < buffer->size(); i++)
|
||||
{
|
||||
|
@ -177,27 +487,76 @@ void SIOClientImpl::handshakeResponse(HttpClient *sender, HttpResponse *response
|
|||
log("SIOClientImpl::handshake() dump data: %s", s.str().c_str());
|
||||
|
||||
std::string res = s.str();
|
||||
std::string sid;
|
||||
size_t pos = 0;
|
||||
std::string sid = "";
|
||||
int heartbeat = 0, timeout = 0;
|
||||
|
||||
pos = res.find(":");
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
sid = res.substr(0, pos);
|
||||
res.erase(0, pos+1);
|
||||
}
|
||||
if (res.at(res.size() - 1) == '}') {
|
||||
|
||||
pos = res.find(":");
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
heartbeat = atoi(res.substr(pos+1, res.size()).c_str());
|
||||
}
|
||||
log("SIOClientImpl::handshake() Socket.IO 1.x detected");
|
||||
_version = SocketIOPacket::V10x;
|
||||
// sample: 97:0{"sid":"GMkL6lzCmgMvMs9bAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}
|
||||
|
||||
int a, b;
|
||||
a = res.find('{');
|
||||
std::string temp = res.substr(a, res.size() - a);
|
||||
|
||||
// find the sid
|
||||
a = temp.find(":");
|
||||
b = temp.find(",");
|
||||
|
||||
sid = temp.substr(a + 2, b - (a + 3));
|
||||
|
||||
temp = temp.erase(0, b + 1);
|
||||
|
||||
// chomp past the upgrades
|
||||
a = temp.find(":");
|
||||
b = temp.find(",");
|
||||
|
||||
temp = temp.erase(0, b + 1);
|
||||
|
||||
// get the pingInterval / heartbeat
|
||||
a = temp.find(":");
|
||||
b = temp.find(",");
|
||||
|
||||
std::string heartbeat_str = temp.substr(a + 1, b - a);
|
||||
heartbeat = atoi(heartbeat_str.c_str()) / 1000;
|
||||
temp = temp.erase(0, b + 1);
|
||||
|
||||
// get the timeout
|
||||
a = temp.find(":");
|
||||
b = temp.find("}");
|
||||
|
||||
std::string timeout_str = temp.substr(a + 1, b - a);
|
||||
timeout = atoi(timeout_str.c_str()) / 1000;
|
||||
log("done parsing 1.x");
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
log("SIOClientImpl::handshake() Socket.IO 0.9.x detected");
|
||||
_version = SocketIOPacket::V09x;
|
||||
// sample: 3GYzE9md2Ig-lm3cf8Rv:60:60:websocket,htmlfile,xhr-polling,jsonp-polling
|
||||
size_t pos = 0;
|
||||
|
||||
pos = res.find(":");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
sid = res.substr(0, pos);
|
||||
res.erase(0, pos + 1);
|
||||
}
|
||||
|
||||
pos = res.find(":");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
heartbeat = atoi(res.substr(pos + 1, res.size()).c_str());
|
||||
}
|
||||
|
||||
pos = res.find(":");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
timeout = atoi(res.substr(pos + 1, res.size()).c_str());
|
||||
}
|
||||
|
||||
pos = res.find(":");
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
timeout = atoi(res.substr(pos+1, res.size()).c_str());
|
||||
}
|
||||
|
||||
_sid = sid;
|
||||
|
@ -215,7 +574,16 @@ void SIOClientImpl::openSocket()
|
|||
log("SIOClientImpl::openSocket() called");
|
||||
|
||||
std::stringstream s;
|
||||
s << _uri << "/socket.io/1/websocket/" << _sid;
|
||||
|
||||
switch (_version)
|
||||
{
|
||||
case SocketIOPacket::V09x:
|
||||
s << _uri << "/socket.io/1/websocket/" << _sid;
|
||||
break;
|
||||
case SocketIOPacket::V10x:
|
||||
s << _uri << "/socket.io/1/websocket/?EIO=2&transport=websocket&sid=" << _sid;
|
||||
break;
|
||||
}
|
||||
|
||||
_ws = new (std::nothrow) WebSocket();
|
||||
if (!_ws->init(*this, s.str()))
|
||||
|
@ -241,17 +609,21 @@ void SIOClientImpl::disconnect()
|
|||
{
|
||||
if(_ws->getReadyState() == WebSocket::State::OPEN)
|
||||
{
|
||||
std::string s = "0::";
|
||||
std::string s, endpoint;
|
||||
s = "";
|
||||
endpoint = "";
|
||||
|
||||
if (_version == SocketIOPacket::V09x)
|
||||
s = "0::" + endpoint;
|
||||
else
|
||||
s = "41" + endpoint;
|
||||
_ws->send(s);
|
||||
|
||||
log("Disconnect sent");
|
||||
|
||||
_ws->close();
|
||||
}
|
||||
|
||||
Director::getInstance()->getScheduler()->unscheduleAllForTarget(this);
|
||||
|
||||
_ws->close();
|
||||
|
||||
_connected = false;
|
||||
|
||||
SocketIO::getInstance()->removeSocket(_uri);
|
||||
|
@ -281,11 +653,9 @@ void SIOClientImpl::addClient(const std::string& endpoint, SIOClient* client)
|
|||
|
||||
void SIOClientImpl::connectToEndpoint(const std::string& endpoint)
|
||||
{
|
||||
std::string path = endpoint == "/" ? "" : endpoint;
|
||||
|
||||
std::string s = "1::" + path;
|
||||
|
||||
_ws->send(s);
|
||||
SocketIOPacket *packet = SocketIOPacket::createPacketWithType("connect", _version);
|
||||
packet->setEndpoint(endpoint);
|
||||
this->send(packet);
|
||||
}
|
||||
|
||||
void SIOClientImpl::disconnectFromEndpoint(const std::string& endpoint)
|
||||
|
@ -296,7 +666,7 @@ void SIOClientImpl::disconnectFromEndpoint(const std::string& endpoint)
|
|||
{
|
||||
log("SIOClientImpl::disconnectFromEndpoint out of endpoints, checking for disconnect");
|
||||
|
||||
if(_connected)
|
||||
if (_connected)
|
||||
this->disconnect();
|
||||
}
|
||||
else
|
||||
|
@ -311,9 +681,9 @@ void SIOClientImpl::disconnectFromEndpoint(const std::string& endpoint)
|
|||
|
||||
void SIOClientImpl::heartbeat(float dt)
|
||||
{
|
||||
std::string s = "2::";
|
||||
SocketIOPacket *packet = SocketIOPacket::createPacketWithType("heartbeat", _version);
|
||||
|
||||
_ws->send(s);
|
||||
this->send(packet);
|
||||
|
||||
log("Heartbeat sent");
|
||||
}
|
||||
|
@ -321,32 +691,43 @@ void SIOClientImpl::heartbeat(float dt)
|
|||
|
||||
void SIOClientImpl::send(std::string endpoint, std::string s)
|
||||
{
|
||||
std::stringstream pre;
|
||||
switch (_version) {
|
||||
case SocketIOPacket::V09x:
|
||||
{
|
||||
SocketIOPacket *packet = SocketIOPacket::createPacketWithType("message", _version);
|
||||
packet->setEndpoint(endpoint);
|
||||
packet->addData(s);
|
||||
this->send(packet);
|
||||
break;
|
||||
}
|
||||
case SocketIOPacket::V10x:
|
||||
{
|
||||
this->emit(endpoint, "message", s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string path = endpoint == "/" ? "" : endpoint;
|
||||
|
||||
pre << "3::" << path << ":" << s;
|
||||
|
||||
std::string msg = pre.str();
|
||||
|
||||
log("sending message: %s", msg.c_str());
|
||||
|
||||
_ws->send(msg);
|
||||
void SIOClientImpl::send(SocketIOPacket *packet)
|
||||
{
|
||||
std::string req = packet->toString();
|
||||
if (_connected)
|
||||
{
|
||||
log("-->SEND:%s", req.data());
|
||||
_ws->send(req.data());
|
||||
}
|
||||
else
|
||||
log("Cant send the message (%s) because disconnected", req);
|
||||
}
|
||||
|
||||
void SIOClientImpl::emit(std::string endpoint, std::string eventname, std::string args)
|
||||
{
|
||||
std::stringstream pre;
|
||||
|
||||
std::string path = endpoint == "/" ? "" : endpoint;
|
||||
|
||||
pre << "5::" << path << ":{\"name\":\"" << eventname << "\",\"args\":" << args << "}";
|
||||
|
||||
std::string msg = pre.str();
|
||||
|
||||
log("emitting event with data: %s", msg.c_str());
|
||||
|
||||
_ws->send(msg);
|
||||
log("Emitting event \"%s\"", eventname);
|
||||
SocketIOPacket *packet = SocketIOPacket::createPacketWithType("event", _version);
|
||||
packet->setEndpoint(endpoint == "/" ? "" : endpoint);
|
||||
packet->setEvent(eventname);
|
||||
packet->addData(args);
|
||||
this->send(packet);
|
||||
}
|
||||
|
||||
void SIOClientImpl::onOpen(WebSocket* ws)
|
||||
|
@ -355,13 +736,19 @@ void SIOClientImpl::onOpen(WebSocket* ws)
|
|||
|
||||
SocketIO::getInstance()->addSocket(_uri, this);
|
||||
|
||||
if (_version == SocketIOPacket::V10x)
|
||||
{
|
||||
std::string s = "5";//That's a ping https://github.com/Automattic/engine.io-parser/blob/1b8e077b2218f4947a69f5ad18be2a512ed54e93/lib/index.js#L21
|
||||
_ws->send(s.data());
|
||||
}
|
||||
|
||||
Director::getInstance()->getScheduler()->schedule(CC_SCHEDULE_SELECTOR(SIOClientImpl::heartbeat), this, (_heartbeat * .9f), false);
|
||||
|
||||
for (auto iter = _clients.begin(); iter != _clients.end(); ++iter)
|
||||
{
|
||||
iter->second->onOpen();
|
||||
}
|
||||
|
||||
Director::getInstance()->getScheduler()->schedule(CC_SCHEDULE_SELECTOR(SIOClientImpl::heartbeat), this, (_heartbeat * .9f), false);
|
||||
|
||||
log("SIOClientImpl::onOpen socket connected!");
|
||||
}
|
||||
|
||||
|
@ -369,94 +756,223 @@ void SIOClientImpl::onMessage(WebSocket* ws, const WebSocket::Data& data)
|
|||
{
|
||||
log("SIOClientImpl::onMessage received: %s", data.bytes);
|
||||
|
||||
int control = atoi(&data.bytes[0]);
|
||||
std::string payload = data.bytes;
|
||||
int control = atoi(payload.substr(0, 1).c_str());
|
||||
payload = payload.substr(1, payload.size() - 1);
|
||||
|
||||
std::string payload, msgid, endpoint, s_data, eventname;
|
||||
payload = data.bytes;
|
||||
|
||||
size_t pos, pos2;
|
||||
|
||||
pos = payload.find(":");
|
||||
if(pos != std::string::npos ) {
|
||||
payload.erase(0, pos+1);
|
||||
}
|
||||
|
||||
pos = payload.find(":");
|
||||
if(pos != std::string::npos ) {
|
||||
msgid = atoi(payload.substr(0, pos+1).c_str());
|
||||
}
|
||||
payload.erase(0, pos+1);
|
||||
|
||||
pos = payload.find(":");
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
endpoint = payload.substr(0, pos);
|
||||
payload.erase(0, pos+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = payload;
|
||||
}
|
||||
|
||||
if (endpoint == "") endpoint = "/";
|
||||
|
||||
|
||||
s_data = payload;
|
||||
SIOClient *c = nullptr;
|
||||
c = getClient(endpoint);
|
||||
if (c == nullptr) log("SIOClientImpl::onMessage client lookup returned nullptr");
|
||||
|
||||
switch(control)
|
||||
switch (_version)
|
||||
{
|
||||
case 0:
|
||||
log("Received Disconnect Signal for Endpoint: %s\n", endpoint.c_str());
|
||||
if(c) c->receivedDisconnect();
|
||||
disconnectFromEndpoint(endpoint);
|
||||
break;
|
||||
case 1:
|
||||
log("Connected to endpoint: %s \n",endpoint.c_str());
|
||||
if(c) c->onConnect();
|
||||
break;
|
||||
case 2:
|
||||
log("Heartbeat received\n");
|
||||
break;
|
||||
case 3:
|
||||
log("Message received: %s \n", s_data.c_str());
|
||||
if(c) c->getDelegate()->onMessage(c, s_data);
|
||||
break;
|
||||
case 4:
|
||||
log("JSON Message Received: %s \n", s_data.c_str());
|
||||
if(c) c->getDelegate()->onMessage(c, s_data);
|
||||
break;
|
||||
case 5:
|
||||
log("Event Received with data: %s \n", s_data.c_str());
|
||||
case SocketIOPacket::V09x:
|
||||
{
|
||||
std::string msgid, endpoint, s_data, eventname;
|
||||
|
||||
if(c)
|
||||
{
|
||||
eventname = "";
|
||||
pos = s_data.find(":");
|
||||
pos2 = s_data.find(",");
|
||||
if(pos2 > pos)
|
||||
{
|
||||
s_data = s_data.substr(pos+1, pos2-pos-1);
|
||||
std::remove_copy(s_data.begin(), s_data.end(),
|
||||
std::back_inserter(eventname), '"');
|
||||
}
|
||||
size_t pos, pos2;
|
||||
|
||||
c->fireEvent(eventname, payload);
|
||||
pos = payload.find(":");
|
||||
if (pos != std::string::npos) {
|
||||
payload.erase(0, pos + 1);
|
||||
}
|
||||
|
||||
pos = payload.find(":");
|
||||
if (pos != std::string::npos) {
|
||||
msgid = atoi(payload.substr(0, pos + 1).c_str());
|
||||
}
|
||||
payload.erase(0, pos + 1);
|
||||
|
||||
pos = payload.find(":");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
endpoint = payload.substr(0, pos);
|
||||
payload.erase(0, pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = payload;
|
||||
}
|
||||
|
||||
if (endpoint == "") endpoint = "/";
|
||||
|
||||
c = getClient(endpoint);
|
||||
|
||||
s_data = payload;
|
||||
|
||||
if (c == nullptr) log("SIOClientImpl::onMessage client lookup returned nullptr");
|
||||
|
||||
switch (control)
|
||||
{
|
||||
case 0:
|
||||
log("Received Disconnect Signal for Endpoint: %s\n", endpoint.c_str());
|
||||
disconnectFromEndpoint(endpoint);
|
||||
c->fireEvent("disconnect", payload);
|
||||
break;
|
||||
case 1:
|
||||
log("Connected to endpoint: %s \n", endpoint.c_str());
|
||||
if (c) {
|
||||
c->onConnect();
|
||||
c->fireEvent("connect", payload);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
log("Heartbeat received\n");
|
||||
break;
|
||||
case 3:
|
||||
log("Message received: %s \n", s_data.c_str());
|
||||
if (c) c->getDelegate()->onMessage(c, s_data);
|
||||
if (c) c->fireEvent("message", s_data);
|
||||
break;
|
||||
case 4:
|
||||
log("JSON Message Received: %s \n", s_data.c_str());
|
||||
if (c) c->getDelegate()->onMessage(c, s_data);
|
||||
if (c) c->fireEvent("json", s_data);
|
||||
break;
|
||||
case 5:
|
||||
log("Event Received with data: %s \n", s_data.c_str());
|
||||
|
||||
if (c)
|
||||
{
|
||||
eventname = "";
|
||||
pos = s_data.find(":");
|
||||
pos2 = s_data.find(",");
|
||||
if (pos2 > pos)
|
||||
{
|
||||
eventname = s_data.substr(pos + 2, pos2 - (pos + 3));
|
||||
s_data = s_data.substr(pos2 + 9, s_data.size() - (pos2 + 11));
|
||||
}
|
||||
|
||||
c->fireEvent(eventname, s_data);
|
||||
}
|
||||
|
||||
break;
|
||||
case 6:
|
||||
log("Message Ack\n");
|
||||
break;
|
||||
case 7:
|
||||
log("Error\n");
|
||||
//if (c) c->getDelegate()->onError(c, s_data);
|
||||
if (c) c->fireEvent("error", s_data);
|
||||
break;
|
||||
case 8:
|
||||
log("Noop\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SocketIOPacket::V10x:
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
case 0:
|
||||
log("Not supposed to receive control 0 for websocket");
|
||||
log("That's not good");
|
||||
break;
|
||||
case 1:
|
||||
log("Not supposed to receive control 1 for websocket");
|
||||
break;
|
||||
case 2:
|
||||
log("Ping received, send pong");
|
||||
payload = "3" + payload;
|
||||
_ws->send(payload.c_str());
|
||||
break;
|
||||
case 3:
|
||||
log("Pong received");
|
||||
if (payload == "probe")
|
||||
{
|
||||
log("Request Update");
|
||||
_ws->send("5");
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
|
||||
const char second = payload.at(0);
|
||||
int control2 = atoi(&second);
|
||||
log("Message code: [%i]", control);
|
||||
|
||||
SocketIOPacket *packetOut = SocketIOPacket::createPacketWithType("event", _version);
|
||||
std::string endpoint = "";
|
||||
|
||||
int a = payload.find("/");
|
||||
int b = payload.find("[");
|
||||
|
||||
if (b != std::string::npos) {
|
||||
if (a != std::string::npos && a < b) {
|
||||
//we have an endpoint and a payload
|
||||
endpoint = payload.substr(a, b - (a + 1));
|
||||
}
|
||||
}
|
||||
else if (a != std::string::npos) {
|
||||
//we have an endpoint with no payload
|
||||
endpoint = payload.substr(a, payload.size() - a);
|
||||
}
|
||||
|
||||
// we didn't find and endpoint and we are in the default namespace
|
||||
if (endpoint == "") endpoint = "/";
|
||||
|
||||
packetOut->setEndpoint(endpoint);
|
||||
|
||||
c = getClient(endpoint);
|
||||
|
||||
payload = payload.substr(1);
|
||||
|
||||
if (endpoint != "/") payload = payload.substr(endpoint.size());
|
||||
if (endpoint != "/" && payload != "") payload = payload.substr(1);
|
||||
|
||||
switch (control2)
|
||||
{
|
||||
case 0:
|
||||
log("Socket Connected");
|
||||
if (c) {
|
||||
c->onConnect();
|
||||
c->fireEvent("connect", payload);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
log("Socket Disconnected");
|
||||
disconnectFromEndpoint(endpoint);
|
||||
c->fireEvent("disconnect", payload);
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
log("Event Received (%s)", payload.c_str());
|
||||
|
||||
int a = payload.find("\"");
|
||||
int b = payload.substr(a + 1).find("\"");
|
||||
|
||||
std::string eventname = payload.substr(a + 1, b - a + 1);
|
||||
log("event name %s between %i and %i", eventname.c_str(), a, b);
|
||||
|
||||
payload = payload.substr(b + 4, payload.size() - (b + 5));
|
||||
|
||||
if (c) c->fireEvent(eventname, payload);
|
||||
if (c) c->getDelegate()->onMessage(c, payload);
|
||||
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
log("Message Ack");
|
||||
break;
|
||||
case 4:
|
||||
log("Error");
|
||||
if (c) c->fireEvent("error", payload);
|
||||
break;
|
||||
case 5:
|
||||
log("Binary Event");
|
||||
break;
|
||||
case 6:
|
||||
log("Binary Ack");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
log("Upgrade required");
|
||||
break;
|
||||
case 6:
|
||||
log("Message Ack\n");
|
||||
break;
|
||||
case 7:
|
||||
log("Error\n");
|
||||
if(c) c->getDelegate()->onError(c, s_data);
|
||||
break;
|
||||
case 8:
|
||||
log("Noop\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -468,7 +984,7 @@ void SIOClientImpl::onClose(WebSocket* ws)
|
|||
{
|
||||
for (auto iter = _clients.begin(); iter != _clients.end(); ++iter)
|
||||
{
|
||||
iter->second->receivedDisconnect();
|
||||
iter->second->socketClosed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,6 +993,7 @@ void SIOClientImpl::onClose(WebSocket* ws)
|
|||
|
||||
void SIOClientImpl::onError(WebSocket* ws, const WebSocket::ErrorCode& error)
|
||||
{
|
||||
log("Websocket error received: %s", error);
|
||||
}
|
||||
|
||||
//begin SIOClient methods
|
||||
|
@ -510,7 +1027,6 @@ void SIOClient::onOpen()
|
|||
void SIOClient::onConnect()
|
||||
{
|
||||
_connected = true;
|
||||
_delegate->onConnect(this);
|
||||
}
|
||||
|
||||
void SIOClient::send(std::string s)
|
||||
|
@ -545,12 +1061,10 @@ void SIOClient::disconnect()
|
|||
|
||||
_socket->disconnectFromEndpoint(_path);
|
||||
|
||||
_delegate->onClose(this);
|
||||
|
||||
this->release();
|
||||
}
|
||||
|
||||
void SIOClient::receivedDisconnect()
|
||||
void SIOClient::socketClosed()
|
||||
{
|
||||
_connected = false;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2013 Chris Hannon http://www.channon.us
|
||||
Copyright (c) 2013-2014 Chukong Technologies Inc.
|
||||
Copyright (c) 2015 Chris Hannon http://www.channon.us
|
||||
Copyright (c) 2013-2015 Chukong Technologies Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -103,22 +103,22 @@ public:
|
|||
/** Destructor of SIODelegate. */
|
||||
virtual ~SIODelegate() {}
|
||||
/**
|
||||
* Pure virtual callback function, this function should be overrided by the subclass.
|
||||
* This is kept for backwards compatibility, connect is now fired as a socket.io event "connect"
|
||||
*
|
||||
* This function would be called when the related SIOClient object recevie messages that mean it have connected to endpoint sucessfully.
|
||||
*
|
||||
* @param client the connected SIOClient object.
|
||||
*/
|
||||
virtual void onConnect(SIOClient* client) = 0;
|
||||
virtual void onConnect(SIOClient* client) { CCLOG("SIODelegate onConnect fired"); };
|
||||
/**
|
||||
* Pure virtual callback function, this function should be overrided by the subclass.
|
||||
* This is kept for backwards compatibility, message is now fired as a socket.io event "message"
|
||||
*
|
||||
* This function would be called wwhen the related SIOClient object recevie message or json message.
|
||||
*
|
||||
* @param client the connected SIOClient object.
|
||||
* @param data the message,it could be json message
|
||||
*/
|
||||
virtual void onMessage(SIOClient* client, const std::string& data) = 0;
|
||||
virtual void onMessage(SIOClient* client, const std::string& data) { CCLOG("SIODelegate onMessage fired with data: %s", data.c_str()); };
|
||||
/**
|
||||
* Pure virtual callback function, this function should be overrided by the subclass.
|
||||
*
|
||||
|
@ -207,7 +207,7 @@ private:
|
|||
|
||||
void onOpen();
|
||||
void onConnect();
|
||||
void receivedDisconnect();
|
||||
void socketClosed();
|
||||
|
||||
friend class SIOClientImpl;
|
||||
|
||||
|
|
Loading…
Reference in New Issue