Add Session::ClosedHandler (#99)
A callback function to signal that the endpoint has closed its connection. Add this as an optional argument to Session::bind() and Session::startProcessingMessages(). Bug: #98
This commit is contained in:
@@ -65,7 +65,7 @@ class Impl : public dap::Session {
|
||||
void connect(const std::shared_ptr<dap::Reader>& r,
|
||||
const std::shared_ptr<dap::Writer>& w) override {
|
||||
if (isBound.exchange(true)) {
|
||||
handlers.error("Session is already bound!");
|
||||
handlers.error("Session::connect called twice");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -73,13 +73,21 @@ class Impl : public dap::Session {
|
||||
writer = dap::ContentWriter(w);
|
||||
}
|
||||
|
||||
void startProcessingMessages() override {
|
||||
recvThread = std::thread([this] {
|
||||
void startProcessingMessages(
|
||||
const ClosedHandler& onClose /* = {} */) override {
|
||||
if (isProcessingMessages.exchange(true)) {
|
||||
handlers.error("Session::startProcessingMessages() called twice");
|
||||
return;
|
||||
}
|
||||
recvThread = std::thread([this, onClose] {
|
||||
while (reader.isOpen()) {
|
||||
if (auto payload = getPayload()) {
|
||||
inbox.put(std::move(payload));
|
||||
}
|
||||
}
|
||||
if (onClose) {
|
||||
onClose();
|
||||
}
|
||||
});
|
||||
|
||||
dispatchThread = std::thread([this] {
|
||||
@@ -398,17 +406,17 @@ class Impl : public dap::Session {
|
||||
// "body" is an optional field for some events, such as "Terminated Event".
|
||||
bool body_ok = true;
|
||||
d->field("body", [&](dap::Deserializer* d) {
|
||||
if (!typeinfo->deserialize(d, data)) {
|
||||
body_ok = false;
|
||||
}
|
||||
return true;
|
||||
if (!typeinfo->deserialize(d, data)) {
|
||||
body_ok = false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!body_ok) {
|
||||
handlers.error("Failed to deserialize event '%s' body", event.c_str());
|
||||
typeinfo->destruct(data);
|
||||
delete[] data;
|
||||
return {};
|
||||
handlers.error("Failed to deserialize event '%s' body", event.c_str());
|
||||
typeinfo->destruct(data);
|
||||
delete[] data;
|
||||
return {};
|
||||
}
|
||||
|
||||
return [=] {
|
||||
@@ -471,6 +479,7 @@ class Impl : public dap::Session {
|
||||
}
|
||||
|
||||
std::atomic<bool> isBound = {false};
|
||||
std::atomic<bool> isProcessingMessages = {false};
|
||||
dap::ContentReader reader;
|
||||
dap::ContentWriter writer;
|
||||
|
||||
|
||||
@@ -579,3 +579,47 @@ TEST_F(SessionTest, Concurrency) {
|
||||
client.reset();
|
||||
server.reset();
|
||||
}
|
||||
|
||||
TEST_F(SessionTest, OnClientClosed) {
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
bool clientClosed = false;
|
||||
|
||||
auto client2server = dap::pipe();
|
||||
auto server2client = dap::pipe();
|
||||
|
||||
client->bind(server2client, client2server);
|
||||
server->bind(client2server, server2client, [&] {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
clientClosed = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
|
||||
client.reset();
|
||||
|
||||
// Wait for the client closed handler to be called.
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
cv.wait(lock, [&] { return static_cast<bool>(clientClosed); });
|
||||
}
|
||||
|
||||
TEST_F(SessionTest, OnServerClosed) {
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
bool serverClosed = false;
|
||||
|
||||
auto client2server = dap::pipe();
|
||||
auto server2client = dap::pipe();
|
||||
|
||||
client->bind(server2client, client2server, [&] {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
serverClosed = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
server->bind(client2server, server2client);
|
||||
|
||||
server.reset();
|
||||
|
||||
// Wait for the client closed handler to be called.
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
cv.wait(lock, [&] { return static_cast<bool>(serverClosed); });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user