summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-01-28 20:31:24 +0100
committerRoland Reichwein <mail@reichwein.it>2023-01-28 20:31:24 +0100
commita69b1d0c580bc779740ef79a7d16b69229896785 (patch)
tree962ecac93c521c1d09f1dc1ca727b7121d1b5472
parentdd358ac5cdfc2b449dcbe94a33a06a7540d8f966 (diff)
Client to Server: send diffs instead of whole file
-rw-r--r--diff.cpp29
-rw-r--r--diff.h3
-rw-r--r--html/whiteboard.js27
-rw-r--r--webassembly/Makefile10
-rw-r--r--whiteboard.cpp34
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 <algorithm>
+#include <iostream>
#include <sstream>
#include <boost/property_tree/xml_parser.hpp>
@@ -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<int>("diff.start");
+ m_pos1 = ptree.get<int>("diff.end");
+
+ if (m_pos0 > m_pos1)
+ throw std::runtime_error("Bad range in diff");
+
+ m_data = ptree.get<std::string>("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<int>("diff.start");
- m_pos1 = tree.get<int>("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<std::string>("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<std::string>("request.id")};
- std::string data {xml.get<std::string>("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<int>("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<int>("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<int>("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<std::string>("request.id")};
int pos {xml.get<int>("request.pos")};