diff --git a/src/Daisy/Ref.py b/src/Daisy/Ref.py index cfaabfba..2f9622fd 100644 --- a/src/Daisy/Ref.py +++ b/src/Daisy/Ref.py @@ -1,5 +1,6 @@ from Daisy.Daisy import Daisy +# TODO: More tooling class Ref(Daisy): """ diff --git a/src/Daisy/Replica.py b/src/Daisy/Replica.py new file mode 100644 index 00000000..80be50f6 --- /dev/null +++ b/src/Daisy/Replica.py @@ -0,0 +1,12 @@ +from .Ref import Ref +import datetime + + +class Replica(Ref): + """ + A Replica is a fallback copy of a distributed asset that is updated by a queued update message + """ + lastUpdate = datetime.datetime.now() + + def __init__(self, data: dict, metadata: dict, path: str, remoteNodeID: str): + super().__init__(metadata+data, path, remoteNodeID) diff --git a/src/Splash/build.py b/src/Splash/build.py index d2089e09..18e8cef7 100755 --- a/src/Splash/build.py +++ b/src/Splash/build.py @@ -28,9 +28,11 @@ copy_tree("res", "build/res") shutil.copyfile("htmx-extensions/src/ws/ws.js", "build/res/js/ws.js") tpath = "templates/" +shutil.copyfile("res/js/p2chat.js", "templates/res/p2chat.js") +shutil.copyfile("res/css/style.css", "templates/res/style.css") for path in os.listdir(tpath): - if ("base" in path) != True: + if (("base" in path) != True) and (("res" in path) != True) : for t in os.listdir(tpath + path): if os.path.exists("build/" + path) != True: os.makedirs("build/" + path) diff --git a/src/Splash/res/css/style.css b/src/Splash/res/css/style.css index 1e1a3e30..2967befc 100755 --- a/src/Splash/res/css/style.css +++ b/src/Splash/res/css/style.css @@ -10,18 +10,20 @@ --palette-four: #61805B; --grid-columns: 8; --grid-rows: 8; + --grid-size: 20px; } +/** #controls { display: grid; grid-template-columns: repeat(var(--grid-columns), auto); gap: 5%; -} +}**/ #render { display: grid; - grid-template-columns: repeat(var(--grid-columns), 20px); - grid-template-rows: repeat(var(--grid-rows), 20px); + grid-template-columns: repeat(var(--grid-columns), var(--grid-size)); + grid-template-rows: repeat(var(--grid-rows), var(--grid-size)); border: 1px solid black; } @@ -56,4 +58,10 @@ input[type=text], input[type=number] { min-width: 150px; max-width: 150px; +} + +.cnum { + min-width: 20px !important; + max-width: 20px !important; + width: 10px !important; } \ No newline at end of file diff --git a/src/Splash/res/js/custom.js b/src/Splash/res/js/custom.js index 7c610886..b215fb43 100644 --- a/src/Splash/res/js/custom.js +++ b/src/Splash/res/js/custom.js @@ -42,123 +42,4 @@ function getCatch() { getFins(); } -// P2Chat code -function splash(that) { - //alert(parent.id); - //alert(parent.getAttribute("data-coord")); - //alert(that.value); - that.style.backgroundColor = document.querySelector("#color").value; -} -function cGen(that) { - document.getElementById("render").innerHTML = ""; - var parent = that.parentElement; - // alert("parent"); - var canvasX = Number(document.querySelector("#canvasX").value); - // alert("x"); - canvasX = Math.floor(canvasX); - document - .querySelector(":root") - .style.setProperty("--grid-rows", "" + canvasX); - // alert("grid"); - - var canvasY = Number(document.querySelector("#canvasY").value); - //alert(document.querySelector("#canvasY").value); - canvasY = Math.floor(canvasY); - document - .querySelector(":root") - .style.setProperty("--grid-columns", "" + canvasY); - //alert(canvasY); - var nodeRender = ""; - var cloneRender = ""; - var nodeControl = ""; - var cloneControl = ""; - //alert("start loop"); - for (let x = 0; x < canvasX; x++) { - for (let y = 0; y < canvasY; y++) { - //alert(" in"); - nodeRender = document.getElementById("rendertemplate"); - //alert(" past template"); - - cloneRender = nodeRender.cloneNode(true); - cloneRender.style.display = "grid"; - cloneRender.id = "i" + x + "x" + y; - if (y == 0) { - //alert(cloneRender.innerHTML); - } - document.getElementById("render").appendChild(cloneRender); - } - } -} - -function setColor(that) { - var color = that.value; - //alert(typeof color); - if (color.includes("#")) { - document.querySelector("#color").value = color; - } else { - document.querySelector("#color").value = "#" + color; - document.querySelector("#picker").value = "#" + color; - } -} - -function saveAs(uri, filename) { - var link = document.createElement("a"); - if (typeof link.download === "string") { - link.href = uri; - link.download = filename; - - //Firefox requires the link to be in the body - document.body.appendChild(link); - - //simulate click - link.click(); - - //remove the link when done - document.body.removeChild(link); - } else { - window.open(uri); - } -} - -function save(toFile) { - var canvas = document.createElement("canvas"); - var canvasX = Number(document.querySelector("#canvasX").value); - var canvasY = Number(document.querySelector("#canvasY").value); - //alert(canvasX); - //alert(canvasY); - canvas.width = canvasY; - canvas.height = canvasX; - var ctx = canvas.getContext("2d"); - var x = 0; - var y = 0; - - for (x = 0; x < canvasX; x++) { - for (y = 0; y < canvasY; y++) { - //alert(document.querySelector("#i" + x + "x" + y).style.backgroundColor); - //alert("before fill style"); - ctx.fillStyle = document.querySelector( - "#i" + x + "x" + y, - ).style.backgroundColor; - //ctx.fillStyle = "#00ff00"; - //alert("after fill style"); - ctx.fillRect(y, x, 1, 1); - } - } - if (toFile) { - saveAs(canvas.toDataURL("image/png"), " download.png"); - } else { - document.getElementById("p2img").value = canvas.toDataURL("image/png"); - } -} -function p2ToBubble() { - save(); - var bub = new Object(); - bub.img = document.getElementById("p2img").value; - document.getElementById("chat_message").value += JSON.stringify(bub); -} - -document.addEventListener("DOMContentLoaded", function(event) { - setColor(document.getElementById("picker")); - cGen(document.getElementById("canvasY")); -}); diff --git a/src/Splash/res/js/p2chat.js b/src/Splash/res/js/p2chat.js new file mode 100644 index 00000000..37370e31 --- /dev/null +++ b/src/Splash/res/js/p2chat.js @@ -0,0 +1,159 @@ + +// P2Chat code +function splash(that) { + //alert(parent.id); + //alert(parent.getAttribute("data-coord")); + //alert(that.value); + var erase = document.getElementById("erase").checked; + console.log(erase); + if (erase){ + that.style.backgroundColor = document.getElementById("rendertemplate").style.backgroundColor; + } else { + that.style.backgroundColor = document.querySelector("#color").value; + } + save(false, true); +} + +function cGen(that) { + document.getElementById("render").innerHTML = ""; + var parent = that.parentElement; + // alert("parent"); + var canvasX = Number(document.querySelector("#canvasX").value); + // alert("x"); + canvasX = Math.floor(canvasX); + document + .querySelector(":root") + .style.setProperty("--grid-rows", "" + canvasX); + // alert("grid"); + + var canvasY = Number(document.querySelector("#canvasY").value); + //alert(document.querySelector("#canvasY").value); + canvasY = Math.floor(canvasY); + document + .querySelector(":root") + .style.setProperty("--grid-columns", "" + canvasY); + //alert(canvasY); + var nodeRender = ""; + var cloneRender = ""; + var nodeControl = ""; + var cloneControl = ""; + //alert("start loop"); + for (let x = 0; x < canvasX; x++) { + for (let y = 0; y < canvasY; y++) { + //alert(" in"); + nodeRender = document.getElementById("rendertemplate"); + //alert(" past template"); + + cloneRender = nodeRender.cloneNode(true); + cloneRender.style.display = "grid"; + cloneRender.id = "i" + x + "x" + y; + if (y == 0) { + //alert(cloneRender.innerHTML); + } + document.getElementById("render").appendChild(cloneRender); + } + } +} + +function setColor(that) { + var color = that.value; + //alert(typeof color); + if (color.includes("#")) { + document.querySelector("#color").value = color; + } else { + document.querySelector("#color").value = "#" + color; + document.querySelector("#picker").value = "#" + color; + } +} + +function saveAs(uri, filename) { + var link = document.createElement("a"); + if (typeof link.download === "string") { + link.href = uri; + link.download = filename; + + //Firefox requires the link to be in the body + document.body.appendChild(link); + + //simulate click + link.click(); + + //remove the link when done + document.body.removeChild(link); + } else { + window.open(uri); + } +} + +var lastActUndo = false; + +var frameCache = []; + +function undo(){ + if (frameCache.length > 0){ + var curCache = frameCache.pop(); + console.log(lastActUndo); + if (lastActUndo != true){ + curCache = frameCache.pop(); + } + for (x = 0; x < curCache.length; x++) { + var curCacheRow = []; + for (y = 0; y < curCache[x].length; y++) { + document.querySelector( + "#i" + x + "x" + y, + ).style.backgroundColor = curCache[x][y]; + } + } + } + lastActUndo = true; +} + +function save(toFile, toFrameCache) { + var canvas = document.createElement("canvas"); + var canvasX = Number(document.querySelector("#canvasX").value); + var canvasY = Number(document.querySelector("#canvasY").value); + //alert(canvasX); + //alert(canvasY); + canvas.width = canvasY; + canvas.height = canvasX; + var ctx = canvas.getContext("2d"); + var x = 0; + var y = 0; + var curCache = []; + + for (x = 0; x < canvasX; x++) { + var curCacheRow = []; + for (y = 0; y < canvasY; y++) { + var curColor = document.querySelector( + "#i" + x + "x" + y, + ).style.backgroundColor; + ctx.fillStyle = curColor; + //ctx.fillStyle = "#00ff00"; + //alert("after fill style"); + if (toFrameCache){ + curCacheRow.push(curColor); + } else { + ctx.fillRect(y, x, 1, 1); + } + } + curCache.push(curCacheRow); + } + if (toFile) { + saveAs(canvas.toDataURL("image/png"), " download.png"); + } else if (toFrameCache){ + lastActUndo = false; + frameCache.push(curCache); + } else { + document.getElementById("p2img").value = canvas.toDataURL("image/png"); + } +} +function p2ToBubble() { + save(false, false); + var bub = new Object(); + bub.img = document.getElementById("p2img").value; + document.getElementById("chat_message").value += JSON.stringify(bub); +} +document.addEventListener("DOMContentLoaded", function(event) { + setColor(document.getElementById("picker")); + cGen(document.getElementById("canvasY")); +}); diff --git a/src/Splash/res/js/package-lock.json b/src/Splash/res/js/package-lock.json index 0bda9c7f..0e6d1165 100755 --- a/src/Splash/res/js/package-lock.json +++ b/src/Splash/res/js/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "htmx.org": "2.0.0", + "simple-peer": "^9.11.1", "three": "^0.166.1" }, "devDependencies": { @@ -598,6 +599,69 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -650,11 +714,45 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/get-browser-rtc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", + "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==" + }, "node_modules/htmx.org": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.0.tgz", "integrity": "sha512-N0r1VjrqeCpig0mTi2/sooDZBeQlp1RBohnWQ/ufqc7ICaI0yjs04fNGhawm6+/HWhJFlcXn8MqOjWI9QGG2lQ==" }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -707,6 +805,46 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/rollup": { "version": "4.19.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.0.tgz", @@ -742,6 +880,53 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-peer": { + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz", + "integrity": "sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "buffer": "^6.0.3", + "debug": "^4.3.2", + "err-code": "^3.0.1", + "get-browser-rtc": "^1.1.0", + "queue-microtask": "^1.2.3", + "randombytes": "^2.1.0", + "readable-stream": "^3.6.0" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -751,11 +936,24 @@ "node": ">=0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/three": { "version": "0.166.1", "resolved": "https://registry.npmjs.org/three/-/three-0.166.1.tgz", "integrity": "sha512-LtuafkKHHzm61AQA1be2MAYIw1IjmhOUxhBa0prrLpEMWbV7ijvxCRHjSgHPGp2493wLBzwKV46tA9nivLEgKg==" }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/vite": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.4.tgz", diff --git a/src/Splash/res/js/package.json b/src/Splash/res/js/package.json index e852c331..f74fdf9c 100755 --- a/src/Splash/res/js/package.json +++ b/src/Splash/res/js/package.json @@ -10,6 +10,7 @@ "description": "", "dependencies": { "htmx.org": "2.0.0", + "simple-peer": "^9.11.1", "three": "^0.166.1" }, "devDependencies": { diff --git a/src/Splash/templates/index/index.html b/src/Splash/templates/index/index.html index 7144179c..bfb31417 100755 --- a/src/Splash/templates/index/index.html +++ b/src/Splash/templates/index/index.html @@ -22,4 +22,6 @@ {% include "shared/catch.editor.html" %}
{% include "shared/messenger.html" %} +
+{% include "shared/webrtc.html" %} {% endblock %} \ No newline at end of file diff --git a/src/Splash/templates/pix/pix.html b/src/Splash/templates/pix/pix.html new file mode 100755 index 00000000..c9bd5723 --- /dev/null +++ b/src/Splash/templates/pix/pix.html @@ -0,0 +1,11 @@ +{% set standAlone = True %} +{% extends "shared/base.html" %} +{% block body %} +
+
+ {% include "shared/p2chat.html" %} +
+ Built for the PierMesh project + https://piermesh.net +
+{% endblock %} \ No newline at end of file diff --git a/src/Splash/templates/res/p2chat.js b/src/Splash/templates/res/p2chat.js new file mode 100644 index 00000000..37370e31 --- /dev/null +++ b/src/Splash/templates/res/p2chat.js @@ -0,0 +1,159 @@ + +// P2Chat code +function splash(that) { + //alert(parent.id); + //alert(parent.getAttribute("data-coord")); + //alert(that.value); + var erase = document.getElementById("erase").checked; + console.log(erase); + if (erase){ + that.style.backgroundColor = document.getElementById("rendertemplate").style.backgroundColor; + } else { + that.style.backgroundColor = document.querySelector("#color").value; + } + save(false, true); +} + +function cGen(that) { + document.getElementById("render").innerHTML = ""; + var parent = that.parentElement; + // alert("parent"); + var canvasX = Number(document.querySelector("#canvasX").value); + // alert("x"); + canvasX = Math.floor(canvasX); + document + .querySelector(":root") + .style.setProperty("--grid-rows", "" + canvasX); + // alert("grid"); + + var canvasY = Number(document.querySelector("#canvasY").value); + //alert(document.querySelector("#canvasY").value); + canvasY = Math.floor(canvasY); + document + .querySelector(":root") + .style.setProperty("--grid-columns", "" + canvasY); + //alert(canvasY); + var nodeRender = ""; + var cloneRender = ""; + var nodeControl = ""; + var cloneControl = ""; + //alert("start loop"); + for (let x = 0; x < canvasX; x++) { + for (let y = 0; y < canvasY; y++) { + //alert(" in"); + nodeRender = document.getElementById("rendertemplate"); + //alert(" past template"); + + cloneRender = nodeRender.cloneNode(true); + cloneRender.style.display = "grid"; + cloneRender.id = "i" + x + "x" + y; + if (y == 0) { + //alert(cloneRender.innerHTML); + } + document.getElementById("render").appendChild(cloneRender); + } + } +} + +function setColor(that) { + var color = that.value; + //alert(typeof color); + if (color.includes("#")) { + document.querySelector("#color").value = color; + } else { + document.querySelector("#color").value = "#" + color; + document.querySelector("#picker").value = "#" + color; + } +} + +function saveAs(uri, filename) { + var link = document.createElement("a"); + if (typeof link.download === "string") { + link.href = uri; + link.download = filename; + + //Firefox requires the link to be in the body + document.body.appendChild(link); + + //simulate click + link.click(); + + //remove the link when done + document.body.removeChild(link); + } else { + window.open(uri); + } +} + +var lastActUndo = false; + +var frameCache = []; + +function undo(){ + if (frameCache.length > 0){ + var curCache = frameCache.pop(); + console.log(lastActUndo); + if (lastActUndo != true){ + curCache = frameCache.pop(); + } + for (x = 0; x < curCache.length; x++) { + var curCacheRow = []; + for (y = 0; y < curCache[x].length; y++) { + document.querySelector( + "#i" + x + "x" + y, + ).style.backgroundColor = curCache[x][y]; + } + } + } + lastActUndo = true; +} + +function save(toFile, toFrameCache) { + var canvas = document.createElement("canvas"); + var canvasX = Number(document.querySelector("#canvasX").value); + var canvasY = Number(document.querySelector("#canvasY").value); + //alert(canvasX); + //alert(canvasY); + canvas.width = canvasY; + canvas.height = canvasX; + var ctx = canvas.getContext("2d"); + var x = 0; + var y = 0; + var curCache = []; + + for (x = 0; x < canvasX; x++) { + var curCacheRow = []; + for (y = 0; y < canvasY; y++) { + var curColor = document.querySelector( + "#i" + x + "x" + y, + ).style.backgroundColor; + ctx.fillStyle = curColor; + //ctx.fillStyle = "#00ff00"; + //alert("after fill style"); + if (toFrameCache){ + curCacheRow.push(curColor); + } else { + ctx.fillRect(y, x, 1, 1); + } + } + curCache.push(curCacheRow); + } + if (toFile) { + saveAs(canvas.toDataURL("image/png"), " download.png"); + } else if (toFrameCache){ + lastActUndo = false; + frameCache.push(curCache); + } else { + document.getElementById("p2img").value = canvas.toDataURL("image/png"); + } +} +function p2ToBubble() { + save(false, false); + var bub = new Object(); + bub.img = document.getElementById("p2img").value; + document.getElementById("chat_message").value += JSON.stringify(bub); +} +document.addEventListener("DOMContentLoaded", function(event) { + setColor(document.getElementById("picker")); + cGen(document.getElementById("canvasY")); +}); diff --git a/src/Splash/templates/res/style.css b/src/Splash/templates/res/style.css new file mode 100644 index 00000000..2967befc --- /dev/null +++ b/src/Splash/templates/res/style.css @@ -0,0 +1,67 @@ +:root { + --palette-text-white: #FFFFFF; + --palette-text-black: #000000; + --palette-text-three: #3A424D; + --palette-text-four: #5B8080; + + --palette-one: #3A4D24; + --palette-two: #A6B08E; + --palette-three: #879B77; + --palette-four: #61805B; + --grid-columns: 8; + --grid-rows: 8; + --grid-size: 20px; +} + +/** +#controls { + display: grid; + grid-template-columns: repeat(var(--grid-columns), auto); + gap: 5%; +}**/ + +#render { + display: grid; + grid-template-columns: repeat(var(--grid-columns), var(--grid-size)); + grid-template-rows: repeat(var(--grid-rows), var(--grid-size)); + border: 1px solid black; +} + +html { + background-color: var(--palette-one); + color: var(--palette-text-white); + font-family: 'Ubuntu Nerd Font'; + padding: 10px; +} + +.plank { + padding: 10px; + background-color: var(--palette-two); +} + +.plankInner { + display: none; +} + +ul { + padding: 0; + list-style-type: none !important; +} + +li { + padding-top: 5px; + text-decoration: none; + list-style-type: none; +} + +input[type=text], +input[type=number] { + min-width: 150px; + max-width: 150px; +} + +.cnum { + min-width: 20px !important; + max-width: 20px !important; + width: 10px !important; +} \ No newline at end of file diff --git a/src/Splash/templates/shared/base.html b/src/Splash/templates/shared/base.html index e5295abe..8324fe3e 100755 --- a/src/Splash/templates/shared/base.html +++ b/src/Splash/templates/shared/base.html @@ -5,13 +5,27 @@ {{ title }} + {% if standAlone %} + + + {% else %} + + + {% endif %} diff --git a/src/Splash/templates/shared/messenger.html b/src/Splash/templates/shared/messenger.html index 016da4ca..fa1a6849 100755 --- a/src/Splash/templates/shared/messenger.html +++ b/src/Splash/templates/shared/messenger.html @@ -5,6 +5,7 @@ Responses:
+{% set standAlone = false %} {% include "shared/p2chat.html" %} Peer ID:

