From a69b1d0c580bc779740ef79a7d16b69229896785 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 28 Jan 2023 20:31:24 +0100 Subject: Client to Server: send diffs instead of whole file --- diff.cpp | 29 ++++++++++++++++++++--------- diff.h | 3 +++ html/whiteboard.js | 27 +++++++++++++++++++++++---- webassembly/Makefile | 10 +++++++++- whiteboard.cpp | 34 +++++++++++++++++++++------------- 5 files changed, 76 insertions(+), 27 deletions(-) diff --git a/diff.cpp b/diff.cpp index 99a2f14..b56fd51 100644 --- a/diff.cpp +++ b/diff.cpp @@ -1,6 +1,7 @@ #include "diff.h" #include +#include #include #include @@ -102,6 +103,22 @@ void Diff::create(const std::string& old_version, const std::string& new_version m_data = new_version.substr(old_pos0, new_pos1 - new_pos0); } +Diff::Diff(const boost::property_tree::ptree& ptree) +{ + create(ptree); +} + +void Diff::create(const boost::property_tree::ptree& ptree) +{ + m_pos0 = ptree.get("diff.start"); + m_pos1 = ptree.get("diff.end"); + + if (m_pos0 > m_pos1) + throw std::runtime_error("Bad range in diff"); + + m_data = ptree.get("diff.data"); +} + Diff::Diff(const std::string& xml) { create(xml); @@ -109,17 +126,11 @@ Diff::Diff(const std::string& xml) void Diff::create(const std::string& xml) { - pt::ptree tree; + pt::ptree ptree; std::istringstream ss{xml}; - pt::read_xml(ss, tree, pt::xml_parser::no_comments | pt::xml_parser::trim_whitespace); - - m_pos0 = tree.get("diff.start"); - m_pos1 = tree.get("diff.end"); - - if (m_pos0 > m_pos1) - throw std::runtime_error("Bad range in diff"); + pt::read_xml(ss, ptree, pt::xml_parser::no_comments | pt::xml_parser::trim_whitespace); - m_data = tree.get("diff.data"); + create(ptree); } boost::property_tree::ptree Diff::get_structure() const diff --git a/diff.h b/diff.h index fbf09b1..09d0936 100644 --- a/diff.h +++ b/diff.h @@ -11,6 +11,9 @@ public: Diff(const std::string& old_version, const std::string& new_version); void create(const std::string& old_version, const std::string& new_version); + Diff(const boost::property_tree::ptree& ptree); + void create(const boost::property_tree::ptree& ptree); + Diff(const std::string& xml); void create(const std::string& xml); diff --git a/html/whiteboard.js b/html/whiteboard.js index aef4391..58023fe 100644 --- a/html/whiteboard.js +++ b/html/whiteboard.js @@ -4,6 +4,8 @@ function init() { } var revision; +var baseline = ""; // data contents relating to revision, acknowledged by server +var baseline_candidate = ""; // will become baseline, after ack by server // helper for breaking feedback loop var caretpos = 0; @@ -42,6 +44,7 @@ function on_getfile(data, rev, pos) board.value = data; } revision = rev; + baseline = data; textAreaSetPos("board", pos); } @@ -72,6 +75,7 @@ function on_version(version) function on_modify_ack(rev) { revision = rev; + baseline = baseline_candidate; } function on_message(e) { @@ -158,9 +162,6 @@ function init_board() { Module.onRuntimeInitialized = () => { connect_websocket(); }; - //Module.onRuntimeInitialized = () => { alert("DEBUG: " + Module._getnum(1) + " " + UTF8ToString(Module._getstring(allocateUTF8("abc")))); - //_free(allocateUTF8("abc")); - //}; var board = document.getElementById("board"); board.addEventListener("input", function() {on_input(); }); @@ -219,7 +220,25 @@ function on_input() dataElement.appendChild(document.createTextNode(document.getElementById("board").value)); requestElement.appendChild(dataElement); - var posElement = xmlDocument.createElement("pos"); + baseline_candidate = document.getElementById("board").value; + + var revisionElement = xmlDocument.createElement("baserev"); + revisionElement.appendChild(document.createTextNode(revision)); + requestElement.appendChild(revisionElement); + + //Module.onRuntimeInitialized = () => { alert("DEBUG: " + Module._getnum(1) + " " + UTF8ToString(Module._getstring(allocateUTF8("abc")))); + //_free(allocateUTF8("abc")); + //}; + var old_version = allocateUTF8(baseline); + var new_version = allocateUTF8(baseline_candidate); + var diff = Module._diff_create(old_version, new_version); + var diffDocument = parser.parseFromString(UTF8ToString(diff), "text/xml"); + _free(old_version); + _free(new_version); + _free(diff); + requestElement.appendChild(xmlDocument.importNode(diffDocument.getElementsByTagName("diff")[0], true)); + + var posElement = xmlDocument.createElement("pos"); posElement.appendChild(document.createTextNode(document.getElementById("board").selectionStart)); requestElement.appendChild(posElement); diff --git a/webassembly/Makefile b/webassembly/Makefile index e2898e4..df81e19 100644 --- a/webassembly/Makefile +++ b/webassembly/Makefile @@ -5,10 +5,17 @@ OBJS=diff.o CXX=em++ -CXXFLAGS=-I/usr/include -std=c++20 +CXXFLAGS=-I./include -O2 -std=c++20 LDFLAGS=-s WASM=1 -s LINKABLE=1 -s EXPORT_ALL=1 + default: $(TARGET) +$(OBJS): include + +include: + mkdir include + cp -r /usr/include/boost include/boost + $(TARGET): $(OBJS) $(CXX) $(LDFLAGS) $(OBJS) -o $(TARGETJS) cp $(TARGETJS) $(TARGET) ../html/ @@ -18,3 +25,4 @@ diff.o: ../diff.cpp clean: -rm -f *.o *.js *.wasm *.html + -rm -rf include diff --git a/whiteboard.cpp b/whiteboard.cpp index b84f7cc..059571d 100644 --- a/whiteboard.cpp +++ b/whiteboard.cpp @@ -39,6 +39,7 @@ #include "libreichwein/xml.h" #include "config.h" +#include "diff.h" #include "qrcode.h" #include "storage.h" @@ -151,20 +152,27 @@ std::string Whiteboard::handle_request(Whiteboard::connection& c, const std::str if (command == "modify") { std::string id {xml.get("request.id")}; - std::string data {xml.get("request.data")}; - if (m_storage->getDocument(id) != data) { - m_storage->setDocument(id, data); - m_registry.setId(c, id); - notify_other_connections_file(c, id); - - int pos {xml.get("request.pos")}; - if (m_storage->getCursorPos(id) != pos) { - m_storage->setCursorPos(id, pos); - notify_other_connections_pos(c, id); - } - return make_xml({{"type", "modify"}, {"revision", std::to_string(m_storage->getRevision(id)) }}); + + int baserev {xml.get("request.baserev")}; + if (baserev != m_storage->getRevision(id)) + return make_xml({{"type", "error"}, {"message", "Bad base revision ("s + std::to_string(baserev) + "). Current: "s + std::to_string(m_storage->getRevision(id)) }}); + + pt::ptree ptree; + ptree.put_child("diff", xml.get_child("request.diff")); + Diff d{ptree}; + std::string data {m_storage->getDocument(id)}; + data = d.apply(data); + + m_storage->setDocument(id, data); + m_registry.setId(c, id); + notify_other_connections_file(c, id); + + int pos {xml.get("request.pos")}; + if (m_storage->getCursorPos(id) != pos) { + m_storage->setCursorPos(id, pos); + notify_other_connections_pos(c, id); } - return {}; + return make_xml({{"type", "modify"}, {"revision", std::to_string(m_storage->getRevision(id)) }}); } else if (command == "cursorpos") { std::string id {xml.get("request.id")}; int pos {xml.get("request.pos")}; -- cgit v1.2.3