Add Fabric client IRC chat mod and Drone pipeline
This commit is contained in:
6
server/config.json
Normal file
6
server/config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"host": "0.0.0.0",
|
||||
"port": 24469,
|
||||
"token": ""
|
||||
}
|
||||
|
||||
132
server/irc-server.js
Normal file
132
server/irc-server.js
Normal file
@@ -0,0 +1,132 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const net = require('node:net');
|
||||
|
||||
const configPath = path.join(__dirname, 'config.json');
|
||||
const defaultConfig = {
|
||||
host: '0.0.0.0',
|
||||
port: 24469,
|
||||
token: ''
|
||||
};
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
|
||||
}
|
||||
|
||||
const config = {
|
||||
...defaultConfig,
|
||||
...JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
||||
};
|
||||
|
||||
const clients = new Set();
|
||||
|
||||
function sendJson(socket, payload) {
|
||||
socket.write(JSON.stringify(payload) + '\n');
|
||||
}
|
||||
|
||||
function broadcast(payload) {
|
||||
const line = JSON.stringify(payload) + '\n';
|
||||
for (const socket of clients) {
|
||||
if (!socket.destroyed) {
|
||||
socket.write(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function systemMessage(message) {
|
||||
return {
|
||||
type: 'system',
|
||||
message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
const server = net.createServer((socket) => {
|
||||
socket.setEncoding('utf8');
|
||||
clients.add(socket);
|
||||
let buffer = '';
|
||||
|
||||
sendJson(socket, systemMessage('Connected to IRC server.'));
|
||||
console.log(`[connect] ${socket.remoteAddress}:${socket.remotePort}`);
|
||||
|
||||
socket.on('data', (chunk) => {
|
||||
buffer += chunk;
|
||||
|
||||
let separatorIndex = buffer.indexOf('\n');
|
||||
while (separatorIndex !== -1) {
|
||||
const rawLine = buffer.slice(0, separatorIndex).trim();
|
||||
buffer = buffer.slice(separatorIndex + 1);
|
||||
separatorIndex = buffer.indexOf('\n');
|
||||
|
||||
if (!rawLine) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let payload;
|
||||
try {
|
||||
payload = JSON.parse(rawLine);
|
||||
} catch (error) {
|
||||
sendJson(socket, systemMessage(`Bad JSON: ${error.message}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.token && payload.token !== config.token) {
|
||||
sendJson(socket, systemMessage('Invalid token.'));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (payload.type === 'hello') {
|
||||
const name = payload.player || 'unknown';
|
||||
sendJson(socket, systemMessage(`Hello, ${name}.`));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (payload.type === 'chat') {
|
||||
const clientName = String(payload.client || 'UNKNOWN-CLIENT').trim();
|
||||
const playerName = String(payload.player || 'unknown').trim();
|
||||
const message = String(payload.message || '').trim();
|
||||
|
||||
if (!message) {
|
||||
sendJson(socket, systemMessage('Empty chat message ignored.'));
|
||||
continue;
|
||||
}
|
||||
|
||||
const outgoing = {
|
||||
type: 'chat',
|
||||
client: clientName,
|
||||
player: playerName,
|
||||
message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
console.log(`[chat] ${clientName} >> ${playerName}: ${message}`);
|
||||
broadcast(outgoing);
|
||||
continue;
|
||||
}
|
||||
|
||||
sendJson(socket, systemMessage(`Unknown packet type: ${payload.type}`));
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('close', () => {
|
||||
clients.delete(socket);
|
||||
console.log(`[disconnect] ${socket.remoteAddress}:${socket.remotePort}`);
|
||||
});
|
||||
|
||||
socket.on('error', (error) => {
|
||||
clients.delete(socket);
|
||||
console.error(`[socket-error] ${socket.remoteAddress}:${socket.remotePort} ${error.message}`);
|
||||
});
|
||||
});
|
||||
|
||||
server.on('error', (error) => {
|
||||
console.error(`[server-error] ${error.message}`);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
|
||||
server.listen(config.port, config.host, () => {
|
||||
console.log(`IRC server listening on ${config.host}:${config.port}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user