diff --git a/src/Splash/templates/shared/p2chat.html b/src/Splash/templates/shared/p2chat.html index 9889750e..229c3070 100644 --- a/src/Splash/templates/shared/p2chat.html +++ b/src/Splash/templates/shared/p2chat.html @@ -1,20 +1,30 @@
- Background color: + Background color (pick a color with the color picker and then click the square to set it):
-
- Color picker: - Hex input: + Color picker:
+
+ Hex input: +
+
+ Erase?
+

- X - Y + X:
+ Y:
+
+ {% if standAlone %} + + {% else %} + {% endif %}

diff --git a/src/Splash/templates/shared/webrtc.html b/src/Splash/templates/shared/webrtc.html new file mode 100644 index 00000000..67df92ae --- /dev/null +++ b/src/Splash/templates/shared/webrtc.html @@ -0,0 +1,43 @@ +
+ +
+ + +
+

+  
+
\ No newline at end of file diff --git a/src/TODO.md b/src/TODO.md new file mode 100644 index 00000000..0eb14450 --- /dev/null +++ b/src/TODO.md @@ -0,0 +1,6 @@ +Add a new tab with Catch contents like in Hopper +Import html into catch editor +Import catch as template +Export as one index.html file with inlined assets or zip without inlining +Automatic Replicas of Catchs +DCDN diff --git a/src/stale/WhaleSong.dhefern.py b/src/stale/WhaleSong.dhefern.py deleted file mode 100755 index 2c144284..00000000 --- a/src/stale/WhaleSong.dhefern.py +++ /dev/null @@ -1,296 +0,0 @@ -import base64 -import os -from cryptography.fernet import Fernet -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import dh -from cryptography.hazmat.primitives.kdf.hkdf import HKDF -from cryptography.hazmat.primitives.serialization import ( - Encoding, - NoEncryption, - ParameterFormat, - PublicFormat, - PrivateFormat, -) -import cryptography.hazmat.primitives.serialization as Serialization -import msgpack -from Daisy.Store import Store - -# TODO: Different store directories per node - - -class DHEFern: - """ - - `🔗 Source `__ - - Attributes - ---------- - cLog - Method reference to `run.Node.cLog` so we can log to the ui from here - - loadedParams: dict - In memory representations of cryptography parameters - - loadedKeys: dict - In memory representations of cryptography keys - - nodeNickname: str - Name of node for isolating configs when running multiple nodes - - cache: Components.daisy.Cache - Daisy cache for use in storing cryptography information - - publicKey - Public key for node - - privateKey - Private key for node - """ - - def __init__(self, cache, nodeNickname, cLog): - """ - Parameters - ---------- - cache: Components.daisy.Cache - Reference to the node instances Daisy cache - - nodeNickname: str - Node nickname for record storage - - cLog - Reference to `run.Node.cLog` - - """ - self.cLog = cLog - self.stores = {} - self.loadedParams = {} - self.loadedKeys = {} - self.nodeNickname = nodeNickname - self.cache = cache - if os.path.exists("daisy/cryptography/{0}/param".format(nodeNickname)) == False: - self.initStore("param") - else: - self.stores["param"] = Store("param", "cryptography", nodeNickname) - self.params = self.loadParamBytes(self.stores["param"].get()["self"]) - self.cLog(20, "Param store initialized") - if os.path.exists("daisy/cryptography/{0}/key".format(nodeNickname)) == False: - self.cLog(20, "Key store DNE, initializing") - self.initStore("key") - self.genKeyPair() - else: - self.cLog(20, "Key store exists, loading") - self.stores["key"] = Store("key", "cryptography", nodeNickname) - self.cLog(20, "Store loaded") - # tks = self.stores["key"].get() - # self.publicKey = tks["self"]["publicKey"] - # self.privateKey = tks["self"]["privateKey"] - self.cLog(20, "Key store initialized") - - def checkInMem(self, store: str, nodeID: str): - """ - Check if parameters or keys are loaded for node of nodeID - - Parameters - ---------- - store: str - Whether to check loaded keys or parameters - - """ - if store == "param": - return nodeID in self.loadedParams.keys() - elif store == "key": - return nodeID in self.loadedKeys.keys() - - def loadRecordToMem(self, store: str, nodeID: str): - """ - Load record of nodeID from store to either keys or pameters - """ - r = self.getRecord(store, nodeID) - if r == False: - self.cLog( - 30, "Tried to load nonexistent {0} for node {1}".format(store, nodeID) - ) - return False - elif self.checkInMem(store, nodeID): - self.cLog(10, "{0}s already deserialized, skipping".format(store)) - else: - if store == "param": - self.loadedParams[nodeID] = self.loadParamBytes(r) - elif store == "key": - self.loadedKeys[nodeID] = { - "publicKey": Serialization.load_pem_public_key(r["publicKey"]), - "privateKey": Serialization.load_pem_private_key( - r["privateKey"], None - ), - } - return True - - def getRecord(self, store: str, key: str): - """ - Get record from store: store with key: key - """ - r = stores[store].getRecord(key) - if r == False: - self.cLog(20, "Record does not exist") - return False - else: - return r - - def initStore(self, store: str): - """ - Initialize store: store - """ - self.stores[store] = Store(store, "cryptography", self.nodeNickname) - if store == "param": - self.genParams() - self.stores[store].update("self", self.getParamsBytes(), recur=False) - elif store == "key": - self.stores[store].update("self", {}, recur=False) - else: - self.cLog(30, "Store not defined") - - def genParams(self): - """ - Generate Diffie Hellman parameters - """ - params = dh.generate_parameters(generator=2, key_size=2048) - self.params = params - return params - - def getParamsBytes(self): - """ - Get bytes encoded from self.parameters (TODO: Encode from store) - """ - return self.params.parameter_bytes(Encoding.PEM, ParameterFormat.PKCS3) - - def loadParamBytes(self, pemBytes: bytes): - """ - Load parameters to self.params from given bytes (TODO: Load from store) - """ - self.params = Serialization.load_pem_parameters(pemBytes) - return self.params - - def genKeyPair(self, paramsOverride=False, setSelf: bool = True): - """ - Generate public and private keys from self.params (TODO: Gen from passed params) - - paramsOverride - False or parameters to use (TODO) - - setSelf: bool - Whether to set self.privateKey and self.publicKey - """ - privateKey = self.params.generate_private_key() - if setSelf: - self.privateKey = privateKey - publicKey = privateKey.public_key() - if setSelf: - self.publicKey = publicKey - self.stores["key"].update( - "self", - { - "publicKey": self.publicKey.public_bytes( - Encoding.PEM, PublicFormat.SubjectPublicKeyInfo - ), - "privateKey": self.privateKey.private_bytes( - Encoding.PEM, PrivateFormat.PKCS8, NoEncryption() - ), - }, - ) - return [privateKey, publicKey] - else: - publicKey = publicKey.public_bytes( - Encoding.PEM, PublicFormat.SubjectPublicKeyInfo - ) - privateKey = privateKey.private_bytes( - Encoding.PEM, PrivateFormat.PKCS8, NoEncryption() - ) - return [privateKey, publicKey] - - def keyDerive(self, pubKey: bytes, salt: bytes, nodeID: str, params: bytes): - """ - Derive shared key using Diffie Hellman - - pubKey: bytes - Public key - - nodeID: str - PierMesh node ID - - params: bytes - Encryption parameters - """ - if self.checkInMem("param", nodeID) == False: - if self.getRecord("param", nodeID) == False: - self.updateStore("param", nodeID, params, recur=False) - self.loadRecordToMem("param", nodeID) - self.cLog(20, "Precheck done for key derivation") - - # TODO: Load them and if private key exists load it, otherwise generate a private key - if self.checkInMem("key", nodeID) == False: - if self.getRecord("key", nodeID) == False: - privateKey, publicKey = self.genKeyPair(setSelf=False) - self.updateStore( - "key", nodeID, {"publicKey": publicKey, "privateKey": privateKey} - ) - self.loadRecordToMem("key", nodeID) - - sharedKey = self.loadedKeys[nodeID]["privateKey"].exchange( - Serialization.load_pem_public_key(pubKey) - ) - # Perform key derivation. - self.cLog(20, "Performing key derivation") - derivedKey = HKDF( - algorithm=hashes.SHA256(), length=32, salt=salt, info=b"handshake data" - ).derive(sharedKey) - self.cLog(20, "Derived key") - ederivedKey = base64.urlsafe_b64encode(derivedKey) - tr = self.getRecord("key", nodeID) - tr["derivedKey"] = ederivedKey - self.updateStore("key", nodeID, tr) - self.cLog(20, "Done with cryptography store updates") - return ederivedKey - - def getSalt(self): - """ - Get random salt - """ - return os.urandom(16) - - # TODO: Build in transport security (node/node) - def encrypt(self, data, nodeID: str, isDict: bool = True): - """ - Do Fernet encryption - - data - Either bytes or dict to encrypt - - isDict: bool - Whether data is a dictionary - """ - r = self.getRecord("key", nodeID) - if r == False: - self.cLog(20, "Node {0} not in keystore".format(nodeID)) - return False - else: - derivedKey = r["derivedKey"] - fernet = Fernet(derivedKey) - if isDict: - data = msgpack.dumps(data) - token = fernet.encrypt(data) - return token - - def decrypt(self, data, nodeID: str): - """ - Decrypt bytes and return either str or dict (TODO: Check whether to msgpack load) - """ - r = self.getRecord("key", nodeID) - if r == False: - self.cLog(20, "No record of node " + nodeID) - return False - elif not "derivedKey" in r.keys(): - self.cLog(20, "No key derived for node " + nodeID) - return False - else: - fernet = Fernet(self.getRecord("key", nodeID)["derivedKey"]) - return msgpack.loads(fernet.decrypt(data)) diff --git a/src/stale/daisy.py b/src/stale/daisy.py deleted file mode 100755 index 6ebe209a..00000000 --- a/src/stale/daisy.py +++ /dev/null @@ -1,454 +0,0 @@ -import os -import json -import msgpack -import random -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - -# TODO: delete -# TODO: propagate json changes to msgpack automatically -# TODO: propagate msgpack changes to cache automatically -# TODO: Indexing - - -def _json_to_msg(path: str): - """ - Convert json at the path plus .json to a msgpack binary - - Parameters - ---------- - path: str - Path to json minus the extension - """ - rpath = path + ".json" - res = b"" - with open(rpath) as f: - res = msgpack.dumps(json.load(f)) - with open(path, "wb") as f: - f.write(res) - - -class Daisy: - """ - Base class for Daisy data representation - - `🔗 Source `_ - - Attributes - ---------- - filepath: str - Path to file representation on disk - - msg: dict - In memory representation - """ - - def __init__( - self, - filepath: str, - templates: dict = {}, - template: bool = False, - prefillDict: bool = False, - ): - """ - Parameters - ---------- - filepath: str - Path to disk location - - templates: dict - Dictionary of templates to Use - - template: bool - Which template to Use - - prefillDict: bool - Whether to fill the record with a template - """ - self.filepath = filepath - if os.path.exists(filepath) != True: - with open(filepath, "wb") as f: - if template != False: - if template in templates.keys(): - t = templates[template].get() - if prefillDict != False: - for k in prefillDict.keys(): - t[k] = prefillDict[k] - f.write(msgpack.dumps(t)) - self.msg = t - else: - print("No such template as: " + template) - else: - f.write(msgpack.dumps({})) - self.msg = {} - elif os.path.isdir(filepath): - self.msg = "directory" - else: - with open(filepath, "rb") as f: - self.msg = msgpack.loads(f.read()) - - # Use override for updating - - def write( - self, - override=False, - encrypt: bool = False, - encryptKey=None, - recur: bool = False, - ): - """ - Write record to disk - - Parameters - ---------- - override - Either false or a dictionary of values to set on the record - - encrypt: bool - Whether to encrypt the record (TODO) - - encryptKey - Key to encrypt record with, or None if not set - - recur: bool - Whether to recursively handle keys - """ - if override != False: - for key in override.keys(): - # TODO: Deeper recursion - if recur: - if not key in self.msg.keys(): - self.msg[key] = {} - for ikey in override[key].keys(): - self.msg[key][ikey] = override[key][ikey] - else: - self.msg[key] = override[key] - data = msgpack.dumps(self.msg) - with open(self.filepath, "wb") as f: - f.write(data) - - # Use for refreshing - - def read(self, decrypt: bool = False, decryptKey=False): - """ - Read record from disk to memory - - Parameters - ---------- - decrypt: bool - Whether to decrypt record - - decryptKey - Key to decrypt record - """ - if os.path.isdir(self.filepath): - self.msg = "directory" - else: - with open(self.filepath, "rb") as f: - self.msg = msgpack.loads(f.read()) - - def get(self): - """ - Get record dictionary from memory - - Returns - ------- - self.msg: dict - """ - return self.msg - - def sublist(self): - """ - Lists contents of directory if object is a directory, otherwise return None - """ - fpath = self.filepath - if os.path.isdir(fpath): - return ["messages/" + x for x in os.listdir(fpath)] - else: - return None - - -def loadTemplates(templatePath: str = "templates"): - """Load templates for prefilling records - - Parameters - ---------- - templatePath: str - Path to templates - """ - templates = {} - for p in os.listdir(templatePath): - p = templatePath + "/" + p - if os.path.isdir(p): - for ip in os.listdir(p): - ip = p + "/" + ip - if os.path.isdir(ip): - print("Too deep, skipping: " + ip) - else: - templates[ip] = Daisy(ip) - else: - templates[p] = Daisy(p) - self.templates = templates - return templates - - -class CFSHandler(FileSystemEventHandler): - """ - File system watchdog that propagates disk changes to records to their proper cache - """ - - def __init__(self, cache, isCatch: bool = False): - """ - Parameters - ---------- - cache: Cache - Daisy cache to update - - isCatch: bool - Is the cache for catchs - """ - self.cache = cache - self.isCatch = isCatch - super().__init__() - - def on_any_event(self, event): - """ - Called when a CRUD operation is performed on a record file - - Parameters - ---------- - event - Event object provided by watchdog - """ - if not (".json" in event.src_path): - if not (".md" in event.src_path): - tpath = "/".join(event.src_path.split("/")[1:]) - if tpath != "": - if self.isCatch: - self.cache.sget(tpath) - else: - self.cache.get(tpath).get() - - -# TODO: Dumping to cacheFile - - -class Cache: - """ - In memory collection of Daisy records - """ - - def __init__( - self, - filepaths=None, - cacheFile=None, - path: str = "daisy", - walk: bool = False, - isCatch: bool = False, - ): - """ - Parameters - ---------- - filepaths - Either a list of filepaths to load or None - - cacheFile - Path to a cache file which is a collection of paths to load - - path: str - Path prefix to load records from - - walk: bool - Whether to automatically walk the path and load records - - isCatch: bool - Whether this cache is for catchs - """ - self.data = {} - self.path = path - self.event_handler = CFSHandler(self, isCatch=isCatch) - self.observer = Observer() - self.observer.schedule(self.event_handler, self.path, recursive=True) - self.observer.start() - # TODO: Test - - if filepaths != None: - for fp in filepaths: - fp = path + "/" + fp - if os.path.isfile(fp): - self.data[fp] = Daisy(fp) - elif cacheFile != None: - with open(cacheFile, "r") as f: - for fp in f.read().split("\n"): - self.data[fp] = Daisy(fp) - elif walk: - for root, dirs, files in os.walk(self.path): - for p in dirs + files: - # print("walking") - if not (".json" in p): - if not (".md" in p): - tpath = root + "/" + p - # print(p) - # print(tpath) - self.data[tpath] = Daisy(tpath) - - def create(self, path: str, data: dict): - """ - Create new record - - Parameters - ---------- - path: str - Path to create record at - - data: dict - Data to populate record with - """ - with open(self.path + "/" + path, "wb") as f: - f.write(msgpack.dumps(data)) - logging.log(10, "Done creating record") - self.data[path] = Daisy(self.path + "/" + path) - logging.log(10, "Done loading to Daisy") - return self.data[path] - - def get(self, path: str): - """ - Get record at path, else return False - - path: str - Path of record - """ - if path in self.data.keys(): - return self.data[path] - else: - if os.path.exists(self.path + "/" + path): - self.data[path] = Daisy(self.path + "/" + path) - return self.data[path] - else: - logging.log(10, "File does not exist") - return False - - def refresh(self): - """ - Reload from disk to memory - """ - for key in self.data.keys(): - self.data[key].read() - - def search(self, keydict: dict, strict: bool = True): - """ - Search cache for record for records with values - - keydict: dict - Values to search for - - strict: bool - Whether to require values match - """ - results = [] - for key, val in self.data.items(): - val = val.get() - if strict and type(val) != str: - addcheck = False - for k, v in keydict.items(): - if k in val.keys(): - if v in val[k]: - addcheck = True - else: - addcheck = False - break - if addcheck: - results.append([key, val]) - elif type(val) != str: - for k, v in keydict.items(): - if k in val.keys(): - if v in val[k]: - results.append([key, val]) - return results - - -class Catch(Cache): - """ - Sub class of Cache for handling catchs - - .. image:: https://git.utopic.work/PierMesh/piermesh/raw/branch/main/imgs/catchdisplay.png - """ - - catches = {} - - def __init__( - self, path: str = "catch", filepaths=None, catchFile=None, walk: bool = False - ): - """ - Basically the same initialization parameters as Catch - """ - super().__init__( - filepaths=filepaths, cacheFile=catchFile, path=path, walk=walk, isCatch=True - ) - - # TODO: Fins - - def sget(self, path: str): - """ - Call Cache's get to get record - """ - return super().get(path) - - def get(self, head: str, tail: str, fins=None): - """ - Get catch by pieces - - Parameters - ---------- - head: str - First part of catch (maximum: 4 characters) - - tail: str - Second part of catch (maximum: 16 characters) - - fins - List of (maximum 8 characters) strings at the end of the catch oe None if none - """ - r = self.search({"head": head, "tail": tail}) - return r[0][1]["html"] - - def addc(self, peer, node, seperator, head, tail, data, fins=None): - tnpath = "catch/" + node - if os.path.exists(tnpath) != True: - os.makedirs(tnpath) - tppath = tnpath + "/" + peer - if os.path.exists(tppath) != True: - os.makedirs(tppath) - sid = str(random.randrange(0, 999999)).zfill(6) - data["seperator"] = seperator - data["head"] = head - data["tail"] = tail - if fins != None: - data["fins"] = fins - res = self.create("{0}/{1}/{2}".format(node, peer, sid), data) - return [sid, res] - - -class Store(Daisy): - def __init__(self, store: str, path: str, nodeNickname: str): - fpath = "daisy/{0}/{1}".format(path, nodeNickname)): - cpath = "{0}/{1}/{2}".format(path, nodeNickname, store) - if not os.path.exists(fpath): - os.mkdir(fpath) - super().__init__("daisy/" + cpath) - - def update(self, entry: str, data, recur: bool=True): - if recur: - for key in data.keys(): - self.msg[entry][key] = data[key] - else: - self.msg[entry] = data - self.write() - - def getRecord(self, key: str): - if key in self.get().keys(): - return self.get()[key] - else: - self.cLog(20, "Record does not exist") - return False - diff --git a/src/stale/microplane.py b/src/stale/microplane.py deleted file mode 100755 index 87254853..00000000 --- a/src/stale/microplane.py +++ /dev/null @@ -1,66 +0,0 @@ -import base64, uuid, json, sys, lzma, bson, random, msgpack -from Packets import Packet, HeaderPacket - -def compressPackets(packets): - cpackets = [] - for packet in packets: - cpacket = lzma.compress(packet) - cpackets.append(cpacket) - return cpackets - -def decompressPackets(packets): - cpackets = [] - for packet in packets: - cpacket = lzma.decompress(packet) - cpackets.append(cpacket) - return cpackets - -# TODO: Sub packets -# Sub packets are indicated by a flag in the header -# TODO: Sub packets implementation -# TODO: Sub packet recursion, collapse -# TODO: Determine sub packet per subpackets allowed for header packet size, done, 5, but user ids and subpackets ids must be 6 digit integers -# Remove duplicate references to objects -# Local db that stores users to lookup for less metadata, daisy -# IDS MUST BE 6 DIGITS -# location prefix added by node -# Check if packet is header by checking if it has sender_id - -# DO NOT CHANGE DATA SIZE UNLESS YOU KNOW WHAT YOURE DOING - -# Moved to Packets/Packets - -def reassemblePackets(packets): - #print(packets) - packet_count = msgpack.loads(packets[0])["packet_count"] - #print("Packet count") - #print(packet_count) - positions = [] - for packet in packets: - p = msgpack.loads(packet) - num = 0 - if "packet_number" in p: - num = p["packet_number"] - #print(p) - positions.append(num) - tpackets = [] - for it in range(0, len(positions)): - tpackets.append(packets[positions.index(it)]) - packets = tpackets - res = b"" - #print("Reassembling") - #print(len(packets)) - for it in range(len(packets)): - if it > 0: - #print(it) - #print(res) - #print(bson.loads(packets[it]).keys()) - res = res + lzma.decompress(msgpack.loads(packets[it])["data"]) - #print(len(res)) - #print(bson.loads(res)) - #print(res) - #print(bson.loads(res)) - return msgpack.loads(res) - -def raiseSizeError(index): - raise ValueError("Field of index: " + str(index) + " too big, maximum is 200 bytes") diff --git a/src/stale/router.py b/src/stale/router.py deleted file mode 100644 index 4d20f848..00000000 --- a/src/stale/router.py +++ /dev/null @@ -1,37 +0,0 @@ -import msgpack -from Siph.map import Network -from Components.daisy import Catch -from Components.daisy import Cache -import random - -# TODO: Move intialization to run, this class is unnecessary - - -class Router: - """ - Router - """ - - def __init__(self, cLog, nfpath="server.info"): - self.cLog = cLog - # TODO: Better network init - self.network = Network() - self.catch = Catch(walk=True) - self.cache = Cache(walk=True) - logger.log(10, "Loading server info") - self.serverInfo = self.cache.get(nfpath) - if self.serverInfo == False: - self.cache.create(nfpath, {"nodeID": random.randrange(0, 1000000)}) - self.serverInfo = self.cache.get(nfpath) - self.n.addin(self.serverInfo.get()["nodeID"]) - - def getRoute(self, headerPacket): - headerPacket = msgpack.loads(headerPacket) - peer = headerPacket["recipient"] - node = headerPacket["node"] - - def getCatch(self, head, tail, fins=None): - return self.c.get(head, tail, fins=fins) - - def addc(self, peer, node, seperator, head, tail, data, fins=None): - self.c.addc(peer, node, seperator, head, tail, data, fins=fins) \ No newline at end of file diff --git a/src/stale/sio.py b/src/stale/sio.py deleted file mode 100755 index c2011d35..00000000 --- a/src/stale/sio.py +++ /dev/null @@ -1,30 +0,0 @@ -import socketio -from threading import Thread -import transmission as t -import microplane as m -import bson - -@sio.event -def send(sid, data): - packets = bson.dumps(data) - packets = m.getPackets(packets) - # TODO: Implement awaitFullResponse - threads = [] - threads.append(Thread(target=t.awaitFullResponse, args=[pid]) - for p in packets: - t.send(interface, p) - #awaitResponse(cpid) - pid = t.cpid threads.append(Thread(target=t.awaitResponse, args=[pid]) - threads[-1].start() - time.sleep(1) - done = True - while True: - for th in threads: - if thread.is_alive(): - done = False - if done: - break - sio.emit('done', {'data': t.messages[packets[0]["packets_id"]]["fresponse"]}, room=sid) - -mgr = socketio.RedisManager('redis://') -sio = socketio.Server(client_manager=mgr) diff --git a/src/stale/transmission.old.py b/src/stale/transmission.old.py deleted file mode 100755 index 0692d972..00000000 --- a/src/stale/transmission.old.py +++ /dev/null @@ -1,193 +0,0 @@ -import meshtastic -import meshtastic.serial_interface -from pubsub import pub -import bson -import microplane as m -import sys -import time -import asyncio -import functools -from util import sendData -from threading import Thread -import webview -from Daisy import Catch, Cache -from Filters import Base - -tcache = Cache() -tcatch = Catch() - -html = False -notConnected = True -messages = {} -acks = {} -# Be careful with this -cpid = 0 -# TODO: Filter out non data packets/log them, DONE -# TODO: Figure out why the message count is resetting, DONE, the while loop was...looping -# TODO: Sending packets across multiple nodes/load balancing/distributed packet transmission/reception -def onReceive(packet, interface): - Base.sieve(packet) - tcache.refresh() - -def onConnection(interface, topic=pub.AUTO_TOPIC): # called when we (re)connect to the radio - # defaults to broadcast, specify a destination ID if you wish - interface.sendData("connect".encode("utf-8")) - global notConnected - notConnected = False -def responseCheck(packet): - #print("got response") - #print("Checking") - #print(packet["decoded"]) - rid = packet["decoded"]["requestId"] - print(rid) - # TODO: Set to false on error - print(packet["decoded"]) - if (packet["decoded"]["routing"]["errorReason"] == "MAX_RETRANSMIT"): - print("Got ack error") - acks[str(rid)] = False - else: - acks[str(rid)] = True - -# TODO: Threaded send nethod - -def send(interface, packet): - global cpid - # TODO: Set to confirm receipt, DONE - # TODO: Async sendData call - # TODO: Fix logging error - print("sending") - pid = interface.sendData(packet, wantAck=True, onResponse=responseCheck) - #pid = await sendData(interface, packet, wantAck=True, onResponse=responseCheck) - #pid = await iloop.run_in_executor(None, functools.partial(interface.sendData, interface, packet, wantAck=True, onResponse=responseCheck)) - # Can I use waitForAckNak on cpid? - cpid = pid.id - print(cpid) - #return pid - return True - -def awaitResponse(pid): - #pid = interface.sendData(p, wantAck=True, onResponse=responseCheck)["id"] - #pid = await loop.run_in_executor(None, send, interface, p) - #pid = await loop.run_in_executor(None, functools.partial(interface.sendData, wantAck=True, onResponse=responseCheck), interface, p) - print(pid) - for i in range(1_000_000_000): - time.sleep(5) - if str(pid) in acks: - print("Response gotten") - break - print("waiting") - return True - -def awaitFullResponse(pid): - for i in range(1_000_000_000): - time.sleep(5) - if pid in messages.keys(): - if messages[pid]["finished"]: - print("Response gotten") - break - print("waiting") - return True - -pub.subscribe(onReceive, "meshtastic.receive") -pub.subscribe(onConnection, "meshtastic.connection.established") -# By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0 -interface = meshtastic.serial_interface.SerialInterface(sys.argv[-1]) -# Wait to connect to partner -# TODO: use node id to delivery directly -while notConnected: - time.sleep(5) - print("Waiting") -if "0" in sys.argv[-1]: - tj = [[{"message":"free palestine! free all colonized people!"}], ["the people yearn for freedom"]] - j2 = {"message":"free palestine! free all colonized people!", "message2":"free palestine! free all colonized people!"} - htmlj = {"html": "

