152 lines
4.7 KiB
JavaScript
152 lines
4.7 KiB
JavaScript
const {WebSocketServer} = require("ws");
|
|
const {authenticateServer} = require("../socket/actions");
|
|
const {setServerOnline} = require("../controller/link");
|
|
const crypto = require("crypto");
|
|
const {setWsHeartbeat} = require("ws-heartbeat/server");
|
|
|
|
let server;
|
|
let clients = [];
|
|
let requestQueue = [];
|
|
|
|
// Create & start the new websocket server
|
|
module.exports.startServer = (port = 8353) => {
|
|
server = new WebSocketServer({port});
|
|
initialize();
|
|
log(`Listening to port ${port}`);
|
|
}
|
|
|
|
// Stop the websocket server
|
|
module.exports.stopServer = () => {
|
|
server.close();
|
|
server = undefined;
|
|
log("Closed the server");
|
|
}
|
|
|
|
// Initializes and adds the socket listener
|
|
const initialize = () => {
|
|
server.on('connection', client => handleClientRequests(client));
|
|
|
|
setWsHeartbeat(server, (ws, data) => {
|
|
try {
|
|
if (JSON.parse(data).code === 7) { // Heartbeat
|
|
ws.send(JSON.stringify({code: 7}));
|
|
}
|
|
} catch (e) {
|
|
}
|
|
}, 5000);
|
|
}
|
|
|
|
// Handle all messages by the client
|
|
const handleClientRequests = (client) => {
|
|
client.on('message', data => {
|
|
try {
|
|
handleClientData(client, JSON.parse(data.toString()));
|
|
} catch (e) {
|
|
}
|
|
});
|
|
|
|
client.on('close', async () => this.closeServerConnectionByClient(client));
|
|
}
|
|
|
|
// Handle client json data
|
|
const handleClientData = (client, json) => {
|
|
if (!json.code) return;
|
|
if (!json.data) return;
|
|
|
|
// Resolve request
|
|
if (json.code === 6 && json.data.requestId) {
|
|
const request = requestQueue[json.data.requestId];
|
|
delete json.data.requestId;
|
|
if (request) request.resolve(json.data);
|
|
return;
|
|
}
|
|
|
|
// Authenticate
|
|
if (json.code === 1) {
|
|
for (const current in clients)
|
|
if (client === clients[current].client) return;
|
|
|
|
authenticateServer(client, json.data)
|
|
.then(currentServer => {
|
|
if (!currentServer) return;
|
|
|
|
for (const current in clients)
|
|
if (currentServer._id.toString() === clients[current].id) return client.send(JSON.stringify({
|
|
code: 5,
|
|
message: "Already connected"
|
|
}));
|
|
|
|
client.send(JSON.stringify({code: 3, message: "Authentication success"}));
|
|
|
|
clients.push({id: currentServer._id.toString(), user_id: currentServer.user_id.toString(), client});
|
|
});
|
|
}
|
|
}
|
|
|
|
// Get the server by the client object
|
|
module.exports.getServerByClient = async (client) => {
|
|
for (const current in clients) {
|
|
if (client === clients[current].client) return clients[current];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Close the server connection by the client object
|
|
module.exports.closeServerConnectionByClient = async (client) => {
|
|
for (const current in clients) {
|
|
if (client === clients[current].client) {
|
|
await setServerOnline(clients[current].id, false);
|
|
client.send(JSON.stringify({code: 4, message: "Authentication renewal required"}));
|
|
clients = clients.filter(e => e.id !== clients[current].id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close the server connection by the server id
|
|
module.exports.closeServerConnectionById = async (server_id) => {
|
|
for (const current in clients) {
|
|
if (server_id === clients[current].id) {
|
|
await setServerOnline(clients[current].id, false);
|
|
clients[current].client.send(JSON.stringify({code: 4, message: "Authentication renewal required"}));
|
|
clients = clients.filter(e => e.id !== clients[current].id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the server is connected
|
|
module.exports.isConnected = (server_id) => {
|
|
for (const current in clients)
|
|
if (server_id === clients[current].id) return true
|
|
return false;
|
|
}
|
|
|
|
// Broadcast message to a specific server by id
|
|
module.exports.broadcastToServer = (server_id, code, data) => {
|
|
clients.forEach(client => client.id === server_id ? client.client.send(JSON.stringify({code, data})) : "");
|
|
}
|
|
|
|
// Get specific information from the server
|
|
module.exports.getInformationFromServer = async (server_id, code, data) => {
|
|
if (!this.isConnected(server_id)) return null;
|
|
const requestId = crypto.randomBytes(48).toString('hex');
|
|
const request = requestQueue[requestId] = {};
|
|
|
|
await this.broadcastToServer(server_id, 6, {code, requestId, ...data});
|
|
|
|
try {
|
|
return await new Promise((resolve, reject) => {
|
|
request.resolve = resolve;
|
|
|
|
setTimeout(() => reject('Timed out'), 5000);
|
|
}).catch(() => null);
|
|
} finally {
|
|
delete requestQueue[requestId];
|
|
}
|
|
}
|
|
|
|
// Log something in the websocket server
|
|
const log = (msg) => {
|
|
console.log(`[Socket] ${msg}`);
|
|
}
|
|
|
|
module.exports.server = server; |