Compare commits

..

5 Commits

14 changed files with 152 additions and 144 deletions

View File

@ -5,7 +5,7 @@ include(FindPackageHandleStandardArgs)
find_path(DEFLATE_INCLUDE_DIRS libdeflate.h)
find_library(DEFLATE_LIBRARY deflate)
find_package_handle_standard_args(DEFLATE
find_package_handle_standard_args(Deflate
FOUND_VAR
DEFLATE_FOUND
REQUIRED_VARS

View File

@ -203,7 +203,7 @@ if (USE_ZLIB)
endif()
# brew install libdeflate
find_package(DEFLATE)
find_package(Deflate)
if (DEFLATE_FOUND)
include_directories(${DEFLATE_INCLUDE_DIRS})
target_link_libraries(ixwebsocket ${DEFLATE_LIBRARIES})
@ -264,7 +264,8 @@ if (USE_WS OR USE_TEST)
include(FetchContent)
FetchContent_Declare(spdlog
GIT_REPOSITORY "https://github.com/gabime/spdlog"
GIT_TAG "v1.8.0")
GIT_TAG "v1.8.0"
GIT_SHALLOW 1)
FetchContent_MakeAvailable(spdlog)

View File

@ -84,6 +84,7 @@ If your company or project is using this library, feel free to open an issue or
- [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), an easy to use Discord-bot framework.
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
- [discord.cpp](https://github.com/luccanunes/discord.cpp), a discord library for making bots
## Continuous Integration

View File

@ -2,6 +2,18 @@
All changes to this project will be documented in this file.
## [10.5.6] - 2020-11-07
(cmake) DEFLATE -> Deflate in CMake to stop warnings about casing
## [10.5.5] - 2020-11-07
(ws autoroute) Display result in compliant way (AUTOROUTE IXWebSocket :: N ms) so that result can be parsed easily
## [10.5.4] - 2020-10-30
(ws gunzip + IXGZipCodec) Can decompress gziped data with libdeflate. ws gunzip computed output filename was incorrect (was the extension aka gz) instead of the file without the extension. Also check whether the output file is writeable.
## [10.5.3] - 2020-10-19
(http code) With zlib disabled, some code should not be reached

View File

@ -102,8 +102,36 @@ namespace ix
#endif
}
#ifdef IXWEBSOCKET_USE_DEFLATE
static uint32_t loadDecompressedGzipSize(const uint8_t* p)
{
return ((uint32_t) p[0] << 0) | ((uint32_t) p[1] << 8) | ((uint32_t) p[2] << 16) |
((uint32_t) p[3] << 24);
}
#endif
bool gzipDecompress(const std::string& in, std::string& out)
{
#ifdef IXWEBSOCKET_USE_DEFLATE
struct libdeflate_decompressor* decompressor;
decompressor = libdeflate_alloc_decompressor();
const void* compressed_data = in.data();
size_t compressed_size = in.size();
// Retrieve uncompressed size from the trailer of the gziped data
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&in.front());
auto uncompressed_size = loadDecompressedGzipSize(&ptr[compressed_size - 4]);
// Use it to redimension our output buffer
out.resize(uncompressed_size);
libdeflate_result result = libdeflate_gzip_decompress(
decompressor, compressed_data, compressed_size, &out.front(), uncompressed_size, NULL);
libdeflate_free_decompressor(decompressor);
return result == LIBDEFLATE_SUCCESS;
#else
z_stream inflateState;
memset(&inflateState, 0, sizeof(inflateState));
@ -143,6 +171,7 @@ namespace ix
inflateEnd(&inflateState);
return true;
#endif
}
#endif
} // namespace ix

View File

@ -6,4 +6,4 @@
#pragma once
#define IX_WEBSOCKET_VERSION "10.5.3"
#define IX_WEBSOCKET_VERSION "10.5.6"

View File

@ -33,6 +33,9 @@ ws_mbedtls_install:
ws:
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
ws_unity:
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
ws_install:
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 .. -DUSE_TEST=0 && ninja install)
@ -247,6 +250,9 @@ doc:
change: format
vim ixwebsocket/IXWebSocketVersion.h docs/CHANGELOG.md
change_no_format:
vim ixwebsocket/IXWebSocketVersion.h docs/CHANGELOG.md
commit:
git commit -am "`sh tools/extract_latest_change.sh`"

View File

@ -38,35 +38,6 @@ namespace
}
});
}
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
{
ix::CobraMetricsPublisher cobraMetricsPublisher;
cobraMetricsPublisher.configure(config, channel);
cobraMetricsPublisher.setSession(uuid4());
cobraMetricsPublisher.enable(true);
Json::Value msg;
msg["fps"] = 60;
cobraMetricsPublisher.setGenericAttributes("game", "ody");
// Wait a bit
ix::msleep(500);
// publish some messages
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
ix::msleep(500);
}
} // namespace
TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")