Hello world!

"} - htmljl = {"html": ""} - with open("test.html", "r") as f: - htmljl["html"] = f.read() - done = False - threads = {} - for p in m.getPackets(bson.dumps(htmljl), 600123, 600123, 600124): - print(sys.getsizeof(p)) - #send_thread = Thread(target=send, args=[interface, p]) - #send_thread.start() - send(interface, p) - #awaitResponse(cpid) - await_thread = Thread(target=awaitResponse, args=[cpid]) - await_thread.start() - cth = { - "ob": await_thread, - "pid": str(cpid), - "packet": p, - "retry": False - } - threads[str(cpid)] = cth - # TODO: see if theres a better way to do this - time.sleep(10) - #await_thread.join() - #await_thread.join() - #loop = asyncio.new_event_loop() - #loopi = asyncio.new_event_loop() - #loopi.run_until_complete(send(interface, p)) - #res = loop.run_until_complete(awaitResponse(cpid)) - # figure out why it doesnt send before timing out - # TODO: running in different threads - #pid = send(interface, p).id - #loop = asyncio.new_event_loop() - #loopi = asyncio.new_event_loop() - #loopi.run_until_complete(send(loopi, interface, p)) - #interface.waitForAckNak() - #res = loop.run_until_complete(awaitResponse(interface, p, cpid)) - #print("Done waiting") - #interface.waitForAckNak() - # DO NOT RUN UNTIL responseCheck CHECKS FOR ERRORS - isDone = False - while not isDone: - doneFlag = True - for th in threads.keys(): - th = threads[th] - if not th["ob"].is_alive: - if not acks[th["pid"]]: - retry = th["retry"] - if retry == False: - retry = 1 - elif retry < 3: - retry += 1 - else: - print("Too many retries") - break - doneFlag = False - send(interface, th["packet"]) - await_thread = Thread(target=awaitResponse, args=[cpid]) - await_thread.start() - cth = { - "ob": await_thread, - "pid": str(cpid), - "packet": p - } - cth["retry"] = retry - threads[str(cpid)] = cth - # TODO: see if theres a better way to do this - time.sleep(5) - if doneFlag: - isDone = True - - - - - for it, p in enumerate(m.getPacketsFromFile("r.jpg", 600123, 600123, 600124)): - #send(interface, p) - #pid = send(interface, p).id - #loopi = asyncio.new_event_loop() - #loopi.run_until_complete(send(loopi, interface, p)) - #interface.waitForAckNak() - #res = loop.run_until_complete(awaitResponse(interface, p, cpid)) - #interface.waitForAckNak() - #print("Sending packet: " + str(it)) - break -else: - while True: - if html != False: - break - pass - webview.create_window('Home', html=html) - webview.start()