fixed scrolling and buffer times- oh yeah also huge backend overhual

This commit is contained in:
ari melody 2023-09-30 15:52:54 +01:00
parent 1eeb632ff2
commit 524969370d
Signed by: ari
GPG key ID: CF99829C92678188
3 changed files with 250 additions and 99 deletions

View file

@ -1,11 +1,22 @@
var buffer = ""; var recv_buffer = [];
var send_buffer = ""; var send_buffer = [];
var content; var content;
var mobile_input; var mobile_input;
var client; var client;
var my_colour = false;
var pre_buffer_chars = 0; var pre_buffer_chars = 0;
var term_interval = 10;
var ready = false; const DATA_TYPES = {
text: 0,
colour: 1,
buffer: 2,
backspace: 3,
backword: 4,
arrow: 5,
};
function start() { function start() {
console.log("%chello, world!", "color: #b7fd49; font-size: 3rem; font-weight: bold"); console.log("%chello, world!", "color: #b7fd49; font-size: 3rem; font-weight: bold");
@ -34,74 +45,115 @@ to help you feel a little more comfortable, i've prepared some commands for you:
content = document.getElementById("content"); content = document.getElementById("content");
mobile_input = document.getElementById("mobile-input"); mobile_input = document.getElementById("mobile-input");
content.addEventListener("click", () => { content.addEventListener("touchend", () => {
mobile_input.focus(); mobile_input.focus();
}); });
buffer += "Connecting to the server..."; add_system_message("Connecting to the server...");
setTimeout(connect, 500); setTimeout(connect, 500);
setInterval(() => {
if (send_buffer.length > 0) {
const data = JSON.stringify(send_buffer[0]);
client.send(data);
send_buffer = send_buffer.slice(1);
}
}, 1000 / 600);
loop(); loop();
} }
function loop() { function loop() {
if (buffer.length > 0) {
const char = buffer.substring(0, 1);
insert_text(char);
buffer = buffer.substring(1);
}
if (send_buffer.length > 0) {
const char = send_buffer.substring(0, 1);
client.send(char);
send_buffer = send_buffer.substring(1);
}
mobile_input.value = content.innerText; mobile_input.value = content.innerText;
setTimeout(loop, term_interval); setTimeout(loop, 1000 / 60);
} }
function connect() { function connect() {
client = new WebSocket("wss://" + window.location.host); client = new WebSocket("wss://" + window.location.host);
client.addEventListener('open', () => { client.addEventListener('open', () => {
// insert_text('\x00'); add_system_message(`\nConnection successful.\n\n`);
buffer += "\nConnection successful.\n\n"; add_system_message(`=== BEGIN SESSION ===\n\n`);
buffer += "=== BEGIN SESSION ===\n\n"; new_caret();
}); });
client.addEventListener('message', event => { client.addEventListener('message', event => { handle_message(JSON.parse(event.data)) });
buffer += event.data;
if (pre_buffer_chars == 0) {
pre_buffer_chars = content.innerText.length + buffer.length;
}
});
client.addEventListener('close', () => { client.addEventListener('close', () => {
insert_text("\n\n[CONNECTION LOST, PLEASE REFRESH]"); add_system_message(`\n[CONNECTION LOST, PLEASE REFRESH]\n`);
}); });
} }
function insert_text(text) { function add_system_message(text) {
const carat = content.querySelector("#carat"); const span = document.createElement("span");
if (carat) carat.remove(); span.classList.add('sticky');
span.innerText = text;
content.appendChild(span);
if (text == "\x00") { new_caret();
content.innerText = ""; }
pre_buffer_chars = 0;
} else if (text == "\b") { function handle_message(data) {
if (content.innerText.length > pre_buffer_chars) { if (!data.type && data.type != 0) return;
const is_at_bottom = content.scrollTop == content.scrollTopMax;
switch (data.type) {
case DATA_TYPES.colour:
my_colour = data.colour;
console.log(`%cColour has been changed to ${my_colour}`, `color: ${my_colour}`);
break;
case DATA_TYPES.backspace:
content.querySelectorAll("#caret").forEach(caret => caret.remove());
/*
const last_child = content.lastChild;
if (last_child.classList.contains('sticky')) break;
last_child.remove();
*/
if (content.innerText.length <= pre_buffer_chars) {
break;
}
content.innerText = content.innerText.slice(0, content.innerText.length - 1); content.innerText = content.innerText.slice(0, content.innerText.length - 1);
} break;
} else { case DATA_TYPES.text:
content.innerText += text; /*
} const span = document.createElement("span");
if (data.colour) span.style.color = data.colour;
if (data.sticky) span.classList.add('sticky');
span.innerText = data.text;
content.appendChild(span);
*/
content.innerText += data.text;
break;
case DATA_TYPES.buffer:
content.innerText += data.data;
break;
/*
data.data.forEach(block => {
handle_message(block);
});
*/
}
const new_carat = document.createElement("div"); if (pre_buffer_chars == 0) {
new_carat.id = "carat"; pre_buffer_chars = content.innerText.length;
content.appendChild(new_carat); }
new_caret();
if (is_at_bottom) content.scrollTop = content.scrollTopMax;
}
function new_caret() {
content.querySelectorAll("#caret").forEach(caret => caret.remove());
const new_caret = document.createElement("div");
new_caret.id = "caret";
if (my_colour) {
new_caret.style.backgroundColor = my_colour;
}
content.appendChild(new_caret);
} }
function handle_input(event) { function handle_input(event) {
@ -109,38 +161,77 @@ function handle_input(event) {
event.preventDefault(); event.preventDefault();
} }
if (event.key == "Backspace") { switch (event.key) {
if (event.ctrlKey && send_buffer.length == 0) { case "Backspace":
const last_space = content.innerText.lastIndexOf(" "); if (event.ctrlKey) {
const last_newline = content.innerText.lastIndexOf("\n"); if (send_buffer.length > 0) return;
/*
var break_at = last_space; send_buffer.push({
if (last_newline > last_space) { type: DATA_TYPES.backword,
break_at = last_newline; });
} */
var break_point = content.innerText.lastIndexOf(" ");
const word_length = content.innerText.length - break_at; const last_newline = content.innerText.lastIndexOf("\n");
for (let i = 0; i < word_length; i++) { if (last_newline > break_point) break_point = last_newline;
send_buffer += '\b'; const count = content.innerText.length - break_point;
for (var i = 0; i < count; i++) {
send_buffer.push({
type: DATA_TYPES.backspace,
});
}
return;
} }
send_buffer.push({
type: DATA_TYPES.backspace,
});
return;
case "Enter":
send_buffer.push({
type: DATA_TYPES.text,
text: "\n",
});
return;
case "ArrowUp":
send_buffer.push({
type: DATA_TYPES.arrow,
dir: "up",
});
return;
case "ArrowDown":
send_buffer.push({
type: DATA_TYPES.arrow,
dir: "down",
});
return;
case "ArrowLeft":
send_buffer.push({
type: DATA_TYPES.arrow,
dir: "left",
});
return;
case "ArrowRight":
send_buffer.push({
type: DATA_TYPES.arrow,
dir: "right",
});
return; return;
}
send_buffer += '\b';
return;
}
if (event.key == "Enter") {
send_buffer += '\n';
return;
} }
if (event.key.length > 1) { if (event.key.length > 1) {
// server will discard text over 1 character, anyway
return; return;
} }
if (event.ctrlKey) { if (event.ctrlKey) {
return; return;
} }
send_buffer += event.key; send_buffer.push({
content.scrollTop = content.scrollHeight; type: DATA_TYPES.text,
text: event.key,
});
content.scrollTop = content.scrollTopMax;
} }
function handle_paste(event) { function handle_paste(event) {
@ -151,8 +242,11 @@ function handle_paste(event) {
} }
const paste = (event.clipboardData || window.clipboardData).getData("text"); const paste = (event.clipboardData || window.clipboardData).getData("text");
send_buffer += paste; send_buffer.push({
content.scrollTop = content.scrollHeight; type: DATA_TYPES.text,
text: paste,
});
content.scrollTop = content.scrollTopMax;
} }
const PALETTE = { const PALETTE = {

View file

@ -28,16 +28,16 @@ pre#content {
text-shadow: 0 0 1em, 0 0 3em; text-shadow: 0 0 1em, 0 0 3em;
} }
div#carat { div#caret {
width: .5em; width: .5em;
height: .9em; height: .9em;
display: inline-block; display: inline-block;
background: var(--colour); background: var(--colour);
transform: translateY(1px); transform: translateY(1px);
animation: linear .5s infinite forwards carat-blink; animation: linear .5s infinite forwards caret-blink;
} }
@keyframes carat-blink { @keyframes caret-blink {
from { from {
opacity: 1; opacity: 1;
} }

View file

@ -20,7 +20,16 @@ const MIME_TYPES = {
svg: "image/svg+xml", svg: "image/svg+xml",
}; };
const motds = [ const DATA_TYPES = {
text: 0,
colour: 1,
buffer: 2,
backspace: 3,
backword: 4,
arrow: 5,
};
const MOTDS = [
"hello, world!", "hello, world!",
"all your TTY are belong to us.", "all your TTY are belong to us.",
"TIP: got a linux system low on storage? try running `sudo rm -rf /`!", "TIP: got a linux system low on storage? try running `sudo rm -rf /`!",
@ -46,7 +55,7 @@ let sockets = [];
let buffer = ""; let buffer = "";
const MAX_BUFFER_SIZE = 10240; const MAX_BUFFER_SIZE = 10240;
const MAX_MESSAGE_LENGTH = 64; const MAX_MESSAGE_LENGTH = 1024;
async function get_file(url) { async function get_file(url) {
const paths = [STATIC_PATH, url]; const paths = [STATIC_PATH, url];
@ -76,14 +85,31 @@ const server = https.createServer(config, async (req, res) => {
const wss = new Websocket.Server({ server }); const wss = new Websocket.Server({ server });
wss.on('connection', socket => { wss.on('connection', socket => {
socket.send(`${banner}/* ${motds[Math.floor(Math.random() * motds.length)]} */\n\n`); /*
socket.send(buffer); socket.colour = generate_colour();
socket.send(JSON.stringify({
type: DATA_TYPES.colour,
colour: socket.colour,
}));
*/
socket.send(JSON.stringify({
type: DATA_TYPES.text,
text: `${banner}/* ${MOTDS[Math.floor(Math.random() * MOTDS.length)]} */\n\n`,
colour: false,
sticky: true,
}));
if (buffer) {
socket.send(JSON.stringify({
type: DATA_TYPES.buffer,
data: buffer,
}));
}
sockets.push(socket); sockets.push(socket);
// console.log(`new connection.\n\tcurrent connections: ${sockets.length}`); // console.log(`new connection.\n\tcurrent connections: ${sockets.length}`);
socket.on('message', handle_message); socket.on('message', event => { handle_message(JSON.parse(event), socket) });
socket.on('close', () => { socket.on('close', () => {
sockets = sockets.filter(s => s !== socket); sockets = sockets.filter(s => s !== socket);
@ -91,38 +117,69 @@ wss.on('connection', socket => {
}); });
}); });
function handle_message(msg) { function handle_message(data, user) {
if (msg.length > MAX_MESSAGE_LENGTH) { switch (data.type) {
return; case DATA_TYPES.backword:
} var break_point = buffer.lastIndexOf(" ");
if (msg == '\b') { const last_newline = buffer.lastIndexOf("\n");
buffer = buffer.slice(0, buffer.length - 1); if (last_newline > break_point) break_point = last_newline;
send_text('\b'); buffer = buffer.substring(0, break_point);
return; for (var i = 0; i < buffer.length - break_point; i++) {
} else if (buffer.length >= MAX_BUFFER_SIZE) { broadcast(JSON.stringify({
return; type: DATA_TYPES.backspace,
} }));
if (msg == '\n') { }
buffer += '\n'; case DATA_TYPES.backspace:
send_text('\n'); buffer = buffer.substring(0, buffer.length - 1);
return; broadcast(JSON.stringify({
type: DATA_TYPES.backspace,
}));
return;
case DATA_TYPES.text:
if (buffer.length >= MAX_BUFFER_SIZE) {
return;
}
if (data.text.length > MAX_MESSAGE_LENGTH) {
return;
}
block = {
type: DATA_TYPES.text,
text: data.text,
colour: user.colour,
};
buffer += data.text;
broadcast(JSON.stringify(block));
} }
buffer += msg.toString();
send_text(msg.toString());
/*
if (buffer.length > MAX_BUFFER_SIZE) { if (buffer.length > MAX_BUFFER_SIZE) {
buffer = buffer.slice(buffer.length - MAX_BUFFER_SIZE, buffer.length); send_as_server(`\n\nSERVER: This channel's maximum buffer length has been hit (${MAX_BUFFER_SIZE}).\n` +
`You will need to make more room, or the server will have to be restarted.\n` +
`Apologies for the inconvenience!`)
} }
*/ }
function generate_colour() {
let result = '#';
let hexref = '0123456789abcdef';
for (let i = 0; i < 6; i++) {
result += hexref.charAt(Math.floor(Math.random() * hexref.length * .75) + 4);
}
return result;
} }
server.listen(PORT, () => { server.listen(PORT, () => {
console.log(`OpenTerminal is now LIVE on https://127.0.0.1:${PORT}!`); console.log(`OpenTerminal is now LIVE on https://127.0.0.1:${PORT}!`);
}); });
function send_text(text) { function send_as_server(message) {
sockets.forEach(s => s.send(text)); broadcast(JSON.stringify({
type: DATA_TYPES.text,
text: message,
colour: "#ffffff",
}));
}
function broadcast(data) {
sockets.forEach(s => s.send(data));
} }