summaryrefslogtreecommitdiffhomepage
path: root/whiteboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'whiteboard.cpp')
-rw-r--r--whiteboard.cpp100
1 files changed, 71 insertions, 29 deletions
diff --git a/whiteboard.cpp b/whiteboard.cpp
index 6782385..b15ebbe 100644
--- a/whiteboard.cpp
+++ b/whiteboard.cpp
@@ -93,7 +93,30 @@ std::string make_xml(const std::initializer_list<std::pair<std::string, std::str
return oss.str();
}
-std::string Whiteboard::handle_request(const std::string& request)
+void Whiteboard::notify_other_connections(Whiteboard::connection& c, const std::string& id)
+{
+ std::for_each(m_registry.begin(id), m_registry.end(id), [&](const Whiteboard::connection& ci)
+ {
+ if (c != ci) {
+ boost::beast::flat_buffer buffer;
+ boost::beast::ostream(buffer) << make_xml({
+ {"type", "getfile"},
+ {"data", m_storage->getDocument(id)},
+ {"revision", std::to_string(m_storage->getRevision(id)) },
+ {"cursorpos", std::to_string(m_storage->getCursorPos(id)) }
+ });
+ std::lock_guard<std::mutex> lock(m_websocket_mutex);
+ try {
+ ci->write(buffer.data());
+ } catch (const std::exception& ex) {
+ std::cerr << "Warning: Notify write for " << ci << " not possible, id " << id << std::endl;
+ m_registry.dump();
+ }
+ }
+ });
+}
+
+std::string Whiteboard::handle_request(Whiteboard::connection& c, const std::string& request)
{
try {
std::lock_guard<std::mutex> lock(m_storage_mutex);
@@ -109,27 +132,41 @@ std::string Whiteboard::handle_request(const std::string& request)
if (command == "modify") {
std::string id {xml.get<std::string>("request.id")};
std::string data {xml.get<std::string>("request.data")};
- m_storage->setDocument(id, data);
- return make_xml({{"type", "modify"}, {"revision", std::to_string(m_storage->getRevision(id)) }});
+ if (m_storage->getDocument(id) != data) {
+ m_storage->setDocument(id, data);
+ m_registry.setId(c, id);
+ notify_other_connections(c, id);
+ return make_xml({{"type", "modify"}, {"revision", std::to_string(m_storage->getRevision(id)) }});
+ }
+ return {};
+ } else if (command == "cursorpos") {
+ std::string id {xml.get<std::string>("request.id")};
+ int pos {xml.get<int>("request.pos")};
+ if (m_storage->getCursorPos(id) != pos) {
+ m_storage->setCursorPos(id, pos);
+ notify_other_connections(c, id);
+ }
+ return {};
} else if (command == "getfile") {
std::string id {xml.get<std::string>("request.id")};
- std::string filedata {m_storage->getDocument(id)};
+ std::string filedata;
+ try {
+ filedata = m_storage->getDocument(id);
+ } catch (const std::runtime_error&) {
+ m_storage->setDocument(id, filedata);
+ }
if (filedata.size() > 30000000)
throw std::runtime_error("File too big");
-
- return make_xml({{"type", "getfile"}, {"data", filedata}, {"revision", std::to_string(m_storage->getRevision(id)) }});
- } else if (command == "checkupdate") {
- std::string id {xml.get<std::string>("request.id")};
- int request_revision {xml.get<int>("request.revision")};
-
- int revision {m_storage->getRevision(id)};
- if (revision != request_revision) {
- return make_xml({{"type", "update"}, {"data", m_storage->getDocument(id)}, {"revision", std::to_string(revision) }});
- } else {
- return {}; // no reply
- }
+ m_registry.setId(c, id);
+
+ return make_xml({
+ {"type", "getfile"},
+ {"data", filedata},
+ {"revision", std::to_string(m_storage->getRevision(id)) },
+ {"cursorpos", std::to_string(m_storage->getCursorPos(id)) }
+ });
} else if (command == "newid") {
return make_xml({{"type", "newid"}, {"id", m_storage->generate_id()}});
} else if (command == "qrcode") {
@@ -146,7 +183,7 @@ std::string Whiteboard::handle_request(const std::string& request)
}
} catch (const std::exception& ex) {
- return "Message handling error: "s + ex.what();
+ return make_xml({{"type", "error"}, {"message", "Message handling error: "s + ex.what()}});
}
}
@@ -154,10 +191,11 @@ void Whiteboard::do_session(boost::asio::ip::tcp::socket socket)
{
try {
// Construct the stream by moving in the socket
- boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(socket)};
+ std::shared_ptr ws{std::make_shared<boost::beast::websocket::stream<boost::asio::ip::tcp::socket>>(std::move(socket))};
+ ConnectionRegistry::RegistryGuard guard(m_registry, ws);
// Set a decorator to change the Server of the handshake
- ws.set_option(boost::beast::websocket::stream_base::decorator(
+ ws->set_option(boost::beast::websocket::stream_base::decorator(
[](boost::beast::websocket::response_type& res)
{
res.set(boost::beast::http::field::server,
@@ -168,27 +206,31 @@ void Whiteboard::do_session(boost::asio::ip::tcp::socket socket)
boost::beast::http::request<boost::beast::http::string_body> req;
boost::beast::flat_buffer buffer;
- boost::beast::http::read(ws.next_layer(), buffer, parser);
+ boost::beast::http::read(ws->next_layer(), buffer, parser);
req = parser.get();
- ws.accept(req);
+ ws->accept(req);
while (true) {
boost::beast::flat_buffer buffer;
- ws.read(buffer);
+ ws->read(buffer);
- ws.text(ws.got_text());
+ ws->text(ws->got_text());
std::string data(boost::asio::buffers_begin(buffer.data()), boost::asio::buffers_end(buffer.data()));
- data = handle_request(data);
- buffer.consume(buffer.size());
- boost::beast::ostream(buffer) << data;
- if (buffer.data().size() > 0)
- ws.write(buffer.data());
+ data = handle_request(ws, data);
+ if (buffer.data().size() > 0) {
+ buffer.consume(buffer.size());
+ }
+ if (data.size() > 0) {
+ boost::beast::ostream(buffer) << data;
+ std::lock_guard<std::mutex> lock(m_websocket_mutex);
+ ws->write(buffer.data());
+ }
}
} catch (boost::beast::system_error const& se) {
// This indicates that the session was closed
- if (se.code() != boost::beast::websocket::error::closed)
+ if (se.code() != boost::beast::websocket::error::closed && se.code() != boost::asio::error::eof)
std::cerr << "Boost system_error in session: " << se.code().message() << std::endl;
} catch (std::exception const& ex) {
std::cerr << "Error in session: " << ex.what() << std::endl;