Merge branch 'computernewb:master' into patch-1
This commit is contained in:
commit
6b563d6d4b
5 changed files with 208 additions and 44 deletions
7
dist/index.html
vendored
7
dist/index.html
vendored
|
@ -55,6 +55,13 @@
|
|||
<button class="btn btn-secondary" id="changeUsernameBtn">Change Username</button>
|
||||
<button class="btn btn-secondary" id="voteResetButton">Vote for Reset</button>
|
||||
<button class="btn btn-secondary" id="screenshotButton">Screenshot</button>
|
||||
<div id="staffbtns">
|
||||
<button class="btn btn-secondary" id="restoreBtn">Restore</button>
|
||||
<button class="btn btn-secondary" id="rebootBtn">Reboot</button>
|
||||
<button class="btn btn-secondary" id="clearQueueBtn">Clear Turn Queue</button>
|
||||
<button class="btn btn-secondary" id="bypassTurnBtn">Bypass Turn</button>
|
||||
<button class="btn btn-secondary" id="endTurnBtn">End Turn</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
|
|
26
dist/style.css
vendored
26
dist/style.css
vendored
|
@ -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,29 @@
|
|||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#turnstatus {
|
||||
text-align: center;
|
||||
}
|
||||
#voteResetPanel {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.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)
|
||||
}
|
||||
|
||||
#staffbtns {
|
||||
display: none;
|
||||
}
|
||||
#staffbtns > button {
|
||||
display: none;
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
|
189
src/index.js
189
src/index.js
|
@ -1,11 +1,14 @@
|
|||
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 = <queue position>
|
||||
var turn = -1;
|
||||
var perms = 0;
|
||||
var perms = makeperms(0);
|
||||
var rank = 0;
|
||||
var connected = false;
|
||||
const vms = [];
|
||||
const users = [];
|
||||
|
@ -13,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;
|
||||
|
@ -37,11 +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;
|
||||
|
@ -63,26 +75,23 @@ 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"]));
|
||||
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":
|
||||
var unbind = this.eventemitter.on('connect', () => {
|
||||
unbind();
|
||||
res();
|
||||
break;
|
||||
}
|
||||
this.socket.removeEventListener("message", f);
|
||||
}
|
||||
}
|
||||
this.socket.addEventListener("message", f);
|
||||
});
|
||||
var failunbind = this.eventemitter.on('connectfail', () => {
|
||||
failunbind();
|
||||
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) {
|
||||
|
@ -91,6 +100,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 +118,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];
|
||||
|
@ -171,6 +203,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,6 +215,7 @@ class CollabVMClient {
|
|||
if (currentTurnUsername === window.username) {
|
||||
turn = 0;
|
||||
turnstatus.innerText = "You have the turn.";
|
||||
display.className = "focused";
|
||||
}
|
||||
// Highlight all waiting users and set their status
|
||||
if (queuedUsers > 1) {
|
||||
|
@ -189,6 +223,7 @@ class CollabVMClient {
|
|||
if (window.username === msgArr[i+3]) {
|
||||
turn = i;
|
||||
turnstatus.innerText = "Waiting for turn";
|
||||
display.className = "waiting";
|
||||
};
|
||||
var user = users.find(u => u.username === msgArr[i+3]);
|
||||
user.turn = i;
|
||||
|
@ -234,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() {
|
||||
|
@ -252,24 +331,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;");
|
||||
});
|
||||
}
|
||||
|
@ -309,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) => {
|
||||
|
@ -364,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) => {
|
||||
|
@ -406,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;
|
||||
window.getPerms = () => perms;
|
||||
window.getRank = () => rank;
|
||||
window.GetAdmin = () => vm.admin;
|
||||
window.cvmEvents = createNanoEvents();
|
23
src/permissions.js
Normal file
23
src/permissions.js
Normal file
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue