Move TopicTree to the App
This commit is contained in:
@@ -18,6 +18,17 @@
|
|||||||
#ifndef UWS_APP_H
|
#ifndef UWS_APP_H
|
||||||
#define UWS_APP_H
|
#define UWS_APP_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace uWS {
|
||||||
|
/* Type queued up when publishing */
|
||||||
|
struct TopicTreeMessage {
|
||||||
|
std::string message;
|
||||||
|
/*OpCode*/ int opCode;
|
||||||
|
bool compress;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/* An app is a convenience wrapper of some of the most used fuctionalities and allows a
|
/* An app is a convenience wrapper of some of the most used fuctionalities and allows a
|
||||||
* builder-pattern kind of init. Apps operate on the implicit thread local Loop */
|
* builder-pattern kind of init. Apps operate on the implicit thread local Loop */
|
||||||
|
|
||||||
@@ -53,10 +64,13 @@ struct TemplatedApp {
|
|||||||
private:
|
private:
|
||||||
/* The app always owns at least one http context, but creates websocket contexts on demand */
|
/* The app always owns at least one http context, but creates websocket contexts on demand */
|
||||||
HttpContext<SSL> *httpContext;
|
HttpContext<SSL> *httpContext;
|
||||||
std::vector<WebSocketContext<SSL, true, int> *> webSocketContexts;
|
/* WebSocketContexts are of differing type, but we as owners and creators must delete them correctly */
|
||||||
|
std::vector<MoveOnlyFunction<void()>> webSocketContextDeleters;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
TopicTree<TopicTreeMessage> *topicTree = nullptr;
|
||||||
|
|
||||||
/* Server name */
|
/* Server name */
|
||||||
TemplatedApp &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}) {
|
TemplatedApp &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}) {
|
||||||
|
|
||||||
@@ -100,27 +114,19 @@ public:
|
|||||||
* TopicTree of this app (technically there are many TopicTrees, however the concept is that one
|
* TopicTree of this app (technically there are many TopicTrees, however the concept is that one
|
||||||
* app has one conceptual Topic tree) */
|
* app has one conceptual Topic tree) */
|
||||||
void publish(std::string_view topic, std::string_view message, OpCode opCode, bool compress = false) {
|
void publish(std::string_view topic, std::string_view message, OpCode opCode, bool compress = false) {
|
||||||
for (auto *webSocketContext : webSocketContexts) {
|
topicTree->publish(nullptr, topic, {std::string(message), opCode, compress});
|
||||||
webSocketContext->getExt()->topicTree.publish(nullptr, topic, {std::string(message), opCode, compress});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns number of subscribers for this topic, or 0 for failure.
|
/* Returns number of subscribers for this topic, or 0 for failure.
|
||||||
* This function should probably be optimized a lot in future releases,
|
* This function should probably be optimized a lot in future releases,
|
||||||
* it could be O(1) with a hash map of fullnames and their counts. */
|
* it could be O(1) with a hash map of fullnames and their counts. */
|
||||||
unsigned int numSubscribers(std::string_view topic) {
|
unsigned int numSubscribers(std::string_view topic) {
|
||||||
unsigned int subscribers = 0;
|
Topic *t = topicTree->lookupTopic(topic);
|
||||||
|
if (t) {
|
||||||
for (auto *webSocketContext : webSocketContexts) {
|
return t->size();
|
||||||
auto *webSocketContextData = webSocketContext->getExt();
|
|
||||||
|
|
||||||
Topic *t = webSocketContextData->topicTree.lookupTopic(topic);
|
|
||||||
if (t) {
|
|
||||||
subscribers += t->size();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return subscribers;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~TemplatedApp() {
|
~TemplatedApp() {
|
||||||
@@ -128,10 +134,21 @@ public:
|
|||||||
if (httpContext) {
|
if (httpContext) {
|
||||||
httpContext->free();
|
httpContext->free();
|
||||||
|
|
||||||
for (auto *webSocketContext : webSocketContexts) {
|
/* Free all our webSocketContexts in a type less way */
|
||||||
webSocketContext->free();
|
for (auto &webSocketContextDeleter : webSocketContextDeleters) {
|
||||||
|
webSocketContextDeleter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete TopicTree */
|
||||||
|
if (topicTree) {
|
||||||
|
delete topicTree;
|
||||||
|
|
||||||
|
/* And unregister loop callbacks */
|
||||||
|
/* We must unregister any loop post handler here */
|
||||||
|
Loop::get()->removePostHandler(topicTree);
|
||||||
|
Loop::get()->removePreHandler(topicTree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disallow copying, only move */
|
/* Disallow copying, only move */
|
||||||
@@ -142,8 +159,12 @@ public:
|
|||||||
httpContext = other.httpContext;
|
httpContext = other.httpContext;
|
||||||
other.httpContext = nullptr;
|
other.httpContext = nullptr;
|
||||||
|
|
||||||
/* Move webSocketContexts */
|
/* Move webSocketContextDeleters */
|
||||||
webSocketContexts = std::move(other.webSocketContexts);
|
webSocketContextDeleters = std::move(other.webSocketContextDeleters);
|
||||||
|
|
||||||
|
/* Move TopicTree */
|
||||||
|
other.topicTree = topicTree;
|
||||||
|
topicTree = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplatedApp(SocketContextOptions options = {}) {
|
TemplatedApp(SocketContextOptions options = {}) {
|
||||||
@@ -200,21 +221,67 @@ public:
|
|||||||
std::cerr << "Warning: idleTimeout should be a multiple of 4!" << std::endl;
|
std::cerr << "Warning: idleTimeout should be a multiple of 4!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we don't have a TopicTree yet, create one now */
|
||||||
|
if (!topicTree) {
|
||||||
|
|
||||||
|
topicTree = new TopicTree<TopicTreeMessage>([](Subscriber *s, TopicTreeMessage &message, auto flags) {
|
||||||
|
/* Subscriber's user is the socket */
|
||||||
|
/* Unfortunately we need to cast is to PerSocketData = int
|
||||||
|
* since many different WebSocketContexts use the same
|
||||||
|
* TopicTree now */
|
||||||
|
auto *ws = (WebSocket<SSL, true, int> *) s->user;
|
||||||
|
|
||||||
|
/* If this is the first message we try and cork */
|
||||||
|
bool needsUncork = false;
|
||||||
|
if (flags & TopicTree<TopicTreeMessage>::IteratorFlags::FIRST) {
|
||||||
|
if (ws->canCork() && !ws->isCorked()) {
|
||||||
|
((AsyncSocket<SSL> *)ws)->cork();
|
||||||
|
needsUncork = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we ever overstep maxBackpresure, exit immediately */
|
||||||
|
if (WebSocket<SSL, true, int>::SendStatus::DROPPED == ws->send(message.message, (OpCode)message.opCode, message.compress)) {
|
||||||
|
|
||||||
|
if (needsUncork) {
|
||||||
|
((AsyncSocket<SSL> *)ws)->uncork();
|
||||||
|
}
|
||||||
|
/* Stop draining */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is the last message we uncork if we are corked */
|
||||||
|
if (flags & TopicTree<TopicTreeMessage>::IteratorFlags::LAST) {
|
||||||
|
/* We should not uncork in all cases? */
|
||||||
|
if (needsUncork) {
|
||||||
|
((AsyncSocket<SSL> *)ws)->uncork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* And hook it up with the loop */
|
||||||
|
/* We empty for both pre and post just to make sure */
|
||||||
|
Loop::get()->addPostHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) {
|
||||||
|
/* Commit pub/sub batches every loop iteration */
|
||||||
|
topicTree->drain();
|
||||||
|
});
|
||||||
|
|
||||||
|
Loop::get()->addPreHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) {
|
||||||
|
/* Commit pub/sub batches every loop iteration */
|
||||||
|
topicTree->drain();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* Every route has its own websocket context with its own behavior and user data type */
|
/* Every route has its own websocket context with its own behavior and user data type */
|
||||||
auto *webSocketContext = WebSocketContext<SSL, true, UserData>::create(Loop::get(), (us_socket_context_t *) httpContext);
|
auto *webSocketContext = WebSocketContext<SSL, true, UserData>::create(Loop::get(), (us_socket_context_t *) httpContext, topicTree);
|
||||||
|
|
||||||
/* Add all other WebSocketContextData to this new WebSocketContextData */
|
|
||||||
for (WebSocketContext<SSL, true, int> *adjacentWebSocketContext : webSocketContexts) {
|
|
||||||
webSocketContext->getExt()->adjacentWebSocketContextDatas.push_back(adjacentWebSocketContext->getExt());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this WebSocketContextData to all other WebSocketContextData */
|
|
||||||
for (WebSocketContext<SSL, true, int> *adjacentWebSocketContext : webSocketContexts) {
|
|
||||||
adjacentWebSocketContext->getExt()->adjacentWebSocketContextDatas.push_back((WebSocketContextData<SSL, int> *) webSocketContext->getExt());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We need to clear this later on */
|
/* We need to clear this later on */
|
||||||
webSocketContexts.push_back((WebSocketContext<SSL, true, int> *) webSocketContext);
|
webSocketContextDeleters.push_back([webSocketContext]() {
|
||||||
|
webSocketContext->free();
|
||||||
|
});
|
||||||
|
|
||||||
/* Quick fix to disable any compression if set */
|
/* Quick fix to disable any compression if set */
|
||||||
#ifdef UWS_NO_ZLIB
|
#ifdef UWS_NO_ZLIB
|
||||||
|
|||||||
@@ -44,8 +44,10 @@ namespace uWS {
|
|||||||
|
|
||||||
template <bool SSL>
|
template <bool SSL>
|
||||||
struct AsyncSocket {
|
struct AsyncSocket {
|
||||||
|
/* This guy is promiscuous */
|
||||||
template <bool> friend struct HttpContext;
|
template <bool> friend struct HttpContext;
|
||||||
template <bool, bool, typename> friend struct WebSocketContext;
|
template <bool, bool, typename> friend struct WebSocketContext;
|
||||||
|
template <bool> friend struct TemplatedApp;
|
||||||
template <bool, typename> friend struct WebSocketContextData;
|
template <bool, typename> friend struct WebSocketContextData;
|
||||||
template <typename> friend struct TopicTree;
|
template <typename> friend struct TopicTree;
|
||||||
|
|
||||||
|
|||||||
+10
-18
@@ -93,7 +93,7 @@ public:
|
|||||||
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
||||||
if (webSocketData->subscriber) {
|
if (webSocketData->subscriber) {
|
||||||
/* This will call back into us, send. */
|
/* This will call back into us, send. */
|
||||||
webSocketContextData->topicTree.drain(webSocketData->subscriber);
|
webSocketContextData->topicTree->drain(webSocketData->subscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transform the message to compressed domain if requested */
|
/* Transform the message to compressed domain if requested */
|
||||||
@@ -187,7 +187,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure to unsubscribe from any pub/sub node at exit */
|
/* Make sure to unsubscribe from any pub/sub node at exit */
|
||||||
webSocketContextData->topicTree.freeSubscriber(webSocketData->subscriber);
|
webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber);
|
||||||
webSocketData->subscriber = nullptr;
|
webSocketData->subscriber = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,12 +215,12 @@ public:
|
|||||||
/* Make us a subscriber if we aren't yet */
|
/* Make us a subscriber if we aren't yet */
|
||||||
WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);
|
WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);
|
||||||
if (!webSocketData->subscriber) {
|
if (!webSocketData->subscriber) {
|
||||||
webSocketData->subscriber = webSocketContextData->topicTree.createSubscriber();
|
webSocketData->subscriber = webSocketContextData->topicTree->createSubscriber();
|
||||||
webSocketData->subscriber->user = this;
|
webSocketData->subscriber->user = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cannot return numSubscribers as this is only for this particular websocket context */
|
/* Cannot return numSubscribers as this is only for this particular websocket context */
|
||||||
webSocketContextData->topicTree.subscribe(webSocketData->subscriber, topic);
|
webSocketContextData->topicTree->subscribe(webSocketData->subscriber, topic);
|
||||||
|
|
||||||
/* Subscribe always succeeds */
|
/* Subscribe always succeeds */
|
||||||
return true;
|
return true;
|
||||||
@@ -235,11 +235,11 @@ public:
|
|||||||
WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);
|
WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);
|
||||||
|
|
||||||
/* Cannot return numSubscribers as this is only for this particular websocket context */
|
/* Cannot return numSubscribers as this is only for this particular websocket context */
|
||||||
auto [ok, last] = webSocketContextData->topicTree.unsubscribe(webSocketData->subscriber, topic);
|
auto [ok, last] = webSocketContextData->topicTree->unsubscribe(webSocketData->subscriber, topic);
|
||||||
|
|
||||||
/* Free us as subscribers if we unsubscribed from our last topic */
|
/* Free us as subscribers if we unsubscribed from our last topic */
|
||||||
if (ok && last) {
|
if (ok && last) {
|
||||||
webSocketContextData->topicTree.freeSubscriber(webSocketData->subscriber);
|
webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber);
|
||||||
webSocketData->subscriber = nullptr;
|
webSocketData->subscriber = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Topic *topicPtr = webSocketContextData->topicTree.lookupTopic(topic);
|
Topic *topicPtr = webSocketContextData->topicTree->lookupTopic(topic);
|
||||||
if (!topicPtr) {
|
if (!topicPtr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -277,14 +277,14 @@ public:
|
|||||||
WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);
|
WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);
|
||||||
if (webSocketData->subscriber) {
|
if (webSocketData->subscriber) {
|
||||||
/* Lock this subscriber for unsubscription / subscription */
|
/* Lock this subscriber for unsubscription / subscription */
|
||||||
webSocketContextData->topicTree.iteratingSubscriber = webSocketData->subscriber;
|
webSocketContextData->topicTree->iteratingSubscriber = webSocketData->subscriber;
|
||||||
|
|
||||||
for (Topic *topicPtr : webSocketData->subscriber->topics) {
|
for (Topic *topicPtr : webSocketData->subscriber->topics) {
|
||||||
cb({topicPtr->name.data(), topicPtr->name.length()});
|
cb({topicPtr->name.data(), topicPtr->name.length()});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlock subscriber */
|
/* Unlock subscriber */
|
||||||
webSocketContextData->topicTree.iteratingSubscriber = nullptr;
|
webSocketContextData->topicTree->iteratingSubscriber = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,15 +304,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Publish as sender, does not receive its own messages even if subscribed to relevant topics */
|
/* Publish as sender, does not receive its own messages even if subscribed to relevant topics */
|
||||||
bool success = webSocketContextData->topicTree.publish(webSocketData->subscriber, topic, {std::string(message), opCode, compress});
|
bool success = webSocketContextData->topicTree->publish(webSocketData->subscriber, topic, {std::string(message), opCode, compress});
|
||||||
|
|
||||||
/* Loop over all websocket contexts for this App */
|
|
||||||
if (success) {
|
|
||||||
/* Success is really only determined by the first publish. We must be subscribed to the topic. */
|
|
||||||
for (auto *adjacentWebSocketContextData : webSocketContextData->adjacentWebSocketContextDatas) {
|
|
||||||
adjacentWebSocketContextData->topicTree.publish(nullptr, topic, {std::string(message), opCode, compress});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure to unsubscribe from any pub/sub node at exit */
|
/* Make sure to unsubscribe from any pub/sub node at exit */
|
||||||
webSocketContextData->topicTree.freeSubscriber(webSocketData->subscriber);
|
webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber);
|
||||||
webSocketData->subscriber = nullptr;
|
webSocketData->subscriber = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,14 +390,14 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/* WebSocket contexts are always child contexts to a HTTP context so no SSL options are needed as they are inherited */
|
/* WebSocket contexts are always child contexts to a HTTP context so no SSL options are needed as they are inherited */
|
||||||
static WebSocketContext *create(Loop */*loop*/, us_socket_context_t *parentSocketContext) {
|
static WebSocketContext *create(Loop */*loop*/, us_socket_context_t *parentSocketContext, TopicTree<TopicTreeMessage> *topicTree) {
|
||||||
WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData<SSL, USERDATA>));
|
WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData<SSL, USERDATA>));
|
||||||
if (!webSocketContext) {
|
if (!webSocketContext) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init socket context data */
|
/* Init socket context data */
|
||||||
new ((WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData<SSL, USERDATA>;
|
new ((WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData<SSL, USERDATA>(topicTree);
|
||||||
return webSocketContext->init();
|
return webSocketContext->init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,16 +40,9 @@ struct WebSocketContextData {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Type queued up when publishing */
|
|
||||||
struct TopicTreeMessage {
|
|
||||||
std::string message;
|
|
||||||
OpCode opCode;
|
|
||||||
bool compress;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* All WebSocketContextData holds a list to all other WebSocketContextData in this app.
|
/* This one points to the App's shared topicTree */
|
||||||
* We cannot type it USERDATA since different WebSocketContextData can have different USERDATA. */
|
TopicTree<TopicTreeMessage> *topicTree;
|
||||||
std::vector<WebSocketContextData<SSL, int> *> adjacentWebSocketContextDatas;
|
|
||||||
|
|
||||||
/* The callbacks for this context */
|
/* The callbacks for this context */
|
||||||
MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *)> openHandler = nullptr;
|
MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *)> openHandler = nullptr;
|
||||||
@@ -75,9 +68,6 @@ public:
|
|||||||
/* These are calculated on creation */
|
/* These are calculated on creation */
|
||||||
std::pair<unsigned short, unsigned short> idleTimeoutComponents;
|
std::pair<unsigned short, unsigned short> idleTimeoutComponents;
|
||||||
|
|
||||||
/* Each websocket context has a topic tree for pub/sub */
|
|
||||||
TopicTree<TopicTreeMessage> topicTree;
|
|
||||||
|
|
||||||
/* This is run once on start-up */
|
/* This is run once on start-up */
|
||||||
void calculateIdleTimeoutCompnents(unsigned short idleTimeout) {
|
void calculateIdleTimeoutCompnents(unsigned short idleTimeout) {
|
||||||
unsigned short margin = 4;
|
unsigned short margin = 4;
|
||||||
@@ -92,55 +82,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~WebSocketContextData() {
|
~WebSocketContextData() {
|
||||||
/* We must unregister any loop post handler here */
|
|
||||||
Loop::get()->removePostHandler(this);
|
|
||||||
Loop::get()->removePreHandler(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketContextData() : topicTree([](Subscriber *s, TopicTreeMessage &message, auto flags) {
|
WebSocketContextData(TopicTree<TopicTreeMessage> *topicTree) : topicTree(topicTree) {
|
||||||
/* Subscriber's user is the socket */
|
|
||||||
auto *ws = (WebSocket<SSL, true, USERDATA> *) s->user;
|
|
||||||
|
|
||||||
/* If this is the first message we try and cork */
|
|
||||||
bool needsUncork = false;
|
|
||||||
if (flags & TopicTree<TopicTreeMessage>::IteratorFlags::FIRST) {
|
|
||||||
if (ws->canCork() && !ws->isCorked()) {
|
|
||||||
((AsyncSocket<SSL> *)ws)->cork();
|
|
||||||
needsUncork = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we ever overstep maxBackpresure, exit immediately */
|
|
||||||
if (WebSocket<SSL, true, USERDATA>::SendStatus::DROPPED == ws->send(message.message, message.opCode, message.compress)) {
|
|
||||||
|
|
||||||
if (needsUncork) {
|
|
||||||
((AsyncSocket<SSL> *)ws)->uncork();
|
|
||||||
}
|
|
||||||
/* Stop draining */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If this is the last message we uncork if we are corked */
|
|
||||||
if (flags & TopicTree<TopicTreeMessage>::IteratorFlags::LAST) {
|
|
||||||
/* We should not uncork in all cases? */
|
|
||||||
if (needsUncork) {
|
|
||||||
((AsyncSocket<SSL> *)ws)->uncork();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Success */
|
|
||||||
return false;
|
|
||||||
}) {
|
|
||||||
/* We empty for both pre and post just to make sure */
|
|
||||||
Loop::get()->addPostHandler(this, [this](Loop */*loop*/) {
|
|
||||||
/* Commit pub/sub batches every loop iteration */
|
|
||||||
topicTree.drain();
|
|
||||||
});
|
|
||||||
|
|
||||||
Loop::get()->addPreHandler(this, [this](Loop */*loop*/) {
|
|
||||||
/* Commit pub/sub batches every loop iteration */
|
|
||||||
topicTree.drain();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user