Add initial send compression
This commit is contained in:
+2
-2
@@ -28,11 +28,11 @@ int main(int argc, char **argv) {
|
|||||||
.open = [](auto *ws, auto *req) {
|
.open = [](auto *ws, auto *req) {
|
||||||
std::cout << "WebSocket connected" << std::endl;
|
std::cout << "WebSocket connected" << std::endl;
|
||||||
/* Access per socket data */
|
/* Access per socket data */
|
||||||
/*PerSocketData *perSocketData = */ws->getUserData();
|
/*PerSocketData *perSocketData = *///ws->getUserData();
|
||||||
/*perSocketData->hello = 13;*/
|
/*perSocketData->hello = 13;*/
|
||||||
},
|
},
|
||||||
.message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {
|
.message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {
|
||||||
ws->send(message, opCode);
|
ws->send(message, opCode, true);
|
||||||
},
|
},
|
||||||
.drain = [](auto *ws) {
|
.drain = [](auto *ws) {
|
||||||
std::cout << "Drainage: " << ws->getBufferedAmount() << std::endl;
|
std::cout << "Drainage: " << ws->getBufferedAmount() << std::endl;
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ public:
|
|||||||
if (!loopData->inflationStream) {
|
if (!loopData->inflationStream) {
|
||||||
loopData->inflationStream = new InflationStream;
|
loopData->inflationStream = new InflationStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!loopData->deflationStream) {
|
||||||
|
loopData->deflationStream = new DeflationStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy all handlers */
|
/* Copy all handlers */
|
||||||
@@ -122,16 +126,23 @@ public:
|
|||||||
|
|
||||||
/* Adopting a socket invalidates it, do not rely on it directly to carry any data */
|
/* Adopting a socket invalidates it, do not rely on it directly to carry any data */
|
||||||
WebSocket<SSL, true> *webSocket = (WebSocket<SSL, true> *) StaticDispatch<SSL>::static_dispatch(us_ssl_socket_context_adopt_socket, us_socket_context_adopt_socket)(
|
WebSocket<SSL, true> *webSocket = (WebSocket<SSL, true> *) StaticDispatch<SSL>::static_dispatch(us_ssl_socket_context_adopt_socket, us_socket_context_adopt_socket)(
|
||||||
(typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE *) webSocketContext, (typename StaticDispatch<SSL>::SOCKET_TYPE *) res, /*sizeof(WebSocketData)*/ 150);
|
(typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE *) webSocketContext, (typename StaticDispatch<SSL>::SOCKET_TYPE *) res, sizeof(WebSocketData));
|
||||||
|
|
||||||
|
/* Update corked socket in case we got a new one (assuming we always are corked in handlers). */
|
||||||
|
webSocket->cork();
|
||||||
|
|
||||||
httpContext->upgradeToWebSocket(
|
httpContext->upgradeToWebSocket(
|
||||||
webSocket->init(perMessageDeflate)
|
webSocket->init(perMessageDeflate)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Emit open event */
|
||||||
if (behavior.open) {
|
if (behavior.open) {
|
||||||
behavior.open(webSocket, req);
|
behavior.open(webSocket, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: perform all the checks such as shutdown, closed, etc!
|
||||||
|
// bug? or does this happen automatically? no!
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* For now we do not support having HTTP and websocket routes on the same URL */
|
/* For now we do not support having HTTP and websocket routes on the same URL */
|
||||||
res->close();
|
res->close();
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public:
|
|||||||
|
|
||||||
/* Compression data */
|
/* Compression data */
|
||||||
InflationStream *inflationStream = nullptr;
|
InflationStream *inflationStream = nullptr;
|
||||||
|
DeflationStream *deflationStream = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,82 @@
|
|||||||
|
|
||||||
// we also need DeflationStream
|
// we also need DeflationStream
|
||||||
|
|
||||||
|
struct DeflationStream {
|
||||||
|
|
||||||
|
// share this under the Loop
|
||||||
|
std::string dynamicZlibBuffer;
|
||||||
|
z_stream deflationStream = {};
|
||||||
|
char *zlibBuffer;
|
||||||
|
|
||||||
|
DeflationStream() {
|
||||||
|
std::cout << "Constructing DeflationStream" << std::endl;
|
||||||
|
zlibBuffer = (char *) malloc(LARGE_BUFFER_SIZE);
|
||||||
|
|
||||||
|
deflateInit2(&deflationStream, 1, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view deflate(std::string_view raw) {
|
||||||
|
|
||||||
|
// slidingDeflateWindow är input, length är in/ut
|
||||||
|
|
||||||
|
z_stream *slidingDeflateWindow = nullptr;
|
||||||
|
|
||||||
|
dynamicZlibBuffer.clear();
|
||||||
|
|
||||||
|
z_stream *compressor = slidingDeflateWindow ? slidingDeflateWindow : &deflationStream;
|
||||||
|
|
||||||
|
compressor->next_in = (Bytef *) raw.data();
|
||||||
|
compressor->avail_in = (unsigned int) raw.length();
|
||||||
|
|
||||||
|
// note: zlib requires more than 6 bytes with Z_SYNC_FLUSH
|
||||||
|
const int DEFLATE_OUTPUT_CHUNK = LARGE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
compressor->next_out = (Bytef *) zlibBuffer;
|
||||||
|
compressor->avail_out = DEFLATE_OUTPUT_CHUNK;
|
||||||
|
|
||||||
|
err = ::deflate(compressor, Z_SYNC_FLUSH);
|
||||||
|
if (Z_OK == err && compressor->avail_out == 0) {
|
||||||
|
dynamicZlibBuffer.append(zlibBuffer, DEFLATE_OUTPUT_CHUNK - compressor->avail_out);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
// note: should not change avail_out
|
||||||
|
if (!slidingDeflateWindow) {
|
||||||
|
deflateReset(compressor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dynamicZlibBuffer.length()) {
|
||||||
|
dynamicZlibBuffer.append(zlibBuffer, DEFLATE_OUTPUT_CHUNK - compressor->avail_out);
|
||||||
|
|
||||||
|
return {(char *) dynamicZlibBuffer.data(), dynamicZlibBuffer.length() - 4};
|
||||||
|
|
||||||
|
//length = dynamicZlibBuffer.length() - 4;
|
||||||
|
//return (char *) dynamicZlibBuffer.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
zlibBuffer,
|
||||||
|
DEFLATE_OUTPUT_CHUNK - compressor->avail_out - 4
|
||||||
|
};
|
||||||
|
|
||||||
|
//length = DEFLATE_OUTPUT_CHUNK - compressor->avail_out - 4;
|
||||||
|
//return zlibBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
~DeflationStream() {
|
||||||
|
std::cout << "Destructing DeflationStream" << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// the loop holds one of these
|
// the loop holds one of these
|
||||||
struct InflationStream {
|
struct InflationStream {
|
||||||
|
|
||||||
|
// share this under the Loop
|
||||||
std::string dynamicZlibBuffer;
|
std::string dynamicZlibBuffer;
|
||||||
z_stream inflationStream = {};
|
z_stream inflationStream = {};
|
||||||
char *zlibBuffer;
|
char *zlibBuffer;
|
||||||
|
|||||||
+11
-3
@@ -54,14 +54,22 @@ public:
|
|||||||
bool send(std::string_view message, uWS::OpCode opCode = uWS::OpCode::BINARY, bool compress = false) {
|
bool send(std::string_view message, uWS::OpCode opCode = uWS::OpCode::BINARY, bool compress = false) {
|
||||||
/* Transform the message to compressed domain if requested */
|
/* Transform the message to compressed domain if requested */
|
||||||
if (compress) {
|
if (compress) {
|
||||||
//message = ;
|
WebSocketData *webSocketData = (WebSocketData *) Super::getExt();
|
||||||
std::cout << "send compression ignored!" << std::endl;
|
|
||||||
|
/* Check and correct the compress hint */
|
||||||
|
if (opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) {
|
||||||
|
// todo: shared deflate window
|
||||||
|
LoopData *loopData = Super::getLoopData();
|
||||||
|
message = loopData->deflationStream->deflate(message);
|
||||||
|
} else {
|
||||||
|
compress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get size, alloate size, write if needed */
|
/* Get size, alloate size, write if needed */
|
||||||
size_t messageFrameSize = WebSocketProtocol<isServer, WebSocket<SSL, isServer>>::messageFrameSize(message.length());
|
size_t messageFrameSize = WebSocketProtocol<isServer, WebSocket<SSL, isServer>>::messageFrameSize(message.length());
|
||||||
auto[sendBuffer, requiresWrite] = Super::getSendBuffer(messageFrameSize);
|
auto[sendBuffer, requiresWrite] = Super::getSendBuffer(messageFrameSize);
|
||||||
WebSocketProtocol<isServer, WebSocket<SSL, isServer>>::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), false);
|
WebSocketProtocol<isServer, WebSocket<SSL, isServer>>::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress);
|
||||||
if (requiresWrite) {
|
if (requiresWrite) {
|
||||||
auto[written, failed] = Super::write(sendBuffer, messageFrameSize);
|
auto[written, failed] = Super::write(sendBuffer, messageFrameSize);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ private:
|
|||||||
} compressionStatus;
|
} compressionStatus;
|
||||||
public:
|
public:
|
||||||
WebSocketData(bool perMessageDeflate) : WebSocketState<true>() {
|
WebSocketData(bool perMessageDeflate) : WebSocketState<true>() {
|
||||||
std::cout << "perMessageDeflate: " << perMessageDeflate << std::endl;
|
//std::cout << "perMessageDeflate: " << perMessageDeflate << std::endl;
|
||||||
compressionStatus = perMessageDeflate ? ENABLED : DISABLED;
|
compressionStatus = perMessageDeflate ? ENABLED : DISABLED;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#ifndef WEBSOCKETPROTOCOL_UWS_H
|
#ifndef WEBSOCKETPROTOCOL_UWS_H
|
||||||
#define WEBSOCKETPROTOCOL_UWS_H
|
#define WEBSOCKETPROTOCOL_UWS_H
|
||||||
|
|
||||||
|
// this module depends on windows ws2_lib being linked which is nonsense, fix!
|
||||||
|
|
||||||
/* This segment is not cross-platform! Fix! */
|
/* This segment is not cross-platform! Fix! */
|
||||||
/* PortableEndianConversion.h */
|
/* PortableEndianConversion.h */
|
||||||
#ifdef __linux
|
#ifdef __linux
|
||||||
|
|||||||
Reference in New Issue
Block a user