View File

@ -20,38 +20,6 @@
using namespace ix;
namespace
{
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
{
ix::CobraMetricsPublisher cobraMetricsPublisher;
cobraMetricsPublisher.configure(config, channel);
cobraMetricsPublisher.setSession(uuid4());
cobraMetricsPublisher.enable(true);
Json::Value msg;
msg["fps"] = 60;
cobraMetricsPublisher.setGenericAttributes("game", "ody");
// Wait a bit
ix::msleep(500);
// publish some messages
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
ix::msleep(500);
}
} // namespace
TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
{
SECTION("Exchange and count sent/received messages.")

View File

@ -10,7 +10,6 @@
#include <iostream>
#include <ixbots/IXCobraToStdoutBot.h>
#include <ixcobra/IXCobraConnection.h>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include <ixcrypto/IXUuid.h>
#include <ixredis/IXRedisServer.h>
#include <ixsentry/IXSentryClient.h>
@ -20,38 +19,6 @@
using namespace ix;
namespace
{
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
{
ix::CobraMetricsPublisher cobraMetricsPublisher;
cobraMetricsPublisher.configure(config, channel);
cobraMetricsPublisher.setSession(uuid4());
cobraMetricsPublisher.enable(true);
Json::Value msg;
msg["fps"] = 60;
cobraMetricsPublisher.setGenericAttributes("game", "ody");
// Wait a bit
ix::msleep(500);
// publish some messages
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
ix::msleep(500);
}
} // namespace
TEST_CASE("Cobra_to_stdout_bot", "[cobra_bots]")
{
SECTION("Exchange and count sent/received messages.")

View File

@ -10,6 +10,8 @@
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include <ixcrypto/IXUuid.h>
#include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXWebSocket.h>
#include <mutex>
@ -243,4 +245,33 @@ namespace ix
return endpoint;
}
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
{
ix::CobraMetricsPublisher cobraMetricsPublisher;
cobraMetricsPublisher.configure(config, channel);
cobraMetricsPublisher.setSession(uuid4());
cobraMetricsPublisher.enable(true);
Json::Value msg;
msg["fps"] = 60;
cobraMetricsPublisher.setGenericAttributes("game", "ody");
// Wait a bit
ix::msleep(500);
// publish some messages
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
ix::msleep(500);
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
ix::msleep(500);
}
} // namespace ix

View File

@ -7,6 +7,7 @@
#pragma once
#include <iostream>
#include <ixcobra/IXCobraConfig.h>
#include <ixsnake/IXAppConfig.h>
#include <ixwebsocket/IXGetFreePort.h>
#include <ixwebsocket/IXSocketTLSOptions.h>
@ -59,4 +60,6 @@ namespace ix
std::string getWsScheme(bool preferTLS);
std::string makeCobraEndpoint(int port, bool preferTLS);
void runPublisher(const ix::CobraConfig& config, const std::string& channel);
} // namespace ix

View File

