diff --git a/src/app/components/SerialConsolePage.tsx b/src/app/components/SerialConsolePage.tsx
index 8658f0d..3d58d81 100644
--- a/src/app/components/SerialConsolePage.tsx
+++ b/src/app/components/SerialConsolePage.tsx
@@ -1,21 +1,23 @@
-import { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef } from 'react';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import '@xterm/xterm/css/xterm.css';
-import { ChevronLeft, Plug, Radio, RotateCcw, Unplug } from 'lucide-react';
+import { ChevronLeft, Radio, RotateCcw } from 'lucide-react';
+import { useWs } from '../ws';
interface Props { onBack: () => void; }
-type ConnStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
-
export default function SerialConsolePage({ onBack }: Props) {
const containerRef = useRef
(null);
const termRef = useRef(null);
const fitRef = useRef(null);
- const wsRef = useRef(null);
- const [status, setStatus] = useState('disconnected');
+ const { status, send, subscribe } = useWs();
- // Initialize xterm on mount
+ // Keep a stable ref to `send` so the xterm onData closure never goes stale
+ const sendRef = useRef(send);
+ useEffect(() => { sendRef.current = send; }, [send]);
+
+ // Initialize xterm once on mount
useEffect(() => {
const el = containerRef.current;
if (!el) return;
@@ -42,12 +44,9 @@ export default function SerialConsolePage({ onBack }: Props) {
fitRef.current = fit;
term.writeln('\x1b[2m── Meatloaf Serial Console ──\x1b[0m');
- term.writeln('\x1b[2mPress Connect to open a session.\x1b[0m');
term.writeln('');
- term.onData((data) => {
- if (wsRef.current?.readyState === WebSocket.OPEN) wsRef.current.send(data);
- });
+ term.onData((data) => sendRef.current(data));
const onResize = () => fitRef.current?.fit();
window.addEventListener('resize', onResize);
@@ -60,79 +59,20 @@ export default function SerialConsolePage({ onBack }: Props) {
};
}, []);
- // Close WebSocket on unmount
+ // Forward all incoming WS messages to the terminal
useEffect(() => {
- return () => {
- if (wsRef.current) {
- wsRef.current.onopen = wsRef.current.onmessage = wsRef.current.onerror = wsRef.current.onclose = null;
- wsRef.current.close();
- wsRef.current = null;
- }
- };
- }, []);
-
- const writeln = (msg: string) => termRef.current?.writeln(msg);
-
- const connect = () => {
- if (wsRef.current) {
- wsRef.current.onopen = wsRef.current.onmessage = wsRef.current.onerror = wsRef.current.onclose = null;
- wsRef.current.close();
- wsRef.current = null;
- }
-
- const url = `ws://${window.location.hostname}/console`;
- setStatus('connecting');
- writeln(`\x1b[2mConnecting to ${url}…\x1b[0m`);
-
- const ws = new WebSocket(url);
- ws.binaryType = 'arraybuffer';
- wsRef.current = ws;
-
- ws.onopen = () => {
- setStatus('connected');
- writeln('\x1b[32mConnected.\x1b[0m');
- };
-
- ws.onmessage = (ev) => {
- if (!termRef.current) return;
- if (ev.data instanceof ArrayBuffer) termRef.current.write(new Uint8Array(ev.data));
- else termRef.current.write(String(ev.data));
- };
-
- let hadError = false;
- ws.onerror = () => {
- hadError = true;
- writeln('\x1b[31mConnection error.\x1b[0m');
- };
-
- ws.onclose = (ev) => {
- setStatus(hadError ? 'error' : 'disconnected');
- wsRef.current = null;
- if (!hadError) writeln(`\x1b[2mSession ended${ev.reason ? `: ${ev.reason}` : ''}.\x1b[0m`);
- };
- };
-
- const disconnect = () => {
- if (wsRef.current) {
- wsRef.current.onopen = wsRef.current.onmessage = wsRef.current.onerror = wsRef.current.onclose = null;
- wsRef.current.close();
- wsRef.current = null;
- }
- setStatus('disconnected');
- writeln('\x1b[2mDisconnected.\x1b[0m');
- };
-
- const busy = status === 'connecting' || status === 'connected';
+ return subscribe((msg) => {
+ termRef.current?.write(msg);
+ });
+ }, [subscribe]);
const statusColor =
- status === 'connected' ? 'text-green-400' :
- status === 'connecting' ? 'text-amber-400' :
- status === 'error' ? 'text-red-400' : 'text-neutral-500';
+ status === 'connected' ? 'text-green-400' :
+ status === 'connecting' ? 'text-amber-400' : 'text-neutral-500';
const statusLabel =
status === 'connected' ? 'Connected' :
- status === 'connecting' ? 'Connecting…' :
- status === 'error' ? 'Error' : 'Disconnected';
+ status === 'connecting' ? 'Connecting…' : 'Disconnected';
return (
@@ -143,7 +83,7 @@ export default function SerialConsolePage({ onBack }: Props) {
style={{ paddingTop: 'max(0.5rem, env(safe-area-inset-top))' }}
>
-
-
{/* Terminal */}
diff --git a/webdav3.py b/webdav3.py
index 65af666..46f033c 100644
--- a/webdav3.py
+++ b/webdav3.py
@@ -941,7 +941,7 @@ class DAVServer(ThreadingMixIn, HTTPServer):
pass
if __name__ == '__main__':
- # WebDav TCP Port
+ # WebDav TCP Port
srvport = 80
# Get local IP address
myaddr = get_localip()