110 lines
2.7 KiB
JavaScript
110 lines
2.7 KiB
JavaScript
import {mkdir, readFile, unlink, writeFile} from 'node:fs/promises';
|
|
import {dirname, join} from 'node:path';
|
|
|
|
import {WebSocketServer} from 'ws';
|
|
|
|
import Server from '@/net/server.js';
|
|
import {getSession} from '@/server/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);
|
|
}
|