Add shared compression for pub/sub

This commit is contained in:
Alex Hultman
2020-05-28 23:24:52 +02:00
parent ac97fef5eb
commit 8f7d642f3f
4 changed files with 49 additions and 18 deletions
+33 -4
View File
@@ -23,6 +23,7 @@
#include "WebSocketProtocol.h"
#include "TopicTree.h"
#include "WebSocketData.h"
namespace uWS {
@@ -56,15 +57,23 @@ struct WebSocketContextData {
Loop::get()->removePreHandler(this);
}
WebSocketContextData() : topicTree([this](Subscriber *s, std::string_view data) -> int {
WebSocketContextData() : topicTree([this](Subscriber *s, std::pair<std::string_view, std::string_view> data) -> int {
/* We rely on writing to regular asyncSockets */
auto *asyncSocket = (AsyncSocket<SSL> *) s->user;
/* Check if we now have too much backpressure (todo: don't buffer up before check) */
if (!maxBackpressure || (unsigned int) asyncSocket->getBufferedAmount() < maxBackpressure) {
/* Pick uncompressed data track */
std::string_view selectedData = data.first;
/* Are we using compression? Fine, pick the compressed data track */
WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData();
if (webSocketData->compressionStatus != WebSocketData::CompressionStatus::DISABLED) {
selectedData = data.second;
}
/* Note: this assumes we are not corked, as corking will swallow things and fail later on */
auto [written, failed] = asyncSocket->write(data.data(), (int) data.length());
auto [written, failed] = asyncSocket->write(selectedData.data(), (int) selectedData.length());
if (!failed) {
asyncSocket->timeout(this->idleTimeout);
}
@@ -97,7 +106,27 @@ struct WebSocketContextData {
char *dst = (char *) malloc(protocol::messageFrameSize(message.size()));
size_t dst_length = protocol::formatMessage<true>(dst, message.data(), message.length(), opCode, message.length(), false);
topicTree.publish(topic, std::string_view(dst, dst_length));
if (compress) {
/* Loop data holds shared compressor */
LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) Loop::get());
/* Compress it */
std::string_view compressedMessage = loopData->deflationStream->deflate(loopData->zlibContext, message, true);
/* Frame it */
char *dst_compressed = (char *) malloc(protocol::messageFrameSize(compressedMessage.size()));
size_t dst_compressed_length = protocol::formatMessage<true>(dst_compressed, compressedMessage.data(), compressedMessage.length(), opCode, compressedMessage.length(), true);
/* Always publish the shortest one in any case */
topicTree.publish(topic, {std::string_view(dst, dst_length), dst_compressed_length >= dst_length ? std::string_view(dst, dst_length) : std::string_view(dst_compressed, dst_compressed_length)});
/* We don't care for allocation here */
::free(dst_compressed);
} else {
/* If not compressing, put same message on both tracks */
topicTree.publish(topic, {std::string_view(dst, dst_length), std::string_view(dst, dst_length)});
}
::free(dst);
}
};