@ -18,10 +18,10 @@ using namespace ix;
namespace
{
class WebSocketChat
class WebSocketBroadcastChat
{
public:
WebSocketChat(const std::string& user, const std::string& session, int port);
WebSocketBroadcastChat(const std::string& user, const std::string& session, int port);
void subscribe(const std::string& channel);
void start();
@ -47,7 +47,9 @@ namespace
mutable std::mutex _mutex;
};
WebSocketChat::WebSocketChat(const std::string& user, const std::string& session, int port)
WebSocketBroadcastChat::WebSocketBroadcastChat(const std::string& user,
const std::string& session,
int port)
: _user(user)
, _session(session)
, _port(port)
@ -55,35 +57,35 @@ namespace
_webSocket.setTLSOptions(makeClientTLSOptions());
}
size_t WebSocketChat::getReceivedMessagesCount() const
size_t WebSocketBroadcastChat::getReceivedMessagesCount() const
{
std::lock_guard<std::mutex> lock(_mutex);
return _receivedMessages.size();
}
const std::vector<std::string>& WebSocketChat::getReceivedMessages() const
const std::vector<std::string>& WebSocketBroadcastChat::getReceivedMessages() const
{
std::lock_guard<std::mutex> lock(_mutex);
return _receivedMessages;
}
void WebSocketChat::appendMessage(const std::string& message)
void WebSocketBroadcastChat::appendMessage(const std::string& message)
{
std::lock_guard<std::mutex> lock(_mutex);
_receivedMessages.push_back(message);
}
bool WebSocketChat::isReady() const
bool WebSocketBroadcastChat::isReady() const
{
return _webSocket.getReadyState() == ix::ReadyState::Open;
}
void WebSocketChat::stop()
void WebSocketBroadcastChat::stop()
{
_webSocket.stop();
}
void WebSocketChat::start()
void WebSocketBroadcastChat::start()
{
std::string url;
{
@ -156,7 +158,8 @@ namespace
_webSocket.start();
}
std::pair<std::string, std::string> WebSocketChat::decodeMessage(const std::string& str)
std::pair<std::string, std::string> WebSocketBroadcastChat::decodeMessage(
const std::string& str)
{
std::string errMsg;
MsgPack msg = MsgPack::parse(str, errMsg);
@ -167,7 +170,7 @@ namespace
return std::pair<std::string, std::string>(msg_user, msg_text);
}
std::string WebSocketChat::encodeMessage(const std::string& text)
std::string WebSocketBroadcastChat::encodeMessage(const std::string& text)
{
std::map<MsgPack, MsgPack> obj;
obj["user"] = _user;
@ -179,7 +182,7 @@ namespace
return output;
}
void WebSocketChat::sendMessage(const std::string& text)
void WebSocketBroadcastChat::sendMessage(const std::string& text)
{
_webSocket.sendBinary(encodeMessage(text));
}
@ -248,11 +251,11 @@ TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
REQUIRE(startServer(server, connectionId));
std::string session = ix::generateSessionId();
std::vector<std::shared_ptr<WebSocketChat>> chatClients;
std::vector<std::shared_ptr<WebSocketBroadcastChat>> chatClients;
for (int i = 0; i < 10; ++i)
{
std::string user("user_" + std::to_string(i));
chatClients.push_back(std::make_shared<WebSocketChat>(user, session, port));
chatClients.push_back(std::make_shared<WebSocketBroadcastChat>(user, session, port));
chatClients[i]->start();
ix::msleep(50);
}

View File

@ -152,7 +152,7 @@ namespace
idx = path.rfind('.');
if (idx != std::string::npos)
{
std::string filename = path.substr(idx + 1);
std::string filename = path.substr(0, idx);
return filename;
}
else
@ -1220,6 +1220,11 @@ namespace ix
std::ofstream f;
f.open(outputFilename);
if (!f.is_open())
{
spdlog::error("Cannot open {} for writing", outputFilename);
return 1;
}
f << decompressedBytes;
f.close();
@ -1268,45 +1273,56 @@ namespace ix
std::condition_variable condition;
std::atomic<bool> stop(false);
std::chrono::time_point<std::chrono::high_resolution_clock> start;
// Setup a callback to be fired
// when a message or an event (open, close, ping, pong, error) is received
webSocket.setOnMessageCallback([&receivedCountPerSecs, &target, &stop, &condition, &bench](
const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Message)
{
receivedCountPerSecs++;
target -= 1;
if (target == 0)
webSocket.setOnMessageCallback(
[&receivedCountPerSecs, &target, &stop, &condition, &bench, &start](
const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Message)
{
stop = true;
condition.notify_one();
receivedCountPerSecs++;
bench.report();
target -= 1;
if (target == 0)
{
stop = true;
condition.notify_one();
bench.report();
auto now = std::chrono::high_resolution_clock::now();
auto milliseconds =
std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
auto duration = milliseconds.count();
spdlog::info("AUTOROUTE IXWebSocket :: {} ms", duration);
}
}
}
else if (msg->type == ix::WebSocketMessageType::Open)
{
bench.reset();
spdlog::info("ws_autoroute: connected");
spdlog::info("Uri: {}", msg->openInfo.uri);
spdlog::info("Headers:");
for (auto it : msg->openInfo.headers)
else if (msg->type == ix::WebSocketMessageType::Open)
{
spdlog::info("{}: {}", it.first, it.second);
bench.reset();
spdlog::info("ws_autoroute: connected");
spdlog::info("Uri: {}", msg->openInfo.uri);
spdlog::info("Headers:");
for (auto it : msg->openInfo.headers)
{
spdlog::info("{}: {}", it.first, it.second);
}
start = std::chrono::high_resolution_clock::now();
}
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
spdlog::info("Received pong {}", msg->str);
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
spdlog::info("ws_autoroute: connection closed");
}
});
else if (msg->type == ix::WebSocketMessageType::Pong)
{
spdlog::info("Received pong {}", msg->str);
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
spdlog::info("ws_autoroute: connection closed");
}
});
auto timer = [&receivedCountPerSecs, &stop] {
setThreadName("Timer");