Compare commits
No commits in common. "193d519bd0b64fab3d0283a8e78711b6b4273426" and "43b9d9f47af6bf9a5921a5f2e3237d9fe05e3592" have entirely different histories.
193d519bd0
...
43b9d9f47a
5 changed files with 66 additions and 300 deletions
|
|
@ -10,7 +10,6 @@ COPY scripts/dos-shell /usr/local/bin/dos-shell
|
||||||
COPY scripts/dos-httpd /usr/local/bin/dos-httpd
|
COPY scripts/dos-httpd /usr/local/bin/dos-httpd
|
||||||
COPY scripts/prepare-svardos.sh /usr/local/bin/prepare-svardos
|
COPY scripts/prepare-svardos.sh /usr/local/bin/prepare-svardos
|
||||||
COPY scripts/start-services.sh /usr/local/bin/start-dos-services
|
COPY scripts/start-services.sh /usr/local/bin/start-dos-services
|
||||||
COPY WebPlus_IBM_VGA_8x16.woff /usr/local/share/dos-httpd/WebPlus_IBM_VGA_8x16.woff
|
|
||||||
RUN chmod +x /usr/local/bin/dos-shell /usr/local/bin/dos-httpd /usr/local/bin/start-dos-services /usr/local/bin/prepare-svardos && echo "/usr/local/bin/dos-shell" >> /etc/shells
|
RUN chmod +x /usr/local/bin/dos-shell /usr/local/bin/dos-httpd /usr/local/bin/start-dos-services /usr/local/bin/prepare-svardos && echo "/usr/local/bin/dos-shell" >> /etc/shells
|
||||||
|
|
||||||
# Create sshd runtime directory
|
# Create sshd runtime directory
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,6 @@ You can override which binary is used for the Linux side by setting `DOS_LINUX_S
|
||||||
| `DOS_SSH_PORT` | `2222` | Host port forwarded to container port 22. |
|
| `DOS_SSH_PORT` | `2222` | Host port forwarded to container port 22. |
|
||||||
| `DOS_TELNET_PORT` | `2323` | Host port forwarded to container port 23. |
|
| `DOS_TELNET_PORT` | `2323` | Host port forwarded to container port 23. |
|
||||||
| `DOS_HTTP_PORT` | `8080` | Host port forwarded to the web console. |
|
| `DOS_HTTP_PORT` | `8080` | Host port forwarded to the web console. |
|
||||||
| `DOS_HTTP_CRT` | `1` | Toggle the CRT styling applied to the web console (`0` to disable). |
|
|
||||||
| `ENABLE_TELNET` | `1` | Toggle BusyBox telnetd. |
|
| `ENABLE_TELNET` | `1` | Toggle BusyBox telnetd. |
|
||||||
| `ENABLE_HTTP_CONSOLE` | `1` | Launch the built-in web terminal. |
|
| `ENABLE_HTTP_CONSOLE` | `1` | Launch the built-in web terminal. |
|
||||||
| `TELNET_PORT` | `23` | Port inside the container where telnetd listens. |
|
| `TELNET_PORT` | `23` | Port inside the container where telnetd listens. |
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ services:
|
||||||
TELNET_LOGIN: /bin/login
|
TELNET_LOGIN: /bin/login
|
||||||
ENABLE_HTTP_CONSOLE: ${ENABLE_HTTP_CONSOLE:-1}
|
ENABLE_HTTP_CONSOLE: ${ENABLE_HTTP_CONSOLE:-1}
|
||||||
DOS_HTTP_PORT: ${DOS_HTTP_PORT:-8080}
|
DOS_HTTP_PORT: ${DOS_HTTP_PORT:-8080}
|
||||||
DOS_HTTP_CRT: 0
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./allowed_repo:/opt/allowed_repo:z
|
- ./allowed_repo:/opt/allowed_repo:z
|
||||||
- ./config/dos_allowed:/etc/dos_allowed:ro,z
|
- ./config/dos_allowed:/etc/dos_allowed:ro,z
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,6 @@ from aiohttp import web, WSMsgType
|
||||||
|
|
||||||
LOG = logging.getLogger("dos_httpd")
|
LOG = logging.getLogger("dos_httpd")
|
||||||
|
|
||||||
|
|
||||||
def _env_bool(name: str, default: bool) -> bool:
|
|
||||||
value = os.environ.get(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
value = value.strip().lower()
|
|
||||||
if value in {"1", "true", "yes", "on"}:
|
|
||||||
return True
|
|
||||||
if value in {"0", "false", "no", "off"}:
|
|
||||||
return False
|
|
||||||
return default
|
|
||||||
|
|
||||||
HTML_PAGE = """<!DOCTYPE html>
|
HTML_PAGE = """<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
|
@ -48,18 +36,12 @@ HTML_PAGE = """<!DOCTYPE html>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
|
||||||
font-family: "DOSVGA";
|
|
||||||
src: url("/assets/WebPlus_IBM_VGA_8x16.woff") format("woff");
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
:root, body { background: #1e1e1e; color: #f0f0f0; height: 100%; }
|
:root, body { background: #1e1e1e; color: #f0f0f0; height: 100%; }
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-family: "DOSVGA", "Fira Code", "Cascadia Mono", "Hack", monospace;
|
font-family: system-ui, sans-serif;
|
||||||
line-height: 1;
|
|
||||||
}
|
}
|
||||||
header {
|
header {
|
||||||
padding: 0.6rem 1rem;
|
padding: 0.6rem 1rem;
|
||||||
|
|
@ -68,274 +50,90 @@ HTML_PAGE = """<!DOCTYPE html>
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
#workspace {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 32px 24px 40px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
#terminal {
|
#terminal {
|
||||||
display: inline-flex;
|
flex: 1 1 auto;
|
||||||
background: rgb(12 12 12);
|
min-height: 0;
|
||||||
border: 1px solid #2b2b2b;
|
|
||||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
|
|
||||||
padding: 12px;
|
|
||||||
transform-origin: center center;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: content-box;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
.crt-display {
|
#terminal .xterm-viewport {
|
||||||
filter: saturate(1.05) contrast(1.08) brightness(0.95);
|
background-color: #000;
|
||||||
--crt-line-step: 1;
|
|
||||||
}
|
|
||||||
.crt-display::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
background-image:
|
|
||||||
repeating-linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
rgba(255, 255, 255, 0.06) 0px,
|
|
||||||
rgba(255, 255, 255, 0.06) calc(var(--crt-line-step) * 1px),
|
|
||||||
rgba(0, 0, 0, 0) calc(var(--crt-line-step) * 1px),
|
|
||||||
rgba(0, 0, 0, 0) calc(var(--crt-line-step) * 2px)
|
|
||||||
),
|
|
||||||
repeating-linear-gradient(
|
|
||||||
to right,
|
|
||||||
rgba(255, 255, 255, 0.025) 0px,
|
|
||||||
rgba(255, 255, 255, 0.025) calc(var(--crt-line-step) * 1px),
|
|
||||||
rgba(0, 0, 0, 0) calc(var(--crt-line-step) * 1px),
|
|
||||||
rgba(0, 0, 0, 0) calc(var(--crt-line-step) * 2px)
|
|
||||||
);
|
|
||||||
mix-blend-mode: screen;
|
|
||||||
opacity: 0.4;
|
|
||||||
animation: crt-scan 6s linear infinite;
|
|
||||||
}
|
|
||||||
.crt-display::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: -0.1%;
|
|
||||||
pointer-events: none;
|
|
||||||
background: radial-gradient(circle at center, rgba(255, 255, 255, 0.08) 0%, rgba(0, 0, 0, 0.45) 70%, rgba(0, 0, 0, 0.75) 100%);
|
|
||||||
mix-blend-mode: multiply;
|
|
||||||
animation: crt-flicker 3s infinite;
|
|
||||||
}
|
|
||||||
@keyframes crt-scan {
|
|
||||||
0% { transform: translateY(-2%); }
|
|
||||||
100% { transform: translateY(2%); }
|
|
||||||
}
|
|
||||||
@keyframes crt-flicker {
|
|
||||||
0%, 100% { opacity: 0.35; }
|
|
||||||
45% { opacity: 0.45; }
|
|
||||||
50% { opacity: 0.3; }
|
|
||||||
55% { opacity: 0.4; }
|
|
||||||
90% { opacity: 0.33; }
|
|
||||||
}
|
|
||||||
#terminal .xterm {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
#terminal .xterm .xterm-helper-textarea {
|
|
||||||
width: 0 !important;
|
|
||||||
height: 0 !important;
|
|
||||||
}
|
|
||||||
#terminal .xterm-viewport,
|
|
||||||
#terminal .xterm-screen,
|
|
||||||
#terminal .xterm-rows,
|
|
||||||
#terminal .xterm-scroll-area {
|
|
||||||
width: 640px !important;
|
|
||||||
height: 400px !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
.xterm-dom-renderer-owner-1 .xterm-bg-0 {
|
|
||||||
background-color: rgb(14 14 14) !important;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>SvarBox DOS Console</header>
|
<header>SvarBox DOS Console</header>
|
||||||
<main id="workspace">
|
<div id="terminal"></div>
|
||||||
<div id="terminal"></div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { Terminal } from "https://cdn.jsdelivr.net/npm/xterm@5.3.0/+esm";
|
import { Terminal } from "https://cdn.jsdelivr.net/npm/xterm@5.3.0/+esm";
|
||||||
const CRT_ENABLED = __CRT_ENABLED__;
|
import { FitAddon } from "https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/+esm";
|
||||||
|
|
||||||
(async () => {
|
const term = new Terminal({
|
||||||
const COLS = 80;
|
cursorBlink: true,
|
||||||
const ROWS = 25;
|
convertEol: true,
|
||||||
const CHAR_HEIGHT = 16;
|
theme: {
|
||||||
const VIEWPORT_WIDTH = 640;
|
background: "#000000",
|
||||||
const VIEWPORT_HEIGHT = 400;
|
foreground: "#f5f5f5"
|
||||||
const BASE_VERTICAL_STRETCH = 1.2;
|
},
|
||||||
const TARGET_ROW_HEIGHT = VIEWPORT_HEIGHT / ROWS;
|
});
|
||||||
|
const fitAddon = new FitAddon();
|
||||||
|
|
||||||
const terminalHost = document.getElementById("terminal");
|
term.loadAddon(fitAddon);
|
||||||
if (CRT_ENABLED) {
|
term.open(document.getElementById("terminal"));
|
||||||
terminalHost.classList.add("crt-display");
|
|
||||||
} else {
|
function fitLater() {
|
||||||
terminalHost.classList.remove("crt-display");
|
requestAnimationFrame(() => fitAddon.fit());
|
||||||
|
}
|
||||||
|
|
||||||
|
fitLater();
|
||||||
|
window.addEventListener("resize", fitLater);
|
||||||
|
|
||||||
|
const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws";
|
||||||
|
const socket = new WebSocket(`${wsProtocol}://${window.location.host}/ws`);
|
||||||
|
const textDecoder = new TextDecoder("utf-8", { fatal: false });
|
||||||
|
|
||||||
|
function decodeBase64ToString(b64) {
|
||||||
|
const binary = atob(b64);
|
||||||
|
const bytes = new Uint8Array(binary.length);
|
||||||
|
for (let i = 0; i < binary.length; i += 1) {
|
||||||
|
bytes[i] = binary.charCodeAt(i);
|
||||||
}
|
}
|
||||||
|
return textDecoder.decode(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
async function waitForDosvgaFont() {
|
socket.addEventListener("open", () => {
|
||||||
if (!document.fonts || typeof document.fonts.load !== "function") {
|
fitLater();
|
||||||
return;
|
term.focus();
|
||||||
}
|
});
|
||||||
|
|
||||||
try {
|
socket.addEventListener("message", (event) => {
|
||||||
await Promise.race([
|
try {
|
||||||
document.fonts.load(`${CHAR_HEIGHT}px "DOSVGA"`),
|
const payload = JSON.parse(event.data);
|
||||||
new Promise((resolve) => setTimeout(resolve, 2000)),
|
if (payload.type === "output") {
|
||||||
]);
|
term.write(decodeBase64ToString(payload.data));
|
||||||
} catch (err) {
|
} else if (payload.type === "exit") {
|
||||||
console.debug("DOSVGA font load race rejected", err);
|
term.write("\\r\\n[dos-shell exited]\\r\\n");
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("failed to process message", err);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function applyViewportClamp() {
|
socket.addEventListener("close", (event) => {
|
||||||
terminalHost.style.width = `${VIEWPORT_WIDTH}px`;
|
term.write(`\\r\\n[connection closed: ${event.code}]\\r\\n`);
|
||||||
terminalHost.style.height = `${VIEWPORT_HEIGHT}px`;
|
});
|
||||||
|
|
||||||
const viewport = terminalHost.querySelector(".xterm-viewport");
|
socket.addEventListener("error", (event) => {
|
||||||
if (viewport) {
|
console.error("websocket error", event);
|
||||||
viewport.style.width = `${VIEWPORT_WIDTH}px`;
|
term.write("\\r\\n[websocket error]\\r\\n");
|
||||||
viewport.style.height = `${VIEWPORT_HEIGHT}px`;
|
});
|
||||||
viewport.style.overflow = "hidden";
|
|
||||||
}
|
|
||||||
|
|
||||||
const scrollArea = terminalHost.querySelector(".xterm-scroll-area");
|
term.onData((data) => {
|
||||||
if (scrollArea) {
|
socket.send(JSON.stringify({ type: "input", data }));
|
||||||
scrollArea.style.width = `${VIEWPORT_WIDTH}px`;
|
});
|
||||||
scrollArea.style.height = `${VIEWPORT_HEIGHT}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const screen = terminalHost.querySelector(".xterm-screen");
|
term.onResize(({ cols, rows }) => {
|
||||||
if (screen) {
|
socket.send(JSON.stringify({ type: "resize", cols, rows }));
|
||||||
screen.style.width = `${VIEWPORT_WIDTH}px`;
|
});
|
||||||
screen.style.height = `${VIEWPORT_HEIGHT}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = terminalHost.querySelector(".xterm-rows");
|
|
||||||
if (rows) {
|
|
||||||
rows.style.width = `${VIEWPORT_WIDTH}px`;
|
|
||||||
rows.style.height = `${VIEWPORT_HEIGHT}px`;
|
|
||||||
const rowDivs = rows.querySelectorAll("div");
|
|
||||||
rowDivs.forEach((div) => {
|
|
||||||
div.style.height = `${TARGET_ROW_HEIGHT}px`;
|
|
||||||
div.style.lineHeight = `${TARGET_ROW_HEIGHT}px`;
|
|
||||||
div.style.width = `${VIEWPORT_WIDTH}px`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateScale() {
|
|
||||||
const maxWidth = window.innerWidth * 0.85;
|
|
||||||
const maxHeight = window.innerHeight * 0.85;
|
|
||||||
|
|
||||||
// reset transform to measure base stretched size
|
|
||||||
terminalHost.style.transform = `scaleY(${BASE_VERTICAL_STRETCH})`;
|
|
||||||
terminalHost.style.transformOrigin = "center center";
|
|
||||||
|
|
||||||
const rect = terminalHost.getBoundingClientRect();
|
|
||||||
const scaleForWidth = maxWidth / rect.width;
|
|
||||||
const scaleForHeight = maxHeight / rect.height;
|
|
||||||
const uniformScale = Math.min(scaleForWidth, scaleForHeight);
|
|
||||||
if (CRT_ENABLED) {
|
|
||||||
terminalHost.style.setProperty('--crt-line-step', (1 / uniformScale).toString());
|
|
||||||
} else {
|
|
||||||
terminalHost.style.removeProperty('--crt-line-step');
|
|
||||||
}
|
|
||||||
terminalHost.style.transform = `scale(${uniformScale}) scaleY(${BASE_VERTICAL_STRETCH})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
await waitForDosvgaFont();
|
|
||||||
|
|
||||||
const term = new Terminal({
|
|
||||||
cursorBlink: true,
|
|
||||||
convertEol: true,
|
|
||||||
fontFamily: "DOSVGA, Fira Code, Cascadia Mono, Hack, monospace",
|
|
||||||
fontSize: CHAR_HEIGHT,
|
|
||||||
lineHeight: 1,
|
|
||||||
cols: COLS,
|
|
||||||
rows: ROWS,
|
|
||||||
theme: {
|
|
||||||
background: "#000000",
|
|
||||||
foreground: "#f5f5f5"
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
term.open(terminalHost);
|
|
||||||
term.resize(COLS, ROWS);
|
|
||||||
applyViewportClamp();
|
|
||||||
updateScale();
|
|
||||||
|
|
||||||
const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws";
|
|
||||||
const socket = new WebSocket(`${wsProtocol}://${window.location.host}/ws`);
|
|
||||||
const textDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
||||||
|
|
||||||
function decodeBase64ToString(b64) {
|
|
||||||
const binary = atob(b64);
|
|
||||||
const bytes = new Uint8Array(binary.length);
|
|
||||||
for (let i = 0; i < binary.length; i += 1) {
|
|
||||||
bytes[i] = binary.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return textDecoder.decode(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.addEventListener("open", () => {
|
|
||||||
socket.send(JSON.stringify({ type: "resize", cols: term.cols, rows: term.rows }));
|
|
||||||
term.focus();
|
|
||||||
applyViewportClamp();
|
|
||||||
updateScale();
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener("message", (event) => {
|
|
||||||
try {
|
|
||||||
const payload = JSON.parse(event.data);
|
|
||||||
if (payload.type === "output") {
|
|
||||||
term.write(decodeBase64ToString(payload.data));
|
|
||||||
} else if (payload.type === "exit") {
|
|
||||||
term.write("\\r\\n[dos-shell exited]\\r\\n");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("failed to process message", err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener("close", (event) => {
|
|
||||||
term.write(`\\r\\n[connection closed: ${event.code}]\\r\\n`);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener("error", (event) => {
|
|
||||||
console.error("websocket error", event);
|
|
||||||
term.write("\\r\\n[websocket error]\\r\\n");
|
|
||||||
});
|
|
||||||
|
|
||||||
term.onData((data) => {
|
|
||||||
socket.send(JSON.stringify({ type: "input", data }));
|
|
||||||
});
|
|
||||||
|
|
||||||
term.onResize(({ cols, rows }) => {
|
|
||||||
socket.send(JSON.stringify({ type: "resize", cols, rows }));
|
|
||||||
applyViewportClamp();
|
|
||||||
updateScale();
|
|
||||||
});
|
|
||||||
|
|
||||||
term.onRender(() => {
|
|
||||||
applyViewportClamp();
|
|
||||||
updateScale();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
|
||||||
applyViewportClamp();
|
|
||||||
updateScale();
|
|
||||||
}, { passive: true });
|
|
||||||
})();
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -510,22 +308,13 @@ class ShellSession:
|
||||||
|
|
||||||
|
|
||||||
async def index_handler(_request: web.Request) -> web.StreamResponse:
|
async def index_handler(_request: web.Request) -> web.StreamResponse:
|
||||||
cfg: "AppConfig" = _request.app["config"]
|
return web.Response(text=HTML_PAGE, content_type="text/html", headers={"Cache-Control": "no-store"})
|
||||||
page = HTML_PAGE.replace("__CRT_ENABLED__", "true" if cfg.crt_effect else "false")
|
|
||||||
return web.Response(text=page, content_type="text/html", headers={"Cache-Control": "no-store"})
|
|
||||||
|
|
||||||
|
|
||||||
async def health_handler(_request: web.Request) -> web.Response:
|
async def health_handler(_request: web.Request) -> web.Response:
|
||||||
return web.Response(text="ok\n", content_type="text/plain")
|
return web.Response(text="ok\n", content_type="text/plain")
|
||||||
|
|
||||||
|
|
||||||
async def font_handler(request: web.Request) -> web.StreamResponse:
|
|
||||||
cfg: "AppConfig" = request.app["config"]
|
|
||||||
if not os.path.exists(cfg.font_path):
|
|
||||||
raise web.HTTPNotFound()
|
|
||||||
return web.FileResponse(path=cfg.font_path, headers={"Cache-Control": "public, max-age=86400"})
|
|
||||||
|
|
||||||
|
|
||||||
async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
|
async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
|
||||||
ws = web.WebSocketResponse(heartbeat=30)
|
ws = web.WebSocketResponse(heartbeat=30)
|
||||||
await ws.prepare(request)
|
await ws.prepare(request)
|
||||||
|
|
@ -558,17 +347,13 @@ async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
|
||||||
|
|
||||||
|
|
||||||
class AppConfig:
|
class AppConfig:
|
||||||
FONT_PATH = "/usr/local/share/dos-httpd/WebPlus_IBM_VGA_8x16.woff"
|
def __init__(self, user: str, shell_path: str, host: str, port: int, rows: int, cols: int):
|
||||||
|
|
||||||
def __init__(self, user: str, shell_path: str, host: str, port: int, rows: int, cols: int, crt_effect: bool):
|
|
||||||
self.user = user
|
self.user = user
|
||||||
self.shell_path = shell_path
|
self.shell_path = shell_path
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.default_rows = rows
|
self.default_rows = rows
|
||||||
self.default_cols = cols
|
self.default_cols = cols
|
||||||
self.font_path = self.FONT_PATH
|
|
||||||
self.crt_effect = crt_effect
|
|
||||||
|
|
||||||
|
|
||||||
def build_argument_parser() -> argparse.ArgumentParser:
|
def build_argument_parser() -> argparse.ArgumentParser:
|
||||||
|
|
@ -593,10 +378,6 @@ def build_argument_parser() -> argparse.ArgumentParser:
|
||||||
choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
|
choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
|
||||||
help="Log verbosity",
|
help="Log verbosity",
|
||||||
)
|
)
|
||||||
default_crt = _env_bool("DOS_HTTP_CRT", True)
|
|
||||||
parser.set_defaults(crt_effect=default_crt)
|
|
||||||
parser.add_argument("--crt", dest="crt_effect", action="store_true", help="Enable CRT overlay")
|
|
||||||
parser.add_argument("--no-crt", dest="crt_effect", action="store_false", help="Disable CRT overlay")
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -611,7 +392,6 @@ async def create_app(cfg: AppConfig) -> web.Application:
|
||||||
[
|
[
|
||||||
web.get("/", index_handler),
|
web.get("/", index_handler),
|
||||||
web.get("/healthz", health_handler),
|
web.get("/healthz", health_handler),
|
||||||
web.get("/assets/WebPlus_IBM_VGA_8x16.woff", font_handler),
|
|
||||||
web.get("/ws", websocket_handler),
|
web.get("/ws", websocket_handler),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
@ -630,7 +410,6 @@ def main() -> None:
|
||||||
port=args.port,
|
port=args.port,
|
||||||
rows=args.rows,
|
rows=args.rows,
|
||||||
cols=args.cols,
|
cols=args.cols,
|
||||||
crt_effect=args.crt_effect,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
app = asyncio.run(create_app(cfg))
|
app = asyncio.run(create_app(cfg))
|
||||||
|
|
|
||||||
|
|
@ -113,16 +113,6 @@ start_http_console() {
|
||||||
if [ -n "${DOS_HTTP_LOG_LEVEL:-}" ]; then
|
if [ -n "${DOS_HTTP_LOG_LEVEL:-}" ]; then
|
||||||
args+=(--log-level "${DOS_HTTP_LOG_LEVEL}")
|
args+=(--log-level "${DOS_HTTP_LOG_LEVEL}")
|
||||||
fi
|
fi
|
||||||
if [ -n "${DOS_HTTP_CRT:-}" ]; then
|
|
||||||
case "${DOS_HTTP_CRT,,}" in
|
|
||||||
0|false|no|off)
|
|
||||||
args+=(--no-crt)
|
|
||||||
;;
|
|
||||||
1|true|yes|on)
|
|
||||||
args+=(--crt)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
"${DOS_HTTPD_BIN}" "${args[@]}" &
|
"${DOS_HTTPD_BIN}" "${args[@]}" &
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue