import {mkdir, readFile, unlink, writeFile} from 'node:fs/promises'; import {dirname, join} from 'node:path'; import {WebSocketServer} from 'ws'; import Server from '@/net/server/server.js'; import {getSession} from '@/session.server.js'; import Engine from './engine.js'; const isInsecure = process.env.SILPHIUS_INSECURE_HTTP; const wss = new WebSocketServer({ noServer: true, }); function onUpgrade(request, socket, head) { const {pathname} = new URL(request.url, 'wss://base.url'); if (pathname === '/ws') { wss.handleUpgrade(request, socket, head, function done(ws) { wss.emit('connection', ws, request); }); } else { socket.destroy(); } } let engine; let onConnect; function createOnConnect(engine) { onConnect = async (ws, request) => { ws.on('close', async () => { await engine.disconnectPlayer(ws); }) ws.on('message', (packed) => { engine.server.accept(ws, new DataView(packed.buffer, packed.byteOffset, packed.length)); }); const session = await getSession(request.headers['cookie']); await engine.connectPlayer(ws, session.get('id')); }; wss.on('connection', onConnect); } class SocketServer extends Server { async ensurePath(path) { await mkdir(path, {recursive: true}); } static qualify(path) { return join(import.meta.dirname, 'data', 'remote', 'UNIVERSE', path); } async readAsset(path) { const url = new URL(path, 'https://localhost:3000') if (isInsecure) { url.protocol = 'http:'; } return fetch(url.href).then((response) => ( response.ok ? response.arrayBuffer() : new ArrayBuffer(0) )); } async readData(path) { const qualified = this.constructor.qualify(path); await this.ensurePath(dirname(qualified)); return readFile(qualified); } async removeData(path) { await unlink(path); } async writeData(path, view) { const qualified = this.constructor.qualify(path); await this.ensurePath(dirname(qualified)); await writeFile(qualified, view); } transmit(ws, packed) { ws.send(packed); } } async function createEngine(Engine) { engine = new Engine(SocketServer); await engine.load(); engine.start(); return engine; } async function remakeServer(Engine) { if (onConnect) { wss.off('connection', onConnect); } if (engine) { for (const [connection] of engine.connectedPlayers) { connection.close(); } } createOnConnect(await createEngine(Engine)); } (async () => { await remakeServer(Engine); })(); if (import.meta.hot) { import.meta.hot.accept('./engine.js', async ({default: Engine}) => { await remakeServer(Engine); }); } export default async function listen(server) { server.on('upgrade', onUpgrade); }