Compare commits

...

6 Commits

Author SHA1 Message Date
Benjamin Sergeant
61e5f52286 - travis CI uses g++ on Linux 2019-06-09 14:27:45 -07:00
Benjamin Sergeant
ce0b716f54 compile error in IXWebSocketMessageQTest 2019-06-09 12:25:36 -07:00
Benjamin Sergeant
aae8e5ec65 fix IXWebSocketMessageQTest.cpp 2019-06-09 12:08:00 -07:00
Benjamin Sergeant
2723e8466e fix changelog 2019-06-09 12:02:38 -07:00
Benjamin Sergeant
f13c610352 update README to reflect the new API 2019-06-09 12:02:02 -07:00
Benjamin Sergeant
55c65b08bf - WebSocket::send() sends message in TEXT mode by default
- WebSocketMessage sets a new binary field, which tells whether the received incoming message is binary or text
2019-06-09 11:56:47 -07:00
14 changed files with 86 additions and 91 deletions

View File

@@ -12,23 +12,23 @@ matrix:
- python test/run.py - python test/run.py
- make ws - make ws
# # Linux # Linux
# - os: linux
# dist: xenial
# script:
# - python test/run.py
# - make ws
# env:
# - CC=gcc
# - CXX=g++
# Clang + Linux disabled for now
- os: linux - os: linux
dist: xenial dist: xenial
script: python test/run.py script:
- python test/run.py
- make ws
env: env:
- CC=clang - CC=gcc
- CXX=clang++ - CXX=g++
# Clang + Linux disabled for now
# - os: linux
# dist: xenial
# script: python test/run.py
# env:
# - CC=clang
# - CXX=clang++
# Windows # Windows
- os: windows - os: windows

View File

@@ -1,11 +1,17 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [Unreleased] - 2019-06-xx ## [unreleased] - 2019-06-09
### Changed ### Changed
- travis CI uses g++ on Linux
## [4.0.0] - 2019-06-09
### Changed
- WebSocket::send() sends message in TEXT mode by default
- WebSocketMessage sets a new binary field, which tells whether the received incoming message is binary or text
- WebSocket::send takes a third arg, binary which default to true (can be text too) - WebSocket::send takes a third arg, binary which default to true (can be text too)
- WebSocket callback only take one object, a const ix::WebSocketMessagePtr& msg - WebSocket callback only take one object, a const ix::WebSocketMessagePtr& msg
- Add explicite WebSocket::sendBinary - Add explicit WebSocket::sendBinary method
- New headers + WebSocketMessage class to hold message data, still not used across the board - New headers + WebSocketMessage class to hold message data, still not used across the board
- Add test/compatibility folder with small servers and clients written in different languages and different libraries to test compatibility. - Add test/compatibility folder with small servers and clients written in different languages and different libraries to test compatibility.
- ws echo_server has a -g option to print a greeting message on connect - ws echo_server has a -g option to print a greeting message on connect

View File

@@ -1 +1 @@
3.1.2 4.0.0

View File

@@ -33,27 +33,22 @@ webSocket.disablePerMessageDeflate();
// Setup a callback to be fired when a message or an event (open, close, error) is received // Setup a callback to be fired when a message or an event (open, close, error) is received
webSocket.setOnMessageCallback( webSocket.setOnMessageCallback(
[](ix::WebSocketMessageType messageType, [](const ix::WebSocketMessagePtr& msg)
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{ {
if (messageType == ix::WebSocketMessageType::Message) if (msg->type == ix::WebSocketMessageType::Message)
{ {
std::cout << str << std::endl; std::cout << msg->str << std::endl;
} }
}); });
// Now that our callback is setup, we can start our background thread and receive messages // Now that our callback is setup, we can start our background thread and receive messages
webSocket.start(); webSocket.start();
// Send a message to the server (default to BINARY mode) // Send a message to the server (default to TEXT mode)
webSocket.send("hello world"); webSocket.send("hello world");
// The message can be sent in TEXT mode // The message can be sent in BINARY mode (useful if you send MsgPack data for example)
webSocket.sendText("hello again"); webSocket.sendBinary("some serialized binary data");
// ... finally ... // ... finally ...
@@ -73,14 +68,9 @@ server.setOnConnectionCallback(
std::shared_ptr<ConnectionState> connectionState) std::shared_ptr<ConnectionState> connectionState)
{ {
webSocket->setOnMessageCallback( webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](ix::WebSocketMessageType messageType, [webSocket, connectionState, &server](const ix::WebSocketMessagePtr msg)
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{ {
if (messageType == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
std::cerr << "New connection" << std::endl; std::cerr << "New connection" << std::endl;
@@ -91,19 +81,21 @@ server.setOnConnectionCallback(
std::cerr << "id: " << connectionState->getId() << std::endl; std::cerr << "id: " << connectionState->getId() << std::endl;
// The uri the client did connect to. // The uri the client did connect to.
std::cerr << "Uri: " << openInfo.uri << std::endl; std::cerr << "Uri: " << msg->openInfo.uri << std::endl;
std::cerr << "Headers:" << std::endl; std::cerr << "Headers:" << std::endl;
for (auto it : openInfo.headers) for (auto it : msg->openInfo.headers)
{ {
std::cerr << it.first << ": " << it.second << std::endl; std::cerr << it.first << ": " << it.second << std::endl;
} }
} }
else if (messageType == ix::WebSocketMessageType::Message) else if (msg->type == ix::WebSocketMessageType::Message)
{ {
// For an echo server, we just send back to the client whatever was received by the server // For an echo server, we just send back to the client whatever was received by the server
// All connected clients are available in an std::set. See the broadcast cpp example. // All connected clients are available in an std::set. See the broadcast cpp example.
webSocket->send(str); // Second parameter tells whether we are sending the message in binary or text mode.
// Here we send it in the same mode as it was received.
webSocket->send(msg->str, msg->binary);
} }
} }
); );
@@ -334,32 +326,27 @@ The onMessage event will be fired when the connection is opened or closed. This
``` ```
webSocket.setOnMessageCallback( webSocket.setOnMessageCallback(
[](ix::WebSocketMessageType messageType, [](const ix::WebSocketMessagePtr& msg)
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{ {
if (messageType == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
std::cout << "send greetings" << std::endl; std::cout << "send greetings" << std::endl;
// Headers can be inspected (pairs of string/string) // Headers can be inspected (pairs of string/string)
std::cout << "Handshake Headers:" << std::endl; std::cout << "Handshake Headers:" << std::endl;
for (auto it : headers) for (auto it : msg->headers)
{ {
std::cout << it.first << ": " << it.second << std::endl; std::cout << it.first << ": " << it.second << std::endl;
} }
} }
else if (messageType == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
std::cout << "disconnected" << std::endl; std::cout << "disconnected" << std::endl;
// The server can send an explicit code and reason for closing. // The server can send an explicit code and reason for closing.
// This data can be accessed through the closeInfo object. // This data can be accessed through the closeInfo object.
std::cout << closeInfo.code << std::endl; std::cout << msg->closeInfo.code << std::endl;
std::cout << closeInfo.reason << std::endl; std::cout << msg->closeInfo.reason << std::endl;
} }
} }
); );
@@ -371,20 +358,15 @@ A message will be fired when there is an error with the connection. The message
``` ```
webSocket.setOnMessageCallback( webSocket.setOnMessageCallback(
[](ix::WebSocketMessageType messageType, [](const ix::WebSocketMessagePtr& msg)
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{ {
if (messageType == ix::WebSocketMessageType::Error) if (msg->type == ix::WebSocketMessageType::Error)
{ {
std::stringstream ss; std::stringstream ss;
ss << "Error: " << error.reason << std::endl; ss << "Error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << event.retries << std::endl; ss << "#retries: " << msg->eventInfo.retries << std::endl;
ss << "Wait time(ms): " << event.wait_time << std::endl; ss << "Wait time(ms): " << msg->eventInfo.wait_time << std::endl;
ss << "HTTP Status: " << event.http_status << std::endl; ss << "HTTP Status: " << msg->eventInfo.http_status << std::endl;
std::cout << ss.str() << std::endl; std::cout << ss.str() << std::endl;
} }
} }
@@ -411,17 +393,12 @@ Ping/pong messages are used to implement keep-alive. 2 message types exists to i
``` ```
webSocket.setOnMessageCallback( webSocket.setOnMessageCallback(
[](ix::WebSocketMessageType messageType, [](const ix::WebSocketMessagePtr& msg)
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{ {
if (messageType == ix::WebSocketMessageType::Ping || if (msg->type == ix::WebSocketMessageType::Ping ||
messageType == ix::WebSocketMessageType::Pong) msg->type == ix::WebSocketMessageType::Pong)
{ {
std::cout << "pong data: " << str << std::endl; std::cout << "pong data: " << msg->str << std::endl;
} }
} }
); );

View File

@@ -325,8 +325,8 @@ namespace ix
WebSocketMessageType webSocketMessageType; WebSocketMessageType webSocketMessageType;
switch (messageKind) switch (messageKind)
{ {
default: case WebSocketTransport::MessageKind::MSG_TEXT:
case WebSocketTransport::MessageKind::MSG: case WebSocketTransport::MessageKind::MSG_BINARY:
{ {
webSocketMessageType = WebSocketMessageType::Message; webSocketMessageType = WebSocketMessageType::Message;
} break; } break;
@@ -350,11 +350,13 @@ namespace ix
WebSocketErrorInfo webSocketErrorInfo; WebSocketErrorInfo webSocketErrorInfo;
webSocketErrorInfo.decompressionError = decompressionError; webSocketErrorInfo.decompressionError = decompressionError;
bool binary = messageKind == WebSocketTransport::MessageKind::MSG_BINARY;
_onMessageCallback( _onMessageCallback(
std::make_shared<WebSocketMessage>( std::make_shared<WebSocketMessage>(
webSocketMessageType, msg, wireSize, webSocketMessageType, msg, wireSize,
webSocketErrorInfo, WebSocketOpenInfo(), webSocketErrorInfo, WebSocketOpenInfo(),
WebSocketCloseInfo())); WebSocketCloseInfo(), binary));
WebSocket::invokeTrafficTrackerCallback(msg.size(), true); WebSocket::invokeTrafficTrackerCallback(msg.size(), true);
}); });
@@ -385,8 +387,8 @@ namespace ix
} }
WebSocketSendInfo WebSocket::send(const std::string& data, WebSocketSendInfo WebSocket::send(const std::string& data,
const OnProgressCallback& onProgressCallback, bool binary,
bool binary) const OnProgressCallback& onProgressCallback)
{ {
return sendMessage(data, return sendMessage(data,
(binary) ? SendMessageKind::Binary: SendMessageKind::Text, (binary) ? SendMessageKind::Binary: SendMessageKind::Text,

View File

@@ -66,8 +66,8 @@ namespace ix
// send is in binary mode by default // send is in binary mode by default
WebSocketSendInfo send(const std::string& data, WebSocketSendInfo send(const std::string& data,
const OnProgressCallback& onProgressCallback = nullptr, bool binary = false,
bool binary = true); const OnProgressCallback& onProgressCallback = nullptr);
WebSocketSendInfo sendBinary(const std::string& text, WebSocketSendInfo sendBinary(const std::string& text,
const OnProgressCallback& onProgressCallback = nullptr); const OnProgressCallback& onProgressCallback = nullptr);
WebSocketSendInfo sendText(const std::string& text, WebSocketSendInfo sendText(const std::string& text,

View File

@@ -31,13 +31,15 @@ namespace ix
size_t w, size_t w,
WebSocketErrorInfo e, WebSocketErrorInfo e,
WebSocketOpenInfo o, WebSocketOpenInfo o,
WebSocketCloseInfo c) WebSocketCloseInfo c,
bool b = false)
: type(t) : type(t)
, str(std::move(s)) , str(std::move(s))
, wireSize(w) , wireSize(w)
, errorInfo(e) , errorInfo(e)
, openInfo(o) , openInfo(o)
, closeInfo(c) , closeInfo(c)
, binary(b)
{ {
; ;
} }

View File

@@ -542,12 +542,17 @@ namespace ix
) { ) {
unmaskReceiveBuffer(ws); unmaskReceiveBuffer(ws);
MessageKind messageKind =
(ws.opcode == wsheader_type::TEXT_FRAME)
? MessageKind::MSG_TEXT
: MessageKind::MSG_BINARY;
// //
// Usual case. Small unfragmented messages // Usual case. Small unfragmented messages
// //
if (ws.fin && _chunks.empty()) if (ws.fin && _chunks.empty())
{ {
emitMessage(MessageKind::MSG, emitMessage(messageKind,
std::string(_rxbuf.begin()+ws.header_size, std::string(_rxbuf.begin()+ws.header_size,
_rxbuf.begin()+ws.header_size+(size_t) ws.N), _rxbuf.begin()+ws.header_size+(size_t) ws.N),
ws, ws,
@@ -567,7 +572,7 @@ namespace ix
_rxbuf.begin()+ws.header_size+(size_t)ws.N)); _rxbuf.begin()+ws.header_size+(size_t)ws.N));
if (ws.fin) if (ws.fin)
{ {
emitMessage(MessageKind::MSG, getMergedChunks(), ws, onMessageCallback); emitMessage(messageKind, getMergedChunks(), ws, onMessageCallback);
_chunks.clear(); _chunks.clear();
} }
else else

View File

@@ -50,7 +50,8 @@ namespace ix
enum class MessageKind enum class MessageKind
{ {
MSG, MSG_TEXT,
MSG_BINARY,
PING, PING,
PONG, PONG,
FRAGMENT FRAGMENT

View File

@@ -200,7 +200,7 @@ namespace ix
{ {
if (client != webSocket) if (client != webSocket)
{ {
client->send(msg->str); client->send(msg->str, msg->binary);
} }
} }
} }

View File

@@ -30,7 +30,7 @@ namespace
Logger() << "New connection"; Logger() << "New connection";
connectionState->computeId(); connectionState->computeId();
Logger() << "id: " << connectionState->getId(); Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << openInfo.uri; Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:"; Logger() << "Headers:";
for (auto&& it : msg->openInfo.headers) for (auto&& it : msg->openInfo.headers)
{ {
@@ -43,11 +43,11 @@ namespace
} }
else if (msg->type == ix::WebSocketMessageType::Message) else if (msg->type == ix::WebSocketMessageType::Message)
{ {
Logger() << "Message received: " << str; Logger() << "Message received: " << msg->str;
for (auto&& client : server.getClients()) for (auto&& client : server.getClients())
{ {
client->send(str); client->send(msg->str);
} }
} }
} }
@@ -89,25 +89,25 @@ namespace
} }
else if (msg->type == WebSocketMessageType::Error) else if (msg->type == WebSocketMessageType::Error)
{ {
ss << "Error ! " << error.reason; ss << "Error ! " << msg->errorInfo.reason;
log(ss.str()); log(ss.str());
testDone = true; testDone = true;
} }
else if (msg->type == WebSocketMessageType::Pong) else if (msg->type == WebSocketMessageType::Pong)
{ {
ss << "Received pong message " << str; ss << "Received pong message " << msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == WebSocketMessageType::Ping) else if (msg->type == WebSocketMessageType::Ping)
{ {
ss << "Received ping message " << str; ss << "Received ping message " << msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == WebSocketMessageType::Message) else if (msg->type == WebSocketMessageType::Message)
{ {
REQUIRE(str.compare("Hey dude!") == 0); REQUIRE(msg->str.compare("Hey dude!") == 0);
++receivedCount; ++receivedCount;
ss << "Received message " << str; ss << "Received message " << msg->str;
log(ss.str()); log(ss.str());
sendNextMessage(); sendNextMessage();
} }

View File

@@ -62,6 +62,7 @@ namespace ix
if (client != webSocket) if (client != webSocket)
{ {
client->send(msg->str, client->send(msg->str,
msg->binary,
[](int current, int total) -> bool [](int current, int total) -> bool
{ {
std::cerr << "Step " << current std::cerr << "Step " << current

View File

@@ -59,7 +59,7 @@ namespace ix
std::cerr << "Received " std::cerr << "Received "
<< msg->wireSize << " bytes" << msg->wireSize << " bytes"
<< std::endl; << std::endl;
webSocket->send(msg->str); webSocket->send(msg->str, msg->binary);
} }
} }
); );

View File

@@ -62,6 +62,7 @@ namespace ix
if (client != webSocket) if (client != webSocket)
{ {
client->send(msg->str, client->send(msg->str,
msg->binary,
[](int current, int total) -> bool [](int current, int total) -> bool
{ {
std::cerr << "ws_transfer: Step " << current std::cerr << "ws_transfer: Step " << current