MWSE/index.js

127 lines
4.1 KiB
JavaScript

/** @type {import('node:cluster').Cluster} */
const cluster = require("cluster");
const os = require("os");
let {randomUUID} = require("crypto");
/**
* Use Round Robin algorithm for cluster process load balancer
*/
// cluster.schedulingPolicy = cluster.SCHED_RR;
async function main()
{
if(cluster.isPrimary == false)
{
console.log("Slave Process PID:", process.pid);
// This process is a worker / slave
// Compile source code and run
require("./Source/index");
// stay here
return;
};
// This process is a primary / master
console.log("Master Process PID:", process.pid);
// Worker process list
const master = new Map();
const coreCount = 3 //os.cpus().length;
for(let index = 0; index < coreCount; index++)
{
// Open slave process
let worker = await generateFlow();
// Save process with id
master.set(worker.id, worker);
// Listen process for commands
worker.message(
// This process want to send payload to sibling process with IPC
(workerId, payload) =>{
// Check Target worker
if(payload.core)
{
switch(payload.core)
{
case "writestat":{
master.get(workerId).setStats(payload)
break;
}
case "readstat":{
master.get(workerId).send({
type: ':stats:',
data: [
...master.entries()
].map((
[, master]
) => {
let e = master.getStats();
return {
core: master.uuid,
ws_writed_bytes:e.ws_writed_bytes,
ws_readed_bytes:e.ws_readed_bytes,
ws_total_bytes:e.ws_total_bytes,
ws_sended_packs:e.ws_sended_packs,
ws_recaived_packs:e.ws_recaived_packs,
ws_total_packs:e.ws_total_packs,
mwse_rooms: e.mwse_rooms,
mwse_clients: e.mwse_clients
}
})
})
break;
}
}
}else if(payload.process)
{
master.get(payload.process).send({
...payload,
pid: worker.id
})
}else for (const [siblingWorkerId,{send}] of master) {
// No sending to itself
if(workerId !== siblingWorkerId)
{
// Send command to sibling with IPC
send({
...payload,
pid: worker.id
})
}
}
}
)
}
}
async function generateFlow()
{
// Mirror this process with for (low-level os multitasking)
const worker = cluster.fork();
// Wait process is online
await new Promise(ok => {
worker.addListener("online",()=> {
ok()
})
});
// Get process pid on the os
let id = worker.process.pid;
let stats = {};
// Simplification wrapping send and get events with IPC's event functions
return {
id,
uuid: randomUUID(),
send: message => worker.send(message),
message: (callback) => worker.addListener("message", e => callback(id,e)),
getStats: () => stats,
setStats: e => Object.assign(stats, e)
}
}
// Run immediately
process.nextTick(main);