a websocket byte relay onto x11vnc's tcp socket, the same shape as the terminal's relay onto the pty sidecar. this is the piece plugins/desktop could not have: a plugin cannot claim a websocket provider. the rfb client is ours rather than vendored novnc — raw and copyrect, one pixel format we dictate so a rectangle memcpys into ImageData. we control the server, so the other eight encodings are surface we would carry and never run. execution, so owner-only: wine runs as the owner, which makes the game's menus file dialogs over the owner's home. two bugs worth keeping. the token key is BEARER_TOKEN, not token, so the upgrade 401'd before any rfb byte moved. and the /status health check opened a tcp connection to prove liveness — libvncserver blocks its accept loop peeking for a websocket handshake, so a polled health check filled the backlog and locked out the real viewer. a liveness check must not be indistinguishable from a client; it reads /proc/net/tcp now. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
29 lines
1.0 KiB
TypeScript
29 lines
1.0 KiB
TypeScript
import { createRouter } from '../../create-router';
|
|
import { sessionStatus, startSession, stopSession } from './session';
|
|
|
|
/**
|
|
* Session control. The pixels do not come through here — they come through the websocket relay; this
|
|
* is only "is it up, bring it up, take it down", plus the window size the panel needs to size its
|
|
* canvas.
|
|
*/
|
|
export const minesweeperRouter = createRouter();
|
|
|
|
minesweeperRouter.get('/status', async (c) => c.json(await sessionStatus()));
|
|
|
|
minesweeperRouter.post('/start', async (c) => {
|
|
const status = await sessionStatus();
|
|
if (!status.installed) {
|
|
return c.json({ error: 'Minesweeper is not installed on this server (wine-minesweeper is missing)' }, 501);
|
|
}
|
|
if (status.running) return c.json(status);
|
|
|
|
const result = await startSession();
|
|
if (!result.ok) return c.json({ error: `Could not start the session: ${result.out.trim()}` }, 500);
|
|
return c.json(await sessionStatus());
|
|
});
|
|
|
|
minesweeperRouter.post('/stop', async (c) => {
|
|
await stopSession();
|
|
return c.json(await sessionStatus());
|
|
});
|