mirror of
https://github.com/ohwgiles/laminar.git
synced 2024-10-27 20:34:20 +00:00
improve websocket handling
The previous implementation meant that messages could get lost if both sending and receiving were scheduled to be processed in the same event loop cycle. This commit separates the two channels more clearly, while still allowing the close event in the receive side to cancel the whole pipeline Part of #49 refactor
This commit is contained in:
parent
4c2aa2680f
commit
078e0e9882
@ -218,10 +218,9 @@ private:
|
|||||||
kj::Own<kj::PromiseFulfiller<void>> fulfiller;
|
kj::Own<kj::PromiseFulfiller<void>> fulfiller;
|
||||||
};
|
};
|
||||||
|
|
||||||
kj::Promise<void> handleWebsocket(WebsocketClient& lc) {
|
kj::Promise<void> websocketRead(WebsocketClient& lc)
|
||||||
auto paf = kj::newPromiseAndFulfiller<void>();
|
{
|
||||||
lc.fulfiller = kj::mv(paf.fulfiller);
|
return lc.ws->receive().then([&lc,this](kj::WebSocket::Message&& message) {
|
||||||
return lc.ws->receive().then([&lc,this](kj::WebSocket::Message&& message) -> kj::Promise<bool> {
|
|
||||||
KJ_SWITCH_ONEOF(message) {
|
KJ_SWITCH_ONEOF(message) {
|
||||||
KJ_CASE_ONEOF(str, kj::String) {
|
KJ_CASE_ONEOF(str, kj::String) {
|
||||||
rapidjson::Document d;
|
rapidjson::Document d;
|
||||||
@ -230,31 +229,36 @@ private:
|
|||||||
int page = d["page"].GetInt();
|
int page = d["page"].GetInt();
|
||||||
lc.scope.page = page;
|
lc.scope.page = page;
|
||||||
laminar.sendStatus(&lc);
|
laminar.sendStatus(&lc);
|
||||||
// freeze this promise. sendStatus will cause the other half of
|
return websocketRead(lc);
|
||||||
// exclusiveJoin below to proceed and this branch will be cancelled
|
|
||||||
return kj::NEVER_DONE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KJ_CASE_ONEOF(close, kj::WebSocket::Close) {
|
KJ_CASE_ONEOF(close, kj::WebSocket::Close) {
|
||||||
// clean socket shutdown
|
// clean socket shutdown
|
||||||
return lc.ws->close(close.code, close.reason).then([]{return false;});
|
return lc.ws->close(close.code, close.reason);
|
||||||
}
|
}
|
||||||
KJ_CASE_ONEOF_DEFAULT {}
|
KJ_CASE_ONEOF_DEFAULT {}
|
||||||
}
|
}
|
||||||
// unhandled/unknown message
|
// unhandled/unknown message
|
||||||
return lc.ws->disconnect().then([]{return false;});
|
return lc.ws->disconnect();
|
||||||
}).exclusiveJoin(kj::mv(paf.promise).then([&lc]{
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
kj::Promise<void> websocketWrite(WebsocketClient& lc)
|
||||||
|
{
|
||||||
|
auto paf = kj::newPromiseAndFulfiller<void>();
|
||||||
|
lc.fulfiller = kj::mv(paf.fulfiller);
|
||||||
|
return paf.promise.then([this,&lc]{
|
||||||
kj::Promise<void> p = kj::READY_NOW;
|
kj::Promise<void> p = kj::READY_NOW;
|
||||||
for(std::string& s : lc.messages) {
|
std::list<std::string> messages = kj::mv(lc.messages);
|
||||||
|
for(std::string& s : messages) {
|
||||||
p = p.then([&s,&lc]{
|
p = p.then([&s,&lc]{
|
||||||
kj::String str = kj::str(s);
|
kj::String str = kj::str(s);
|
||||||
return lc.ws->send(str).attach(kj::mv(str));
|
return lc.ws->send(str).attach(kj::mv(str));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return p.then([]{return true;});
|
return p.attach(kj::mv(messages)).then([this,&lc]{
|
||||||
//return lc.ws->send(str).attach(kj::mv(str)).then([]{ return true;});
|
return websocketWrite(lc);
|
||||||
})).then([this,&lc](bool cont){
|
});
|
||||||
return cont ? handleWebsocket(lc) : kj::READY_NOW;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +289,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
laminar.registerClient(&lc);
|
laminar.registerClient(&lc);
|
||||||
kj::Promise<void> connection = handleWebsocket(lc);
|
kj::Promise<void> connection = websocketRead(lc).exclusiveJoin(websocketWrite(lc));
|
||||||
// registerClient can happen after a successful websocket handshake.
|
// registerClient can happen after a successful websocket handshake.
|
||||||
// However, the connection might not be closed gracefully, so the
|
// However, the connection might not be closed gracefully, so the
|
||||||
// corresponding deregister operation happens in the WebsocketClient
|
// corresponding deregister operation happens in the WebsocketClient
|
||||||
|
Loading…
Reference in New Issue
Block a user