diff --git a/components/VNC/VNC.tsx b/components/VNC/VNC.tsx index a891806e..df553569 100644 --- a/components/VNC/VNC.tsx +++ b/components/VNC/VNC.tsx @@ -16,22 +16,38 @@ const VNC = ({ server }: Props) => { const [loaded, setLoaded] = useState(false); // DOS-style box for text - const consoleRef = useRef(null); - const statusRef = useRef(null); + const terminalRef = useRef(null); + const terminalMessageRef = useRef(null); // the actual connection and virtual screen (injected by noVNC when it's ready) const rfbRef = useRef(null); const screenRef = useRef(null); - useEffect(() => { - // end the session when the current page changes - const disconnectVM = () => { - try { - rfbRef.current.disconnect(); - } catch (e) {} // eslint-disable-line no-empty - }; + // makes the console reappear with the given message if there's an error loading, or if the VM has gone poof for + // whatever reason (doesn't really matter). + const showTerminalMessage = (message = "") => { + try { + screenRef.current.style.display = "none"; + terminalRef.current.style.display = null; + terminalMessageRef.current.textContent = `${message}\n\nPress the Any key or refresh the page to continue.`; + } catch (e) {} // eslint-disable-line no-empty + }; - // prepare for possible navigation away from this page + // hide the console when VM connects and show the screen + const showScreen = () => { + terminalRef.current.style.display = "none"; + screenRef.current.style.display = null; + }; + + // end the session forcefully + const disconnectVM = () => { + try { + rfbRef.current.disconnect(); + } catch (e) {} // eslint-disable-line no-empty + }; + + // prepare for possible navigation away from this page, and disconnect when it happens + useEffect(() => { router.events.on("routeChangeStart", disconnectVM); return () => { @@ -42,14 +58,13 @@ const VNC = ({ server }: Props) => { useEffect(() => { if (loaded) { + // don't do any of this more than once and overwhelm the fragile backend return; } if (!window.WebSocket) { // browser doesn't support websockets - statusRef.current.textContent = - "WebSockets must be enabled to play in the Y2K Sandbox!!!\n\nPress the Any key to continue."; - + showTerminalMessage("WebSockets must be enabled to begin!"); return; } @@ -57,6 +72,7 @@ const VNC = ({ server }: Props) => { rfbRef.current = new RFB(screenRef.current, server, { wsProtocols: ["binary", "base64"], }); + // scale screen to make it kinda "responsive" rfbRef.current.scaleViewport = true; @@ -67,37 +83,25 @@ const VNC = ({ server }: Props) => { rfbRef.current.addEventListener("connect", () => { console.log("successfully connected to VM socket!"); - // hide the console when VM connects - consoleRef.current.style.display = "none"; - // ...and show the screen - screenRef.current.style.display = "block"; + showScreen(); }); // VM disconnected - rfbRef.current.addEventListener("disconnect", (detail) => { + rfbRef.current.addEventListener("disconnect", (detail: unknown) => { console.warn("VM ended session remotely:", detail); - // make the console reappear now that the VM has gone poof for whatever reason (doesn't really matter) - try { - screenRef.current.style.display = "none"; - consoleRef.current.style.display = "block"; - statusRef.current.textContent = - "Oh dear, it looks like something's gone very wrong. Sorry about that.\n\nPress the Any key or refresh the page to continue."; - } catch (e) {} // eslint-disable-line no-empty + showTerminalMessage("Oh dear, it looks like something's gone very wrong. Sorry about that."); }); - - console.log( - "🤓 Hey, fellow nerd! Want to see how I made this? Check out this post: https://jarv.is/notes/y2k-sandbox/" - ); }, [loaded, server]); return ( <> -
- Spinning up your very own personal computer, please wait!{" "} +
+ Spinning up your very own personal computer, please wait!{" "} _
+ {/* the VNC canvas is hidden until we've successfully connected to the socket */}
); diff --git a/pages/y2k.tsx b/pages/y2k.tsx index a0f058ec..13aa97fb 100644 --- a/pages/y2k.tsx +++ b/pages/y2k.tsx @@ -1,3 +1,4 @@ +import { useEffect } from "react"; import dynamic from "next/dynamic"; import { NextSeo } from "next-seo"; import Wallpaper from "../components/Wallpaper/Wallpaper"; @@ -5,36 +6,55 @@ import Wallpaper from "../components/Wallpaper/Wallpaper"; // obviously, an interactive VNC display will not work even a little bit server-side const VNC = dynamic(() => import("../components/VNC/VNC"), { ssr: false }); -const Y2K = () => ( - <> - +const Y2K = () => { + // print a fancy console message (in browser only) just for funsies + useEffect(() => { + console.log( + ` +%c🤓 %cHey there, fellow nerd!%c Looking for the magic behind this page? - {/* set a random retro wallpaper tile for the content area */} - - - +%cCheck out this post: https://jarv.is/notes/y2k-sandbox/ - - -); + return ( + <> + + + {/* set a random retro wallpaper tile for the content area */} + + + + + + + ); +}; export default Y2K;