106 lines
3.1 KiB
JavaScript
106 lines
3.1 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 {
|
|
RESOURCES_PATH = [process.cwd(), 'resources'].join('/'),
|
|
} = process.env;
|
|
|
|
global.__silphiusWebsocket = null;
|
|
|
|
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 {pathname} = new URL(path, 'http://example.org');
|
|
const resourcePath = pathname.slice('/resources/'.length);
|
|
try {
|
|
const {buffer} = await readFile([RESOURCES_PATH, resourcePath].join('/'));
|
|
return buffer;
|
|
}
|
|
catch (error) {
|
|
if ('ENOENT' !== error.code) {
|
|
throw error;
|
|
}
|
|
return 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); }
|
|
}
|
|
|
|
export async function handleUpgrade(request, socket, head) {
|
|
if (!global.__silphiusWebsocket) {
|
|
const engine = new Engine(SocketServer);
|
|
await engine.load();
|
|
engine.start();
|
|
const handleConnection = 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'));
|
|
};
|
|
const wss = new WebSocketServer({
|
|
noServer: true,
|
|
});
|
|
wss.on('connection', handleConnection);
|
|
global.__silphiusWebsocket = {engine, handleConnection, wss};
|
|
}
|
|
const {pathname} = new URL(request.url, 'wss://base.url');
|
|
if (pathname === '/ws') {
|
|
const {wss} = global.__silphiusWebsocket;
|
|
wss.handleUpgrade(request, socket, head, function done(ws) {
|
|
wss.emit('connection', ws, request);
|
|
});
|
|
}
|
|
else {
|
|
socket.destroy();
|
|
}
|
|
}
|
|
|
|
if (import.meta.hot) {
|
|
import.meta.hot.on('vite:beforeUpdate', async () => {
|
|
if (global.__silphiusWebsocket) {
|
|
const {engine, handleConnection, wss} = global.__silphiusWebsocket;
|
|
wss.off('connection', handleConnection);
|
|
const connections = [];
|
|
for (const [connection] of engine.connectedPlayers) {
|
|
engine.server.send(connection, {type: 'EcsChange'});
|
|
connections.push(connection);
|
|
}
|
|
await engine.stop();
|
|
for (const connection of connections) {
|
|
connection.close();
|
|
}
|
|
global.__silphiusWebsocket = null;
|
|
}
|
|
});
|
|
import.meta.hot.accept();
|
|
}
|