With basic config to have TLS certs with ACME. It works! TODO: - gitea - bar-jupyter
212 lines
6.5 KiB
HTML
212 lines
6.5 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<title>A simple netcat client</title>
|
|
<link rel="icon">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
<style>
|
|
body {
|
|
background-color: rgb(4, 18, 0);
|
|
color: rgb(199, 224, 192);
|
|
}
|
|
|
|
.container {
|
|
padding: 32px;
|
|
width: 800px;
|
|
}
|
|
|
|
@media only screen and (max-width: 480px) {
|
|
body {
|
|
font-size: 100%;
|
|
}
|
|
|
|
.container {
|
|
width: 100%;
|
|
padding: 0px;
|
|
}
|
|
}
|
|
|
|
.console {
|
|
height: 480px;
|
|
border: solid;
|
|
border-radius: 8px;
|
|
border-color: rgb(76, 75, 83);
|
|
padding: 10px;
|
|
|
|
background-color: rgb(8, 36, 0);
|
|
|
|
margin-bottom: 10px;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.console-text {
|
|
overflow: auto;
|
|
max-height: calc(100% - 20px);
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.echo {
|
|
font-size: 80%;
|
|
color: rgb(133, 199, 170);
|
|
}
|
|
|
|
.online-status {
|
|
font-weight: bold;
|
|
color: greenyellow;
|
|
font-size: larger;
|
|
display: none;
|
|
text-align: center;
|
|
width: 120px;
|
|
}
|
|
</style>
|
|
<script src="https://code.jquery.com/jquery-3.7.0.slim.min.js"></script>
|
|
<script>
|
|
$(() => {
|
|
let ws;
|
|
const history = [];
|
|
let history_cursor;
|
|
|
|
function colorize(input) {
|
|
var mapObj = {
|
|
30: '#000000',
|
|
31: '#cc0000',
|
|
32: '#4e9a06',
|
|
33: '#c4a000',
|
|
34: '#729fcf',
|
|
35: '#75507b',
|
|
36: '#06989a',
|
|
37: '#d3d7cf',
|
|
|
|
90: '#555753',
|
|
91: '#ef2929',
|
|
92: '#8ae234',
|
|
93: '#fce94f',
|
|
94: '#32afff',
|
|
95: '#ad7fa8',
|
|
96: '#34e2e2',
|
|
97: '#ffffff',
|
|
};
|
|
const colored = input.replace(/\033\[(?:0;)?(\d+)m/g, function (_, color) {
|
|
return `</span><span style="color:${mapObj[color]}">`;
|
|
}).replace(/\033\[0m/g, '</span><span>');
|
|
|
|
return `<span>${colored}</span>`;
|
|
}
|
|
|
|
document.addEventListener("visibilitychange", () => {
|
|
if (!document.hidden) {
|
|
$('link')[0].href = document.createElement('canvas').toDataURL();
|
|
}
|
|
});
|
|
|
|
function notifyActivity() {
|
|
if (document.hasFocus()) {
|
|
return;
|
|
}
|
|
|
|
let c = document.createElement('canvas');
|
|
c.width = 16;
|
|
c.height = 16;
|
|
let ctx = c.getContext('2d');
|
|
ctx.fillStyle = "red";
|
|
ctx.beginPath();
|
|
ctx.arc(7, 7, 3, 0, 2*Math.PI);
|
|
ctx.fill();
|
|
$('link')[0].href = c.toDataURL();
|
|
}
|
|
|
|
$('.input').keydown(e => {
|
|
if (e.key == "ArrowUp") {
|
|
if (history_cursor === undefined) {
|
|
history_cursor = history.length;
|
|
} else if (history_cursor === 0) {
|
|
return true;
|
|
}
|
|
|
|
history_cursor--;
|
|
$('.input').val(history[history_cursor]);
|
|
return false;
|
|
} else if (e.key == "ArrowDown" && history_cursor !== undefined) {
|
|
if (history_cursor >= history.length - 1) {
|
|
history_cursor = undefined;
|
|
$('.input').val('');
|
|
return false;
|
|
}
|
|
history_cursor++;
|
|
$('.input').val(history[history_cursor]);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
$('.input').keypress(e => {
|
|
if (e.key == "Enter") {
|
|
if (ws === undefined || ws.readyState !== 1) {
|
|
return true;
|
|
}
|
|
const sh = $('.console-text').get(0).scrollHeight;
|
|
const line = $('.input').val()
|
|
$('.console-text').append('<br /> <span class="echo">> ' + line + '</span><br />').scrollTop(sh);
|
|
$('.input').val('');
|
|
|
|
history.push(line);
|
|
history_cursor = undefined;
|
|
|
|
ws.send(`${line}\n`);
|
|
|
|
return false; //<---- Add this line
|
|
}
|
|
});
|
|
|
|
function connect() {
|
|
ws = new WebSocket($('input[name=wshost]').val());
|
|
ws.onerror = console.log;
|
|
ws.onclose = e => {
|
|
$('.online-status').hide();
|
|
$('input[type=button]').prop('value', 'Connect');
|
|
};
|
|
ws.onopen = e => {
|
|
$('.online-status').show();
|
|
$('.input').focus();
|
|
};
|
|
ws.onmessage = m => {
|
|
m.data.text().then(text => {
|
|
text = text
|
|
.replaceAll('&', '&')
|
|
.replaceAll('<', '<')
|
|
.replaceAll('>', '>');
|
|
const sh = $('.console-text').get(0).scrollHeight;
|
|
$('.console-text').append(colorize(text)).scrollTop(sh);
|
|
});
|
|
notifyActivity();
|
|
};
|
|
$('input[type=button]').prop('value', 'Disconnect');
|
|
}
|
|
|
|
function disconnect() {
|
|
ws.close();
|
|
}
|
|
|
|
$('input[type=button]').click(() => {
|
|
if (ws && ws.readyState !== WebSocket.CLOSED) {
|
|
disconnect();
|
|
} else {
|
|
connect();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="container">
|
|
<input name="wshost" value="wss://mushroom.jenova.ponteilla.net/ws"><input type="button" value="Connect">
|
|
<span class="online-status">online</span>
|
|
<div class="console">
|
|
<pre class="console-text"></pre>
|
|
</div>
|
|
<input class="input" style="width:100%">
|
|
</div>
|
|
</body>
|
|
|
|
</html>
|