From a9cf21e06670ab82d017feb91243992eb324b06b Mon Sep 17 00:00:00 2001 From: Brandan <32969563+dfault-user@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:19:21 -0500 Subject: [PATCH 1/6] Attempt 1 at indicating if user has turn or waiting for turn more vibrantly --- dist/style.css | 21 +++++++++++++++++++-- src/index.js | 4 +++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/dist/style.css b/dist/style.css index 24c43e4..e5a85ef 100644 --- a/dist/style.css +++ b/dist/style.css @@ -19,6 +19,7 @@ display: block; margin-bottom: 10px; } + #vmlist > div.row > div { padding-bottom: 10px; } @@ -26,9 +27,11 @@ cursor: pointer; border-color: rgb(8, 121, 250); } + .vmtile > img { margin-bottom: 2px; -}*/ +} + .chat-table, .username-table { overflow-y: auto; border: 1px solid #575757; @@ -36,6 +39,7 @@ .chat-table { height: 30vh; } + .username-table { max-height: 30vh; } @@ -43,9 +47,22 @@ position: sticky; top: 0; } + #turnstatus { text-align: center; } #voteResetPanel { text-align: center; -} \ No newline at end of file +} + +.focused { + box-shadow: 0 0 9px 0 rgba(45,213,255,.75); + -moz-box-shadow: 0 0 9px 0 rgba(45,213,255,.75); + -webkit-box-shadow: 0 0 9px 0 rgba(45,213,255,.75) +} + +.waiting { + box-shadow: 0 0 9px 0 rgba(242,255,63,.75); + -moz-box-shadow: 0 0 9px 0 rgba(242,255,63,.75); + -webkit-box-shadow: 0 0 9px 0 rgba(242,255,63,.75) +} diff --git a/src/index.js b/src/index.js index b715436..3b80d69 100644 --- a/src/index.js +++ b/src/index.js @@ -182,13 +182,15 @@ class CollabVMClient { if (currentTurnUsername === window.username) { turn = 0; turnstatus.innerText = "You have the turn."; - } + vmview.class = "focused"; + } // Highlight all waiting users and set their status if (queuedUsers > 1) { for (var i = 1; i < queuedUsers; i++) { if (window.username === msgArr[i+3]) { turn = i; turnstatus.innerText = "Waiting for turn"; + vmview.class="waiting"; }; var user = users.find(u => u.username === msgArr[i+3]); user.turn = i; From a0f320868677bfb81cc604a18369f68dc5ea1949 Mon Sep 17 00:00:00 2001 From: Brandan <32969563+dfault-user@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:21:36 -0500 Subject: [PATCH 2/6] wrong thing, whoops Fuark --- src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 3b80d69..083afb6 100644 --- a/src/index.js +++ b/src/index.js @@ -182,7 +182,7 @@ class CollabVMClient { if (currentTurnUsername === window.username) { turn = 0; turnstatus.innerText = "You have the turn."; - vmview.class = "focused"; + display.class = "focused"; } // Highlight all waiting users and set their status if (queuedUsers > 1) { @@ -190,7 +190,7 @@ class CollabVMClient { if (window.username === msgArr[i+3]) { turn = i; turnstatus.innerText = "Waiting for turn"; - vmview.class="waiting"; + display.class="waiting"; }; var user = users.find(u => u.username === msgArr[i+3]); user.turn = i; From 54153e723d88d743c70fbdb55a5aba9600374bbe Mon Sep 17 00:00:00 2001 From: elijahr2411 Date: Thu, 26 Jan 2023 16:27:19 -0500 Subject: [PATCH 3/6] switch to using nanoevents from the weird onmessage shit I had --- package.json | 1 + src/index.js | 70 +++++++++++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 26545db..d69059a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "author": "Elijah R", "license": "GPL-3.0", "dependencies": { + "nanoevents": "^7.0.1", "webpack": "^5.75.0", "webpack-cli": "^5.0.1" } diff --git a/src/index.js b/src/index.js index 84a5fa9..a3c7190 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import { guacutils } from "./protocol"; import { config } from "./common"; import { GetKeysym } from "./keyboard"; +import { createNanoEvents } from "nanoevents"; // None = -1 // Has turn = 0 // In queue = @@ -41,6 +42,7 @@ const votetime = document.getElementById("votetime"); const chatListDiv = document.querySelector(".chat-table"); class CollabVMClient { + eventemitter = createNanoEvents(); socket; #url; constructor(url) { @@ -67,21 +69,14 @@ class CollabVMClient { if (savedUsername === null) this.socket.send(guacutils.encode(["rename"])); else this.socket.send(guacutils.encode(["rename", savedUsername])); - var f = (e) => { - var msgArr = guacutils.decode(e.data); - if (msgArr[0] == "connect") { - switch (msgArr[1]) { - case "0": - rej("Failed to connect to the node"); - break; - case "1": - res(); - break; - } - this.socket.removeEventListener("message", f); - } - } - this.socket.addEventListener("message", f); + var unbind = this.eventemitter.on('connect', () => { + unbind(); + res(); + }); + var failunbind = this.eventemitter.on('connectfail', () => { + failunbind(); + rej(); + }); this.socket.send(guacutils.encode(["connect", node])); }); } @@ -91,6 +86,16 @@ class CollabVMClient { case "nop": this.socket.send("3.nop;"); break; + case "connect": + switch (msgArr[1]) { + case "0": + this.eventemitter.emit('connectfail'); + break; + case "1": + this.eventemitter.emit('connect'); + break; + } + break; case "chat": if (!connected) return; for (var i = 1; i < msgArr.length; i += 2) { @@ -99,6 +104,19 @@ class CollabVMClient { chatsound.play(); chatListDiv.scrollTop = chatListDiv.scrollHeight; break; + case "list": + var list = []; + for (var i = 1; i < msgArr.length; i+=3) { + list.push({ + url: this.#url, + id: msgArr[i], + name: msgArr[i+1], + thumb: msgArr[i+2], + + }); + } + this.eventemitter.emit('list', list); + break; case "size": if (!connected || msgArr[1] !== "0") return; display.width = msgArr[2]; @@ -252,24 +270,10 @@ class CollabVMClient { } async list() { return new Promise((res, rej) => { - var h = (e) => { - var msgArr = guacutils.decode(e.data); - if (msgArr[0] === "list") { - var list = []; - for (var i = 1; i < msgArr.length; i+=3) { - list.push({ - url: this.#url, - id: msgArr[i], - name: msgArr[i+1], - thumb: msgArr[i+2], - - }); - } - this.socket.removeEventListener("message", h); - res(list); - } - }; - this.socket.addEventListener("message", h); + var unbind = this.eventemitter.on('list', (e) => { + unbind(); + res(e); + }) this.socket.send("4.list;"); }); } From 27a878b6199593ad13197e142f359c93520b4796 Mon Sep 17 00:00:00 2001 From: Brandan <32969563+dfault-user@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:27:38 -0500 Subject: [PATCH 4/6] make it actually work this time todo: 'you have a turn' text doesn't move chat --- src/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 083afb6..1c22d81 100644 --- a/src/index.js +++ b/src/index.js @@ -171,6 +171,7 @@ class CollabVMClient { buttons.takeTurn.innerText = "Take Turn"; turn = -1; turnstatus.innerText = ""; + display.className = ""; // Get the number of users queued for a turn var queuedUsers = Number(msgArr[2]); if (queuedUsers === 0) return; @@ -182,7 +183,7 @@ class CollabVMClient { if (currentTurnUsername === window.username) { turn = 0; turnstatus.innerText = "You have the turn."; - display.class = "focused"; + display.className = "focused"; } // Highlight all waiting users and set their status if (queuedUsers > 1) { @@ -190,7 +191,7 @@ class CollabVMClient { if (window.username === msgArr[i+3]) { turn = i; turnstatus.innerText = "Waiting for turn"; - display.class="waiting"; + display.className="waiting"; }; var user = users.find(u => u.username === msgArr[i+3]); user.turn = i; From d406522cce1d55c4e093c606f3f5e9151d8b11ae Mon Sep 17 00:00:00 2001 From: Brandan <32969563+dfault-user@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:30:25 -0500 Subject: [PATCH 5/6] peter the coding style is consistent --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 301b377..2601d0f 100644 --- a/src/index.js +++ b/src/index.js @@ -191,7 +191,7 @@ class CollabVMClient { if (window.username === msgArr[i+3]) { turn = i; turnstatus.innerText = "Waiting for turn"; - display.className="waiting"; + display.className = "waiting"; }; var user = users.find(u => u.username === msgArr[i+3]); user.turn = i; From 4aeb9437df4295df4ea6ca01de14a0f4c78148a0 Mon Sep 17 00:00:00 2001 From: elijahr2411 Date: Thu, 26 Jan 2023 19:45:29 -0500 Subject: [PATCH 6/6] - Add staff shit (no qemu monitor or user-specific actions just yet) - Switch events to capture --- dist/index.html | 7 +++ dist/style.css | 7 +++ src/index.js | 122 +++++++++++++++++++++++++++++++++++++++++---- src/permissions.js | 23 +++++++++ 4 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 src/permissions.js diff --git a/dist/index.html b/dist/index.html index 48922ba..3bb3f63 100644 --- a/dist/index.html +++ b/dist/index.html @@ -45,6 +45,13 @@ +
+ + + + + +
diff --git a/dist/style.css b/dist/style.css index e5a85ef..7bf4bd2 100644 --- a/dist/style.css +++ b/dist/style.css @@ -66,3 +66,10 @@ -moz-box-shadow: 0 0 9px 0 rgba(242,255,63,.75); -webkit-box-shadow: 0 0 9px 0 rgba(242,255,63,.75) } + +#staffbtns { + display: none; +} +#staffbtns > button { + display: none; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index dd9b822..4aa53af 100644 --- a/src/index.js +++ b/src/index.js @@ -2,11 +2,13 @@ import { guacutils } from "./protocol"; import { config } from "./common"; import { GetKeysym } from "./keyboard"; import { createNanoEvents } from "nanoevents"; +import { makeperms } from "./permissions"; // None = -1 // Has turn = 0 // In queue = var turn = -1; -var perms = 0; +var perms = makeperms(0); +var rank = 0; var connected = false; const vms = []; const users = []; @@ -14,7 +16,13 @@ const buttons = { takeTurn: window.document.getElementById("takeTurnBtn"), changeUsername: window.document.getElementById("changeUsernameBtn"), voteReset: window.document.getElementById("voteResetButton"), - screenshot: window.document.getElementById("screenshotButton") + screenshot: window.document.getElementById("screenshotButton"), + // Staff + restore: window.document.getElementById("restoreBtn"), + reboot: window.document.getElementById("rebootBtn"), + clearQueue: window.document.getElementById("clearQueueBtn"), + bypassTurn: window.document.getElementById("bypassTurnBtn"), + endTurn: window.document.getElementById("endTurnBtn"), } var hasTurn = false; var vm; @@ -38,12 +46,14 @@ const votenobtn = document.getElementById("voteNoBtn"); const voteyeslabel = document.getElementById("voteYesLabel"); const votenolabel = document.getElementById("voteNoLabel"); const votetime = document.getElementById("votetime"); +const staffbtns = document.getElementById("staffbtns"); // needed to scroll to bottom const chatListDiv = document.querySelector(".chat-table"); class CollabVMClient { eventemitter = createNanoEvents(); socket; + node; #url; constructor(url) { this.#url = url; @@ -65,6 +75,7 @@ class CollabVMClient { } connectToVM(node) { return new Promise((res, rej) => { + this.node = node; var savedUsername = window.localStorage.getItem("username"); if (savedUsername === null) this.socket.send(guacutils.encode(["rename"])); @@ -78,6 +89,9 @@ class CollabVMClient { rej(); }); this.socket.send(guacutils.encode(["connect", node])); + var pass = window.localStorage.getItem("password_"+this.#url); + if (pass) + this.admin.login(pass); }); } async #onMessage(event) { @@ -202,7 +216,7 @@ class CollabVMClient { turn = 0; turnstatus.innerText = "You have the turn."; display.className = "focused"; - } + } // Highlight all waiting users and set their status if (queuedUsers > 1) { for (var i = 1; i < queuedUsers; i++) { @@ -255,6 +269,50 @@ class CollabVMClient { break; } break; + case "admin": + switch (msgArr[1]) { + case "0": + // Login + switch (msgArr[2]) { + case "0": + this.eventemitter.emit('login', {error: 'badpassword'}); + return; + break; + case "1": + perms = makeperms(65535); + rank = 2; + break; + case "3": + rank = 3; + perms = makeperms(parseInt(msgArr[3])) + } + this.eventemitter.emit('login', {perms: perms, rank: rank}); + usernameSpan.classList.remove("text-light"); + switch (rank) { + case 2: + usernameSpan.classList.add("text-danger"); + break; + case 3: + usernameSpan.classList.add("text-success"); + break; + } + // Disabled for now until we figure out the issue of uservm + //window.localStorage.setItem("password_"+this.#url, password); + staffbtns.style.display = "block"; + if (perms.restore) buttons.restore.style.display = "inline-block"; + if (perms.reboot) buttons.reboot.style.display = "inline-block"; + if (perms.bypassturn) { + buttons.bypassTurn.style.display = "inline-block"; + buttons.clearQueue.style.display = "inline-block"; + buttons.endTurn.style.display = "inline-block"; + } + break; + + } + break; + default: + window.cvmEvents.emit(msgArr[0], msgArr.slice(1)); + break; } } reloadUsers() { @@ -316,6 +374,28 @@ class CollabVMClient { voteReset(reset) { this.socket.send(guacutils.encode(["vote", reset ? "1" : "0"])); } + admin = { + login: (password) => { + return new Promise((res, rej) => { + var unbind = this.eventemitter.on('login', (args) => { + unbind(); + if (args.error) rej(error); + res(args); + }) + this.socket.send(guacutils.encode(["admin", "2", password])); + }); + }, + adminInstruction: (...args) => { // Compatibility + args.unshift("admin"); + console.log(args); + this.socket.send(guacutils.encode(args)); + }, + restore: () => this.socket.send(guacutils.encode(["admin", "8", this.node])), + reboot: () => this.socket.send(guacutils.encode(["admin", "10", this.node])), + clearQueue: () => this.socket.send(guacutils.encode(["admin", "17", this.node])), + bypassTurn: () => this.socket.send(guacutils.encode(["admin", "20"])), + endTurn: () => this.socket.send(guacutils.encode(["admin", "16", users[0].username])), + } } function multicollab(url) { return new Promise(async (res, rej) => { @@ -371,15 +451,15 @@ async function openVM(url, node) { await vm.connectToVM(node); vmlist.style.display = "none"; vmview.style.display = "block"; - display.addEventListener('mousemove', (e) => vm.mouseevent(e)) - display.addEventListener('mousedown', (e) => vm.mouseevent(e)); - display.addEventListener('mouseup', (e) => vm.mouseevent(e)); + display.addEventListener('mousemove', (e) => vm.mouseevent(e), {capture: true}) + display.addEventListener('mousedown', (e) => vm.mouseevent(e), {capture: true}); + display.addEventListener('mouseup', (e) => vm.mouseevent(e), {capture: true}); display.addEventListener('contextmenu', (e) => e.preventDefault()); display.addEventListener('click', () => { if (turn === -1) vm.turn(); - }); - display.addEventListener('keydown', (e) => vm.keyevent(e, true)); - display.addEventListener('keyup', (e) => vm.keyevent(e, false)); + }, {capture: true}); + display.addEventListener('keydown', (e) => vm.keyevent(e, true), {capture: true}); + display.addEventListener('keyup', (e) => vm.keyevent(e, false), {capture: true}); } function screenshotVM() { return new Promise((res, rej) => { @@ -413,9 +493,31 @@ buttons.takeTurn.addEventListener('click', () => vm.turn()); buttons.voteReset.addEventListener('click', () => vm.voteReset(true)); voteyesbtn.addEventListener('click', () => vm.voteReset(true)); votenobtn.addEventListener('click', () => vm.voteReset(false)); +// Staff buttons +buttons.restore.addEventListener('click', () => vm.admin.restore()); +buttons.reboot.addEventListener('click', () => vm.admin.reboot()); +buttons.clearQueue.addEventListener('click', () => vm.admin.clearQueue()); +buttons.bypassTurn.addEventListener('click', () => vm.admin.bypassTurn()); +buttons.endTurn.addEventListener('click', () => vm.admin.endTurn()); +// Login +var usernameClick = false; +usernameSpan.addEventListener('click', () => { + if (!usernameClick) { + usernameClick = true; + setInterval(() => {usernameClick = false;}, 1000); + return; + } + var pass = window.prompt("🔑"); + if (!pass) return; + vm.admin.login(pass); +}); // Load all vms config.serverAddresses.forEach(multicollab); // Export some stuff window.screenshotVM = screenshotVM; -window.multicollab = multicollab; \ No newline at end of file +window.multicollab = multicollab; +window.getPerms = () => perms; +window.getRank = () => rank; +window.GetAdmin = () => vm.admin; +window.cvmEvents = createNanoEvents(); \ No newline at end of file diff --git a/src/permissions.js b/src/permissions.js new file mode 100644 index 0000000..87dca86 --- /dev/null +++ b/src/permissions.js @@ -0,0 +1,23 @@ +export function makeperms(mask) { + const perms = { + restore: false, + reboot: false, + ban: false, + forcevote: false, + mute: false, + kick: false, + bypassturn: false, + rename: false, + grabip: false + }; + if ((mask & 1) !== 0) perms.restore = true; + if ((mask & 2) !== 0) perms.reboot = true; + if ((mask & 4) !== 0) perms.ban = true; + if ((mask & 8) !== 0) perms.forcevote = true; + if ((mask & 16) !== 0) perms.mute = true; + if ((mask & 32) !== 0) perms.kick = true; + if ((mask & 64) !== 0) perms.bypassturn = true; + if ((mask & 128) !== 0) perms.rename = true; + if ((mask & 256) !== 0) perms.grabip = true; + return perms; +} \ No newline at end of file