From 9417a11576f221d6c098d4ff1d0ad3cc37cfe31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ozan=20E=C4=9Fitmen?= Date: Wed, 25 Mar 2020 21:45:06 +0300 Subject: [PATCH 1/3] Add new features --- .idea/.gitignore | 2 + .idea/dictionaries/ozan.xml | 7 + .idea/misc.xml | 6 + .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 + .idea/whitebophir.iml | 8 ++ .vscode/settings.json | 5 + client-data/board.css | 4 + client-data/board.html | 2 + client-data/js/board.js | 1 + client-data/tools/background/background.js | 37 ++++++ client-data/tools/pointer/pointer.css | 16 +++ client-data/tools/pointer/pointer.js | 93 ++++++++++++++ package-lock.json | 142 ++++++++++++++++++--- package.json | 4 + server/boardData.js | 56 ++++---- server/createSVG.js | 31 +++-- server/minio.js | 26 ++++ 18 files changed, 404 insertions(+), 50 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/dictionaries/ozan.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/whitebophir.iml create mode 100644 .vscode/settings.json create mode 100644 client-data/tools/background/background.js create mode 100644 client-data/tools/pointer/pointer.css create mode 100644 client-data/tools/pointer/pointer.js create mode 100644 server/minio.js diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..e7e9d11d --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml diff --git a/.idea/dictionaries/ozan.xml b/.idea/dictionaries/ozan.xml new file mode 100644 index 00000000..deb7005f --- /dev/null +++ b/.idea/dictionaries/ozan.xml @@ -0,0 +1,7 @@ + + + + minio + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..28a804d8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..6049530d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/whitebophir.iml b/.idea/whitebophir.iml new file mode 100644 index 00000000..c956989b --- /dev/null +++ b/.idea/whitebophir.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..c6826029 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "onquit" + ] +} \ No newline at end of file diff --git a/client-data/board.css b/client-data/board.css index a673f130..a381dea3 100644 --- a/client-data/board.css +++ b/client-data/board.css @@ -4,6 +4,10 @@ html, body, svg { font-family: Liberation sans, sans-serif; } +body { + overflow: hidden; +} + #canvas { transform-origin: 0 0; } diff --git a/client-data/board.html b/client-data/board.html index 86582338..f230ac80 100644 --- a/client-data/board.html +++ b/client-data/board.html @@ -89,6 +89,8 @@ + + diff --git a/client-data/js/board.js b/client-data/js/board.js index 8101f471..bff46863 100644 --- a/client-data/js/board.js +++ b/client-data/js/board.js @@ -153,6 +153,7 @@ Tools.change = function (toolName) { //Call the start callback of the new tool newtool.onstart(Tools.curTool); + Tools.prevToolName = curToolName; Tools.curTool = newtool; }; diff --git a/client-data/tools/background/background.js b/client-data/tools/background/background.js new file mode 100644 index 00000000..1daf4066 --- /dev/null +++ b/client-data/tools/background/background.js @@ -0,0 +1,37 @@ +// This isn't an HTML5 canvas, it's an old svg hack, (the code is _that_ old!) +const fakeCanvas = document.getElementById("canvas"); +const uid = Tools.generateUID("b"); // b for background + +function onstart() { + const fileInput = document.createElement("input"); + fileInput.type = "file"; + fileInput.accept = "image/*"; + + fileInput.addEventListener("change", () => { + const file = fileInput.files[0]; + + Tools.drawAndSend({ + id: uid, + data: file, + fileType: file.type + }, "Background"); + Tools.change(Tools.prevToolName); + }); + + fileInput.click(); +} + +function draw(msg, self) { + const file = self ? msg.data : new Blob([msg.data], { type: msg.fileType }); + const fileURL = URL.createObjectURL(file); + + fakeCanvas.style.background = `url("${fileURL}") 170px 0px no-repeat`; +} + +Tools.add({ + "name": "Background", + "icon": "🖼️", + "shortcut": "b", + "draw": draw, + "onstart": onstart +}); diff --git a/client-data/tools/pointer/pointer.css b/client-data/tools/pointer/pointer.css new file mode 100644 index 00000000..ccbd0e19 --- /dev/null +++ b/client-data/tools/pointer/pointer.css @@ -0,0 +1,16 @@ +.pointer { + position: absolute; + font-size: 2.5rem; + visibility: hidden; + transform: translate(-50%, -50%); + cursor: none; + border-radius: 40%; +} + +.pointer.visible { + visibility: visible; +} + +.pointer.highlight { + background-color: cornflowerblue; +} diff --git a/client-data/tools/pointer/pointer.js b/client-data/tools/pointer/pointer.js new file mode 100644 index 00000000..910014ee --- /dev/null +++ b/client-data/tools/pointer/pointer.js @@ -0,0 +1,93 @@ +const uid = Tools.generateUID("f"); // f for finger +let lastTime = performance.now(); + +const pointer = document.createElement("div"); +pointer.classList.add("pointer"); +pointer.innerHTML = "👆"; + +Tools.board.appendChild(pointer); + +function movePointer(x, y) { + pointer.style.left = `${x * Tools.scale}px`; + pointer.style.top = `${y * Tools.scale}px`; + + // TODO: Could find a better solution for JIP + if (!pointer.classList.contains("visible")) { + showPointer(true, false); + } +} + +function move(x, y) { + movePointer(x, y); + + if (performance.now() - lastTime > 70) { + Tools.send({ + id: uid, + type: "update", + action: "move", + x, + y + }, "Pointer"); + lastTime = performance.now(); + } +} + +function draw(msg) { + switch (msg.action) { + case "move": + movePointer(msg.x, msg.y); + break; + case "show": + showPointer(true, false); + break; + case "hide": + showPointer(false, false); + break; + case "highlight": + highlightPointer(true, false); + break; + case "noHighlight": + highlightPointer(false, false); + break; + } +} + +function highlightPointer(highlight, self) { + pointer.classList.toggle("highlight", highlight); + + if (self) { + Tools.send({ + id: uid, + type: "update", + action: highlight ? "highlight" : "noHighlight" + }, "Pointer"); + } +} + +function showPointer(show, self) { + pointer.classList.toggle("visible", show); + + if (self) { + Tools.send({ + id: uid, + type: "update", + action: show ? "show" : "hide" + }, "Pointer"); + } +} + +Tools.add({ + "name": "Pointer", + "icon": "👆", + "shortcut": "f", + "listeners": { + "press": () => highlightPointer(true, true), + "move": move, + "release": () => highlightPointer(false, true) + }, + "draw": draw, + "onstart": () => showPointer(true, true), + "onquit": () => showPointer(false, true), + "mouseCursor": "none", + "stylesheet": "tools/pointer/pointer.css" +}); diff --git a/package-lock.json b/package-lock.json index c80c7792..ef882e7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,46 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", + "dev": true + }, + "@types/minio": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/minio/-/minio-7.0.5.tgz", + "integrity": "sha512-lbZSyinS73XTJ9u4PTO3oVbv1qKzubqtp4hDCxfG36fAGNLPMBDMNcxC8jfs6ezc3kliGXwZy4/8eh4HvyVO4Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "12.12.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.31.tgz", + "integrity": "sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg==", + "dev": true + }, + "@types/node-static": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@types/node-static/-/node-static-0.7.3.tgz", + "integrity": "sha512-Jxj+S/xHWg+0OV5cY1X6rPFY028wzOng8u8J1smda7pg9ij7EWaViBrSGmo3u9GovHQ3wGRBSnepKCWKt5WdmQ==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/socket.io": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.4.tgz", + "integrity": "sha512-cI98INy7tYnweTsUlp8ocveVdAxENUThO0JsLSCs51cjOP2yV5Mqo5QszMDPckyRRA+PO6+wBgKvGvHUCc23TQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -236,6 +276,14 @@ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, + "block-stream2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.0.0.tgz", + "integrity": "sha512-1oI+RHHUEo64xomy1ozLgVJetFlHkIfQfJzTBQrj6xWnEMEPooeo2fZoqFjp0yzfHMBrgxwgh70tKp6T17+i3g==", + "requires": { + "readable-stream": "^3.4.0" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -578,6 +626,11 @@ "has-binary2": "~1.0.2" } }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -772,8 +825,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "is-extglob": { "version": "2.1.1", @@ -826,6 +878,11 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz", + "integrity": "sha1-GjhU4o0rvuqzHMfd9oPS3cVlJwg=" + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -873,8 +930,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash.defaults": { "version": "4.2.0", @@ -945,14 +1001,12 @@ "mime-db": { "version": "1.43.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", - "dev": true + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" }, "mime-types": { "version": "2.1.26", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "dev": true, "requires": { "mime-db": "1.43.0" } @@ -977,11 +1031,35 @@ "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" }, + "minio": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/minio/-/minio-7.0.15.tgz", + "integrity": "sha512-ucZnLNUQgQV+/S8FfyO40yM/X8gVcw8WRcoGH5WWk4xQwKAp4K/xjooHwkV0Oc3Iu/6WZDnGQ+Nf4I4XIzl9eA==", + "requires": { + "async": "^3.1.0", + "block-stream2": "^2.0.0", + "es6-error": "^4.1.1", + "json-stream": "^1.0.0", + "lodash": "^4.14.2", + "mime-types": "^2.1.14", + "mkdirp": "^0.5.1", + "querystring": "0.2.0", + "through2": "^3.0.1", + "xml": "^1.0.0", + "xml2js": "^0.4.15" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + } + } + }, "mkdirp": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", - "dev": true, "requires": { "minimist": "^1.2.5" }, @@ -989,8 +1067,7 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } }, @@ -1235,6 +1312,11 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -1248,7 +1330,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1311,8 +1392,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -1320,6 +1400,11 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "sha1-file": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/sha1-file/-/sha1-file-1.0.4.tgz", @@ -1546,7 +1631,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -1582,6 +1666,14 @@ "readable-stream": "^3.1.1" } }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + } + }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", @@ -1642,8 +1734,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utile": { "version": "0.3.0", @@ -1747,6 +1838,25 @@ "async-limiter": "~1.0.0" } }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", diff --git a/package.json b/package.json index 9376d799..3377fcd6 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "AGPL-3.0-or-later", "dependencies": { "handlebars": "^4.7.3", + "minio": "^7.0.15", "node-static": "^0.7.11", "socket.io": "^2.3.0" }, @@ -23,6 +24,9 @@ "url": "http://github.com/lovasoa/whitebophir.git" }, "devDependencies": { + "@types/minio": "^7.0.5", + "@types/node-static": "^0.7.3", + "@types/socket.io": "^2.1.4", "openode": "^2.0.15" } } diff --git a/server/boardData.js b/server/boardData.js index 55edc0aa..9fb661a3 100644 --- a/server/boardData.js +++ b/server/boardData.js @@ -25,17 +25,10 @@ * @module boardData */ -var fs = require('fs') +var { minioClient, bucketName } = require("./minio") , log = require("./log.js").log , path = require("path"); -/** @constant - @type {string} - @default - Path to the file where boards will be saved by default -*/ -var HISTORY_DIR = path.join(__dirname, "../server-data/"); - /** @constant @type {Number} @default @@ -54,7 +47,7 @@ var MAX_BOARD_SIZE = 65536; // Maximum value for any x or y on the board var BoardData = function (name) { this.name = name; this.board = {}; - this.file = path.join(HISTORY_DIR, "board-" + encodeURIComponent(name) + ".json"); + this.file = "board-" + encodeURIComponent(name) + ".json"; this.lastSaveDate = Date.now(); this.users = new Set(); }; @@ -179,10 +172,8 @@ BoardData.prototype.save = function (file) { }); } } - fs.writeFile(tmp_file, board_txt, function onBoardSaved(err) { - if (err) afterSave(err); - else fs.rename(tmp_file, file, afterSave); - }); + + minioClient.putObject(bucketName, file, board_txt, afterSave); }; /** Remove old elements from the board */ @@ -234,26 +225,43 @@ BoardData.prototype.validate = function validate(item, parent) { BoardData.load = function loadBoard(name) { var boardData = new BoardData(name); return new Promise((accept) => { - fs.readFile(boardData.file, function (err, data) { - try { - if (err) throw err; - boardData.board = JSON.parse(data); - for (id in boardData.board) boardData.validate(boardData.board[id]); - log('disk load', { 'board': boardData.name }); - } catch (e) { - console.error("Unable to read history from " + boardData.file + ". The following error occured: " + e); + minioClient.getObject(bucketName, boardData.file, (err, dataStream) => { + const buffer = []; + + function catchCallback(err, hack) { + console.error("Unable to read history from " + boardData.file + ". The following error occurred: " + err); log('empty board creation', { 'board': boardData.name }); - boardData.board = {} + boardData.board = {}; + const data = Buffer.concat(buffer).toString("utf-8"); if (data) { // There was an error loading the board, but some data was still read var backup = backupFileName(boardData.file); log("Writing the corrupted file to " + backup); - fs.writeFile(backup, data, function (err) { + minioClient.putObject(bucketName, backup, data, err => { if (err) log("Error writing " + backup + ": " + err); }); } + if (hack) { + accept(boardData); + } + } + + if (err) { + catchCallback(err, true); + return; } - accept(boardData); + + dataStream.on("data", buffer.push); + dataStream.on("end", () => { + try { + boardData.board = Buffer.concat(buffer).toJSON(); // TODO: Might have to do string -> json first + for (id in boardData.board) boardData.validate(boardData.board[id]); + log('disk load', { 'board': boardData.name }); + } catch (err) { + catchCallback(err, false); + } + accept(boardData); + }); }); }); }; diff --git a/server/createSVG.js b/server/createSVG.js index 39f77b6f..fa014c43 100644 --- a/server/createSVG.js +++ b/server/createSVG.js @@ -1,4 +1,4 @@ -var fs = require("fs"), +var { minioClient, bucketName } = require("./minio"), path = require("path"); function htmlspecialchars(str) { @@ -92,16 +92,27 @@ function toSVG(obj) { function renderBoard(file, callback) { var t = Date.now(); - fs.readFile(file, function (err, data) { - if (err) return callback(err); - try { - var board = JSON.parse(data); - console.warn("JSON parsed in " + (Date.now() - t) + "ms."); - var svg = toSVG(board); - console.warn("Board rendered in " + (Date.now() - t) + "ms."); - callback(null, svg); + + minioClient.getObject(bucketName, file, (err, dataStream) => { + if (err) { + return callback(err); } - catch (err) { return callback(err) } + + const buffer = []; + + dataStream.on("data", buffer.push); + dataStream.on("error", callback); + dataStream.on("end", () => { + try { + const board = Buffer.concat(buffer).toJSON(); // TODO: Might have to do string -> json first + console.warn("JSON parsed in " + (Date.now() - t) + "ms."); + const svg = toSVG(board); + console.warn("Board rendered in " + (Date.now() - t) + "ms."); + callback(null, svg); + } catch (err) { + callback(err); + } + }); }); } diff --git a/server/minio.js b/server/minio.js new file mode 100644 index 00000000..d38ccc00 --- /dev/null +++ b/server/minio.js @@ -0,0 +1,26 @@ +const Minio = require("minio"); + +// Minio configuration +const minioClient = new Minio.Client({ + endPoint: "YourEndPointAddressHere", + port: 9000, + useSSL: false, + accessKey: "YourAccessKeyHere", + secretKey: "YourSecretKeyHere" +}); +const bucketName = "server-data"; + +// Create default bucket if it doesn't exists +minioClient.bucketExists(bucketName, (err, bucketExists) => { + if (bucketExists) { + return; + } + + console.log(`Default bucket "${bucketName}" doesn't exist, creating it...`); + minioClient.makeBucket(bucketName, "", () => { + console.log(`Successfully created default bucket "${bucketName}"`); + }); +}); + +module.exports.bucketName = bucketName; +module.exports.minioClient = minioClient; From 446c60e1c77cb3a8b40fdcf873d43cd85066e47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ozan=20E=C4=9Fitmen?= Date: Wed, 25 Mar 2020 21:55:17 +0300 Subject: [PATCH 2/3] Update README about the new features --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 1f65582f..e1da7b1b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +> Hi. This is a fork of the original project. It adds couple of small features (2 new tools and minio support). They are described briefly at the bottom of this README. + # WBO WBO is an online collaborative whiteboard that allows many users to draw simultaneously on a large virtual board. @@ -73,3 +75,12 @@ If you do that, the code is running directly on your machine, without any isolat ## Troubleshooting If you experience an issue or want to propose a new feature in WBO, please [open a github issue](https://github.com/lovasoa/whitebophir/issues/new). + + +### Additional Features +#### Two new tools: +- Background (Shortcut: `b`): Allows you to upload an image for the background of the canvas. +- Pointer (Shortcut: `f`): Allows users to point at things for others to see. + +#### Minio suport: +- Instead of writing to the filesystem, the server now saves boards to a minio instance. The configuration is inside [server/minio.js](server/minio.js). From 17516e040d8a2ceb51324f58ba8e3b986b7aedd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ozan=20E=C4=9Fitmen?= Date: Wed, 25 Mar 2020 21:58:23 +0300 Subject: [PATCH 3/3] Make the fact that this is a fork stand out more --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e1da7b1b..89e38327 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -> Hi. This is a fork of the original project. It adds couple of small features (2 new tools and minio support). They are described briefly at the bottom of this README. +# 654wak654 Fork +Hi. This is a fork of the original project. It adds couple of small features (2 new tools and minio support). They are described briefly at the bottom of this README. # WBO