Merge pull request 'multitasking' (#7) from multitasking into stable
Reviewed-on: #7
This commit is contained in:
		
						commit
						03ae02e8ba
					
				| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
const { CLIENT_SEND_MESSAGE, CLIENT_UPDATE_PROP } = require("./IPC");
 | 
			
		||||
const stats = require("./stats");
 | 
			
		||||
function Client()
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +23,17 @@ function Client()
 | 
			
		|||
    this.APNumber = 0;
 | 
			
		||||
    this.APShortCode = 0;
 | 
			
		||||
    this.APIPAddress = 0;
 | 
			
		||||
 | 
			
		||||
    this.isProxy = false;
 | 
			
		||||
    this.proxyProcess = null;
 | 
			
		||||
 | 
			
		||||
    this.sync = function(...args){
 | 
			
		||||
        process.nextTick(()=>{
 | 
			
		||||
            for (const name of args) {
 | 
			
		||||
                CLIENT_UPDATE_PROP(this.id, name, this[name]);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
/**
 | 
			
		||||
 * @type {Map<string, Client>}
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +47,7 @@ Client.prototype.peerRequest = function(client){
 | 
			
		|||
    let info = {};
 | 
			
		||||
    this.store.forEach((value, name) => info[name] = value);
 | 
			
		||||
    this.pairs.add(client.id);
 | 
			
		||||
    this.sync('pairs');
 | 
			
		||||
    client.send([{
 | 
			
		||||
        from: this.id,
 | 
			
		||||
        info
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +59,7 @@ Client.prototype.peerRequest = function(client){
 | 
			
		|||
 */
 | 
			
		||||
 Client.prototype.acceptPeerRequest = function(client){
 | 
			
		||||
    this.pairs.add(client.id);
 | 
			
		||||
    this.sync('pairs');
 | 
			
		||||
    client.send([{
 | 
			
		||||
        from: this.id
 | 
			
		||||
    },'accepted/pair']);
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +70,7 @@ Client.prototype.peerRequest = function(client){
 | 
			
		|||
Client.prototype.rejectPeerRequest = function(client){
 | 
			
		||||
    this.pairs.delete(client.id);
 | 
			
		||||
    client.pairs.delete(this.id);
 | 
			
		||||
    this.sync('pairs');
 | 
			
		||||
    client.send([{
 | 
			
		||||
        from: this.id
 | 
			
		||||
    },'rejected/pair']);
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +91,13 @@ Client.prototype.pairList = function(){
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
Client.prototype.send = function(obj){
 | 
			
		||||
    this.socket.sendUTF(JSON.stringify(obj));
 | 
			
		||||
    if(this.isProxy)
 | 
			
		||||
    {
 | 
			
		||||
        CLIENT_SEND_MESSAGE(this.id, obj, this.proxyProcess)
 | 
			
		||||
    }else{
 | 
			
		||||
        stats.ws_sended_packs++;
 | 
			
		||||
        this.socket.sendUTF(JSON.stringify(obj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.Client = Client;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,19 +6,27 @@ let compression = require("compression");
 | 
			
		|||
let {resolve} = require("path");
 | 
			
		||||
const { termoutput } = require("./config");
 | 
			
		||||
let server = http.createServer();
 | 
			
		||||
const stats = require("./stats");
 | 
			
		||||
let app = express();
 | 
			
		||||
server.addListener("request", app);
 | 
			
		||||
app.use(compression({
 | 
			
		||||
    level: 9
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
server.listen(7707,'0.0.0.0',() => {
 | 
			
		||||
    termoutput && console.log("HTTP Service Running...");
 | 
			
		||||
});
 | 
			
		||||
server.addListener("error",(err)=> {
 | 
			
		||||
    console.err(err)
 | 
			
		||||
})
 | 
			
		||||
exports.http = server;
 | 
			
		||||
 | 
			
		||||
app.get("/script",(request, response)=>{
 | 
			
		||||
    response.sendFile(resolve("./script/index.js"))
 | 
			
		||||
});
 | 
			
		||||
app.get("/test",(request, response)=>{
 | 
			
		||||
    response.sendFile(resolve("./script/test.html"))
 | 
			
		||||
});
 | 
			
		||||
app.get("/index.js.map",(request, response)=>{
 | 
			
		||||
    response.sendFile(resolve("./script/index.js.map"))
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +36,12 @@ app.get("/webrtc.js",(request, response)=>{
 | 
			
		|||
app.get("/webrtc.adapter.js",(request, response)=>{
 | 
			
		||||
    response.sendFile(resolve("./script/webrtc.adapter.js"))
 | 
			
		||||
});
 | 
			
		||||
app.get("/",(request, response)=>{
 | 
			
		||||
    response.sendFile(resolve("./script/index.html"))
 | 
			
		||||
});
 | 
			
		||||
app.post("/stats",(request, response)=>{
 | 
			
		||||
    response.json(stats.others);
 | 
			
		||||
});
 | 
			
		||||
app.get("*",(request, response)=>{
 | 
			
		||||
    response.sendFile(resolve("./script/status.xml"))
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,187 @@
 | 
			
		|||
 | 
			
		||||
process.on('message',data => {
 | 
			
		||||
    const { Client } = require("./Client.js");
 | 
			
		||||
    const { Room } = require("./Services/Room");
 | 
			
		||||
    switch(data.type)
 | 
			
		||||
    {
 | 
			
		||||
        case "CLIENT_CREATED":{
 | 
			
		||||
            slog("CLIENT_CREATED");
 | 
			
		||||
            let client = new Client();
 | 
			
		||||
            client.isProxy = true;
 | 
			
		||||
            client.proxyProcess = data.pid;
 | 
			
		||||
            client.id = data.uuid;
 | 
			
		||||
            Client.clients.set(client.id, client);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "CLIENT_UPDATE_PROP":{
 | 
			
		||||
            slog("CLIENT_UPDATE_PROP");
 | 
			
		||||
            let client = Client.clients.get(data.uuid);
 | 
			
		||||
            client[data.name] = data.value;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "CLIENT_SEND_MESSAGE":{
 | 
			
		||||
            //slog("CLIENT_SEND_MESSAGE");
 | 
			
		||||
            let client = Client.clients.get(data.uuid);
 | 
			
		||||
            if(client.isProxy != true)
 | 
			
		||||
            {
 | 
			
		||||
                client.send(data.message)
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "CLIENT_DESTROY":{
 | 
			
		||||
            slog("CLIENT_DESTROY");
 | 
			
		||||
            Client.clients.delete(data.uuid);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "ROOM_CREATED":{
 | 
			
		||||
            slog("ROOM_CREATED");
 | 
			
		||||
            let room = Room.fromJSON(data.value);
 | 
			
		||||
            Room.rooms.set(room.id, room);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "ROOM_UPDATE_PROP":{
 | 
			
		||||
            slog("ROOM_UPDATE_PROP");
 | 
			
		||||
            let room = Room.rooms.get(data.uuid);
 | 
			
		||||
            room[data.name] = data.value;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "ROOM_JOIN_CLIENT":{
 | 
			
		||||
            slog("ROOM_JOIN_CLIENT");
 | 
			
		||||
            let room = Room.rooms.get(data.uuid);
 | 
			
		||||
            let client = Client.clients.get(data.client);
 | 
			
		||||
            if(room && client)
 | 
			
		||||
            {
 | 
			
		||||
                client.rooms.add(room.id);
 | 
			
		||||
                room.clients.set(client.id, client);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "ROOM_EJECT_CLIENT":{
 | 
			
		||||
            slog("ROOM_EJECT_CLIENT");
 | 
			
		||||
            let room = Room.rooms.get(data.uuid);
 | 
			
		||||
            let client = Client.clients.get(data.client);
 | 
			
		||||
            if(room && client)
 | 
			
		||||
            {
 | 
			
		||||
                client.rooms.delete(room.id);
 | 
			
		||||
                room.clients.delete(client.id, client);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case "ROOM_DESTROY":{
 | 
			
		||||
            slog("ROOM_DESTROY");
 | 
			
		||||
            Room.rooms.delete(data.value);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function CLIENT_CREATED(uuid)
 | 
			
		||||
{
 | 
			
		||||
    mlog("CLIENT_CREATED");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'CLIENT_CREATED',
 | 
			
		||||
        uuid: uuid
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
function CLIENT_UPDATE_PROP(uuid, name, value)
 | 
			
		||||
{
 | 
			
		||||
    mlog("CLIENT_UPDATE_PROP");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'CLIENT_UPDATE_PROP',
 | 
			
		||||
        uuid: uuid,
 | 
			
		||||
        name,
 | 
			
		||||
        value
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
function CLIENT_SEND_MESSAGE(uuid, message, clusterPid)
 | 
			
		||||
{
 | 
			
		||||
    mlog("CLIENT_SEND_MESSAGE");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'CLIENT_SEND_MESSAGE',
 | 
			
		||||
        uuid: uuid,
 | 
			
		||||
        message,
 | 
			
		||||
        process:clusterPid
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
function CLIENT_DESTROY(uuid)
 | 
			
		||||
{
 | 
			
		||||
    mlog("CLIENT_DESTROY");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'CLIENT_DESTROY',
 | 
			
		||||
        uuid: uuid
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function ROOM_CREATED(room)
 | 
			
		||||
{
 | 
			
		||||
    mlog("ROOM_CREATED");
 | 
			
		||||
    let raw = room.toJSON(true);
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'ROOM_CREATED',
 | 
			
		||||
        value: raw
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ROOM_UPDATE_PROP(uuid, name, value)
 | 
			
		||||
{
 | 
			
		||||
    mlog("ROOM_UPDATE_PROP");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'ROOM_UPDATE_PROP',
 | 
			
		||||
        uuid: uuid,
 | 
			
		||||
        name,
 | 
			
		||||
        value
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ROOM_JOIN_CLIENT(uuid, client)
 | 
			
		||||
{
 | 
			
		||||
    mlog("ROOM_JOIN_CLIENT");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'ROOM_JOIN_CLIENT',
 | 
			
		||||
        uuid: uuid,
 | 
			
		||||
        client
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
function ROOM_EJECT_CLIENT(uuid, client)
 | 
			
		||||
{
 | 
			
		||||
    mlog("ROOM_EJECT_CLIENT");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'ROOM_EJECT_CLIENT',
 | 
			
		||||
        uuid: uuid,
 | 
			
		||||
        client
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ROOM_DESTROY(room)
 | 
			
		||||
{
 | 
			
		||||
    mlog("ROOM_DESTROY");
 | 
			
		||||
    process.send({
 | 
			
		||||
        type:'ROOM_DESTROY',
 | 
			
		||||
        value: room.id
 | 
			
		||||
    })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function mlog(command)
 | 
			
		||||
{
 | 
			
		||||
    return;
 | 
			
		||||
    console.log("M",process.pid, command)
 | 
			
		||||
}
 | 
			
		||||
function slog(command)
 | 
			
		||||
{
 | 
			
		||||
    return;
 | 
			
		||||
    console.log("S",process.pid, command)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
exports.CLIENT_CREATED = CLIENT_CREATED;
 | 
			
		||||
exports.CLIENT_UPDATE_PROP = CLIENT_UPDATE_PROP;
 | 
			
		||||
exports.CLIENT_DESTROY = CLIENT_DESTROY;
 | 
			
		||||
exports.CLIENT_SEND_MESSAGE = CLIENT_SEND_MESSAGE;
 | 
			
		||||
exports.ROOM_CREATED = ROOM_CREATED;
 | 
			
		||||
exports.ROOM_UPDATE_PROP = ROOM_UPDATE_PROP;
 | 
			
		||||
exports.ROOM_JOIN_CLIENT = ROOM_JOIN_CLIENT;
 | 
			
		||||
exports.ROOM_EJECT_CLIENT = ROOM_EJECT_CLIENT;
 | 
			
		||||
exports.ROOM_DESTROY = ROOM_DESTROY;
 | 
			
		||||
exports.mlog = mlog;
 | 
			
		||||
exports.slog = slog;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
const { Client } = require("../Client.js");
 | 
			
		||||
const { CLIENT_UPDATE_PROP } = require("../IPC.js");
 | 
			
		||||
let {addService, addListener} = require("../WebSocket.js");
 | 
			
		||||
 | 
			
		||||
addService(({
 | 
			
		||||
| 
						 | 
				
			
			@ -13,13 +14,16 @@ addService(({
 | 
			
		|||
        case "auth/pair-system":{
 | 
			
		||||
            if(value == 'everybody')
 | 
			
		||||
            {
 | 
			
		||||
                client.requiredPair = true; 
 | 
			
		||||
                client.requiredPair = true;
 | 
			
		||||
                end({status:"success"});
 | 
			
		||||
                client.sync('requiredPair');
 | 
			
		||||
            }
 | 
			
		||||
            if(value == 'disable')
 | 
			
		||||
            {
 | 
			
		||||
                client.requiredPair = false;
 | 
			
		||||
                end({status:"success"});
 | 
			
		||||
                client.sync('requiredPair');
 | 
			
		||||
                //CLIENT_UPDATE_PROP(client.id, 'requiredPair', client.requiredPair);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +33,7 @@ addService(({
 | 
			
		|||
        }
 | 
			
		||||
        case 'auth/public':{
 | 
			
		||||
            client.requiredPair = false;
 | 
			
		||||
            client.sync('requiredPair');
 | 
			
		||||
            return end({
 | 
			
		||||
                value: 'success',
 | 
			
		||||
                mode: 'public'
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +41,7 @@ addService(({
 | 
			
		|||
        }
 | 
			
		||||
        case 'auth/private':{
 | 
			
		||||
            client.requiredPair = true;
 | 
			
		||||
            client.sync('requiredPair');
 | 
			
		||||
            return end({
 | 
			
		||||
                value: 'success',
 | 
			
		||||
                mode: 'private'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ let {addService, addListener} = require("../WebSocket.js");
 | 
			
		|||
let {
 | 
			
		||||
    randomBytes
 | 
			
		||||
} = require("node:crypto");
 | 
			
		||||
const { slog } = require("../IPC");
 | 
			
		||||
 | 
			
		||||
class APNumber{
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -11,14 +12,20 @@ class APNumber{
 | 
			
		|||
    static busyNumbers = new Map();
 | 
			
		||||
    /**
 | 
			
		||||
     * @type {number}
 | 
			
		||||
     * @param {Client} client
 | 
			
		||||
     */
 | 
			
		||||
    static lock()
 | 
			
		||||
    static lock(client)
 | 
			
		||||
    {
 | 
			
		||||
        let c = 24;
 | 
			
		||||
        while(true){
 | 
			
		||||
            if(!APNumber.busyNumbers.has(c))
 | 
			
		||||
            {
 | 
			
		||||
                APNumber.busyNumbers.set(c,true);
 | 
			
		||||
                APNumber.busyNumbers.set(c,client);
 | 
			
		||||
                process.send({
 | 
			
		||||
                    type: 'AP_NUMBER/LOCK',
 | 
			
		||||
                    uuid: client.id,
 | 
			
		||||
                    value: c
 | 
			
		||||
                })
 | 
			
		||||
                return c;
 | 
			
		||||
            }
 | 
			
		||||
            c++;
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +37,11 @@ class APNumber{
 | 
			
		|||
    static release(num)
 | 
			
		||||
    {
 | 
			
		||||
        APNumber.busyNumbers.delete(num);
 | 
			
		||||
        process.send({
 | 
			
		||||
            type: 'AP_NUMBER/RELEASE',
 | 
			
		||||
            uuid: APNumber.busyNumbers.get(num).id,
 | 
			
		||||
            value: num
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    static whois(num){
 | 
			
		||||
        return APNumber.busyNumbers.get(num)?.id;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +68,11 @@ class APShortCode{
 | 
			
		|||
            if(APShortCode.busyCodes.has(code) == false)
 | 
			
		||||
            {
 | 
			
		||||
                APShortCode.busyCodes.set(code, client);
 | 
			
		||||
                process.send({
 | 
			
		||||
                    type: 'AP_SHORTCODE/LOCK',
 | 
			
		||||
                    uuid: APShortCode.busyCodes.get(num).id,
 | 
			
		||||
                    value: code
 | 
			
		||||
                })
 | 
			
		||||
                return code;
 | 
			
		||||
            }
 | 
			
		||||
            if(!thirdLetter.end())
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +96,15 @@ class APShortCode{
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    static release(code){
 | 
			
		||||
        APShortCode.busyCodes.delete(code);
 | 
			
		||||
        if(APShortCode.busyCodes.has(code))
 | 
			
		||||
        {
 | 
			
		||||
            process.send({
 | 
			
		||||
                type: 'AP_SHORTCODE/RELEASE',
 | 
			
		||||
                uuid: APShortCode.busyCodes.get(code).id,
 | 
			
		||||
                value: code
 | 
			
		||||
            })
 | 
			
		||||
            APShortCode.busyCodes.delete(code);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    static whois(num){
 | 
			
		||||
        return APShortCode.busyCodes.get(num)?.id;
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +147,11 @@ class APIPAddress{
 | 
			
		|||
            if(APIPAddress.busyIP.has(code) == false)
 | 
			
		||||
            {
 | 
			
		||||
                APIPAddress.busyIP.set(code, client);
 | 
			
		||||
                process.send({
 | 
			
		||||
                    type: 'AP_IPADDRESS/LOCK',
 | 
			
		||||
                    uuid: APIPAddress.busyIP.get(code).id,
 | 
			
		||||
                    value: code
 | 
			
		||||
                })
 | 
			
		||||
                return code;
 | 
			
		||||
            }
 | 
			
		||||
            if(D != 255)
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +186,15 @@ class APIPAddress{
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    static release(code){
 | 
			
		||||
        APIPAddress.busyIP.delete(code);
 | 
			
		||||
        if(APIPAddress.busyIP.has(code))
 | 
			
		||||
        {
 | 
			
		||||
            process.send({
 | 
			
		||||
                type: 'AP_IPADDRESS/RELEASE',
 | 
			
		||||
                uuid: APIPAddress.busyIP.get(code).id,
 | 
			
		||||
                value: code
 | 
			
		||||
            })
 | 
			
		||||
            APIPAddress.busyIP.delete(code);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    static whois(num){
 | 
			
		||||
        return APIPAddress.busyIP.get(num)?.id;
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +205,6 @@ exports.APNumber = APNumber;
 | 
			
		|||
exports.APShortCode = APShortCode;
 | 
			
		||||
exports.APIPAddress = APIPAddress;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
addService(({
 | 
			
		||||
    client,
 | 
			
		||||
    message,
 | 
			
		||||
| 
						 | 
				
			
			@ -186,6 +223,7 @@ addService(({
 | 
			
		|||
            };
 | 
			
		||||
            let value = APIPAddress.lock(client);
 | 
			
		||||
            client.APIPAddress = value;
 | 
			
		||||
            client.sync('APIPAddress');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success",
 | 
			
		||||
                ip : value
 | 
			
		||||
| 
						 | 
				
			
			@ -201,6 +239,7 @@ addService(({
 | 
			
		|||
            };
 | 
			
		||||
            let value = APNumber.lock(client);
 | 
			
		||||
            client.APNumber = value;
 | 
			
		||||
            client.sync('APNumber');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success",
 | 
			
		||||
                number : value
 | 
			
		||||
| 
						 | 
				
			
			@ -216,6 +255,7 @@ addService(({
 | 
			
		|||
            };
 | 
			
		||||
            let value = APShortCode.lock(client);
 | 
			
		||||
            client.APShortCode = value;
 | 
			
		||||
            client.sync('APShortCode');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success",
 | 
			
		||||
                code : value
 | 
			
		||||
| 
						 | 
				
			
			@ -230,6 +270,7 @@ addService(({
 | 
			
		|||
            }
 | 
			
		||||
            APIPAddress.release(client.APIPAddress);
 | 
			
		||||
            let value = APIPAddress.lock(client);
 | 
			
		||||
            client.sync('APIPAddress');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success",
 | 
			
		||||
                ip : value
 | 
			
		||||
| 
						 | 
				
			
			@ -244,6 +285,7 @@ addService(({
 | 
			
		|||
            }
 | 
			
		||||
            APNumber.release(client.APNumber);
 | 
			
		||||
            let value = APNumber.lock(client);
 | 
			
		||||
            client.sync('APNumber');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success",
 | 
			
		||||
                number : value
 | 
			
		||||
| 
						 | 
				
			
			@ -258,6 +300,7 @@ addService(({
 | 
			
		|||
            }
 | 
			
		||||
            APShortCode.release(client.APShortCode);
 | 
			
		||||
            let value = APShortCode.lock(client);
 | 
			
		||||
            client.sync('APShortCode');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success",
 | 
			
		||||
                code : value
 | 
			
		||||
| 
						 | 
				
			
			@ -266,6 +309,8 @@ addService(({
 | 
			
		|||
        }
 | 
			
		||||
        case "release/APIPAddress":{
 | 
			
		||||
            APIPAddress.release(client.APIPAddress);
 | 
			
		||||
            client.APIPAddress = void 0;
 | 
			
		||||
            client.sync('APShortCode');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success"
 | 
			
		||||
            })
 | 
			
		||||
| 
						 | 
				
			
			@ -273,6 +318,8 @@ addService(({
 | 
			
		|||
        }
 | 
			
		||||
        case "release/APNumber":{
 | 
			
		||||
            APNumber.release(client.APNumber);
 | 
			
		||||
            client.APNumber = void 0;
 | 
			
		||||
            client.sync('APIPAddress');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success"
 | 
			
		||||
            })
 | 
			
		||||
| 
						 | 
				
			
			@ -280,6 +327,8 @@ addService(({
 | 
			
		|||
        }
 | 
			
		||||
        case "release/APShortCode":{
 | 
			
		||||
            APShortCode.release(client.APShortCode);
 | 
			
		||||
            client.APShortCode = void 0;
 | 
			
		||||
            client.sync('APIPAddress');
 | 
			
		||||
            end({
 | 
			
		||||
                status : "success"
 | 
			
		||||
            })
 | 
			
		||||
| 
						 | 
				
			
			@ -333,6 +382,72 @@ addService(({
 | 
			
		|||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
process.on('message',({type, uuid, value}) => {
 | 
			
		||||
    switch(type)
 | 
			
		||||
    {
 | 
			
		||||
        case "AP_NUMBER/LOCK":{
 | 
			
		||||
            console.log("S",process.pid, 'IPPressure SYNCED')
 | 
			
		||||
            let client = Client.clients.get(uuid);
 | 
			
		||||
            APNumber.busyNumbers.set(value, client);
 | 
			
		||||
            if(client)
 | 
			
		||||
            {
 | 
			
		||||
                client.APNumber = value;
 | 
			
		||||
                client.sync('APNumber');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        case "AP_NUMBER/RELEASE":{
 | 
			
		||||
            console.log("S",process.pid, 'IPPressure SYNCED')
 | 
			
		||||
            APNumber.busyNumbers.delete(value);
 | 
			
		||||
            let client = Client.clients.get(uuid);
 | 
			
		||||
            if(client)
 | 
			
		||||
            {
 | 
			
		||||
                client.APNumber = void 0;
 | 
			
		||||
                client.sync('APNumber');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        case "AP_SHORTCODE/LOCK":{
 | 
			
		||||
            console.log("S",process.pid, 'IPPressure SYNCED')
 | 
			
		||||
            let client = Client.clients.get(uuid);
 | 
			
		||||
            APShortCode.busyCodes.set(value, client);
 | 
			
		||||
            if(client)
 | 
			
		||||
            {
 | 
			
		||||
                client.APShortCode = value;
 | 
			
		||||
                client.sync('APShortCode');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        case "AP_SHORTCODE/RELEASE":{
 | 
			
		||||
            console.log("S",process.pid, 'IPPressure SYNCED')
 | 
			
		||||
            APShortCode.busyCodes.delete(value);
 | 
			
		||||
            let client = Client.clients.get(uuid);
 | 
			
		||||
            if(client)
 | 
			
		||||
            {
 | 
			
		||||
                client.APShortCode = void 0;
 | 
			
		||||
                client.sync('APShortCode');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        case "AP_IPADDRESS/LOCK":{
 | 
			
		||||
            console.log("S",process.pid, 'IPPressure SYNCED')
 | 
			
		||||
            let client = Client.clients.get(uuid);
 | 
			
		||||
            APIPAddress.busyIP.set(value, client);
 | 
			
		||||
            if(client)
 | 
			
		||||
            {
 | 
			
		||||
                client.APIPAddress = value;
 | 
			
		||||
                client.sync('APIPAddress');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        case "AP_IPADDRESS/RELEASE":{
 | 
			
		||||
            console.log("S",process.pid, 'IPPressure SYNCED')
 | 
			
		||||
            APIPAddress.busyIP.delete(value);
 | 
			
		||||
            let client = Client.clients.get(uuid);
 | 
			
		||||
            if(client)
 | 
			
		||||
            {
 | 
			
		||||
                client.APIPAddress = void 0;
 | 
			
		||||
                client.sync('APIPAddress');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
addListener('disconnect',(global, client)=>{
 | 
			
		||||
    if(client.APIPAddress != 0)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ let {randomUUID,createHash} = require("crypto");
 | 
			
		|||
const joi = require("joi");
 | 
			
		||||
let {addService,addListener} = require("../WebSocket.js");
 | 
			
		||||
const { termoutput } = require("../config.js");
 | 
			
		||||
const { ROOM_CREATED, ROOM_DESTROY, ROOM_UPDATE_PROP, ROOM_JOIN_CLIENT, ROOM_EJECT_CLIENT } = require("../IPC.js");
 | 
			
		||||
let term = require("terminal-kit").terminal;
 | 
			
		||||
 | 
			
		||||
function Sha256(update)
 | 
			
		||||
| 
						 | 
				
			
			@ -64,15 +65,24 @@ function Room()
 | 
			
		|||
     * @type {string[]}
 | 
			
		||||
     */
 | 
			
		||||
    this.waitingInvited = new Set();
 | 
			
		||||
 | 
			
		||||
    this.sync = function(...args){
 | 
			
		||||
        process.nextTick(()=>{
 | 
			
		||||
            for (const name of args) {
 | 
			
		||||
                ROOM_UPDATE_PROP(this.id, name, this[name]);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Room} room 
 | 
			
		||||
 */
 | 
			
		||||
Room.prototype.publish = function(room){
 | 
			
		||||
    Room.rooms.set(this.id, this);
 | 
			
		||||
    ROOM_CREATED(this);
 | 
			
		||||
    termoutput && term.green("Room Published ").white(this.name," in ").yellow(this.clients.size).white(" clients")('\n');
 | 
			
		||||
};
 | 
			
		||||
Room.prototype.toJSON = function(){
 | 
			
		||||
Room.prototype.toJSON = function(detailed){
 | 
			
		||||
    let obj = {};
 | 
			
		||||
    obj.id = this.id;
 | 
			
		||||
    obj.accessType = this.accessType;
 | 
			
		||||
| 
						 | 
				
			
			@ -82,8 +92,47 @@ Room.prototype.toJSON = function(){
 | 
			
		|||
    obj.name = this.name;
 | 
			
		||||
    obj.owner = this.owner.id;
 | 
			
		||||
    obj.waitingInvited = [...this.waitingInvited];
 | 
			
		||||
    if(detailed)
 | 
			
		||||
    {
 | 
			
		||||
        obj.credential = this.credential;
 | 
			
		||||
        obj.notifyActionInvite = this.notifyActionInvite;
 | 
			
		||||
        obj.notifyActionJoined = this.notifyActionJoined;
 | 
			
		||||
        obj.notifyActionEjected = this.notifyActionEjected;
 | 
			
		||||
        obj.clients = [...this.clients.keys()];
 | 
			
		||||
    }
 | 
			
		||||
    return obj;
 | 
			
		||||
};
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Object} data
 | 
			
		||||
 * @param {Room} room
 | 
			
		||||
 */
 | 
			
		||||
Room.fromJSON = function(data, room){
 | 
			
		||||
    room = room || new Room();
 | 
			
		||||
    let obj = {};
 | 
			
		||||
    room.id = data.id;
 | 
			
		||||
    room.accessType = data.accessType;
 | 
			
		||||
    room.createdAt = data.createdAt;
 | 
			
		||||
    room.description = data.description;
 | 
			
		||||
    room.joinType = data.joinType;
 | 
			
		||||
    room.name = data.name;
 | 
			
		||||
    if(data.owner && Client.clients.has(data.owner))
 | 
			
		||||
    {
 | 
			
		||||
        room.owner = Client.clients.get(data.owner);
 | 
			
		||||
    }
 | 
			
		||||
    room.waitingInvited = new Set(data.waitingInvited);
 | 
			
		||||
    obj.credential = data.credential;
 | 
			
		||||
    obj.notifyActionInvite = data.notifyActionInvite;
 | 
			
		||||
    obj.notifyActionJoined = data.notifyActionJoined;
 | 
			
		||||
    obj.notifyActionEjected = data.notifyActionEjected;
 | 
			
		||||
    obj.clients = new Map(
 | 
			
		||||
        data.clients.map(e => ([
 | 
			
		||||
                e,                          // map key
 | 
			
		||||
                Client.clients.get(e)       // map value
 | 
			
		||||
            ])
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    return room;
 | 
			
		||||
};
 | 
			
		||||
Room.prototype.send = function(obj, withOut){
 | 
			
		||||
    for (const client of this.clients.values()) {
 | 
			
		||||
        if(client.id != withOut)
 | 
			
		||||
| 
						 | 
				
			
			@ -107,6 +156,7 @@ Room.prototype.join = function(client){
 | 
			
		|||
    };
 | 
			
		||||
    client.rooms.add(this.id);
 | 
			
		||||
    this.clients.set(client.id, client);
 | 
			
		||||
    ROOM_JOIN_CLIENT(this.id, client.id);
 | 
			
		||||
    termoutput && term.green("Client Room joined ").white(this.name," in ").yellow(this.clients.size  + "").white(" clients")('\n');
 | 
			
		||||
};
 | 
			
		||||
Room.prototype.down = function(){
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +166,7 @@ Room.prototype.down = function(){
 | 
			
		|||
        ownerid: this.owner.id
 | 
			
		||||
    },'room/closed']);
 | 
			
		||||
    Room.rooms.delete(this.id);
 | 
			
		||||
    ROOM_DESTROY(this)
 | 
			
		||||
};
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Client} client 
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +182,7 @@ Room.prototype.eject = function(client){
 | 
			
		|||
    }
 | 
			
		||||
    client.rooms.delete(this.id);
 | 
			
		||||
    this.clients.delete(client.id);
 | 
			
		||||
    ROOM_EJECT_CLIENT(this.id, client.id);
 | 
			
		||||
 | 
			
		||||
    if(this.clients.size == 0)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -154,8 +206,8 @@ addListener('connect',(global, client)=>{
 | 
			
		|||
    room.id = client.id;
 | 
			
		||||
    room.name = "Your Room | " + client.id;
 | 
			
		||||
    room.owner = client;
 | 
			
		||||
    room.join(client);
 | 
			
		||||
    room.publish();
 | 
			
		||||
    room.join(client);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
addListener('disconnect',(global, client)=>{
 | 
			
		||||
| 
						 | 
				
			
			@ -296,8 +348,8 @@ addService(({
 | 
			
		|||
                {
 | 
			
		||||
                    room.credential = Sha256(message.credential + "");
 | 
			
		||||
                }
 | 
			
		||||
                room.join(client);
 | 
			
		||||
                room.publish();
 | 
			
		||||
                room.join(client);
 | 
			
		||||
                end({
 | 
			
		||||
                    status: "success",
 | 
			
		||||
                    room: room.toJSON()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@ let {http} = require("./HTTPServer");
 | 
			
		|||
let {randomUUID} = require("crypto");
 | 
			
		||||
const { Client } = require("./Client.js");
 | 
			
		||||
const { termoutput } = require("./config");
 | 
			
		||||
const { CLIENT_CREATED, CLIENT_DESTROY } = require("./IPC");
 | 
			
		||||
const stats = require("./stats");
 | 
			
		||||
termoutput && console.log("Web Socket Protocol is ready");
 | 
			
		||||
 | 
			
		||||
http.addListener("upgrade",() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -15,11 +17,22 @@ let wsServer = new websocket.server({
 | 
			
		|||
    httpServer: http,
 | 
			
		||||
    autoAcceptConnections: true
 | 
			
		||||
});
 | 
			
		||||
/*
 | 
			
		||||
process.send({
 | 
			
		||||
    core: "writestat",
 | 
			
		||||
    writeBytes:0,
 | 
			
		||||
    readBytes:0,
 | 
			
		||||
    totalBytes:0,
 | 
			
		||||
    recaivedPacket:0,
 | 
			
		||||
    sendedPacket:0,
 | 
			
		||||
    totalPacket:0
 | 
			
		||||
})*/
 | 
			
		||||
 | 
			
		||||
let global = new Map();
 | 
			
		||||
let clients = new Map();
 | 
			
		||||
wsServer.addListener("connect",(socket) => {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
wsServer.addListener("connect",(socket) => {
 | 
			
		||||
    let xClient = new Client();
 | 
			
		||||
    let id = randomUUID();
 | 
			
		||||
    socket.id = id;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,12 +42,34 @@ wsServer.addListener("connect",(socket) => {
 | 
			
		|||
    Client.clients.set(id, xClient);
 | 
			
		||||
    clients.set(id, xClient);
 | 
			
		||||
 | 
			
		||||
    console.log("Client:", id,"on worker pid:",process.pid)
 | 
			
		||||
 | 
			
		||||
    CLIENT_CREATED(id);
 | 
			
		||||
 | 
			
		||||
    emit("connect", global, xClient);
 | 
			
		||||
 | 
			
		||||
    let oldw = 0, oldr = 0;
 | 
			
		||||
    let timer = setInterval(()=>{
 | 
			
		||||
        let writed = socket.socket.bytesRead - oldr;
 | 
			
		||||
        let readed = socket.socket.bytesWritten - oldw;
 | 
			
		||||
        stats.ws_total_bytes += (writed + readed);
 | 
			
		||||
        stats.ws_readed_bytes += readed;
 | 
			
		||||
        stats.ws_writed_bytes += writed;
 | 
			
		||||
        oldr = socket.socket.bytesRead;
 | 
			
		||||
        oldw = socket.socket.bytesWritten;
 | 
			
		||||
    }, 1000)
 | 
			
		||||
 | 
			
		||||
    socket.addListener("close",()=>{
 | 
			
		||||
        emit("disconnect",  global, xClient);
 | 
			
		||||
        CLIENT_DESTROY(id);
 | 
			
		||||
        Client.clients.set(id, xClient);
 | 
			
		||||
        clearInterval(timer);
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    socket.addListener("message",({type,utf8Data}) => {
 | 
			
		||||
        stats.ws_recaived_packs++;
 | 
			
		||||
        stats.ws_total_packs++;
 | 
			
		||||
 | 
			
		||||
        if(type == "utf8")
 | 
			
		||||
        {
 | 
			
		||||
            let json;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
const { mlog } = require("./IPC");
 | 
			
		||||
 | 
			
		||||
exports.ws_writed_bytes = 0;
 | 
			
		||||
exports.ws_readed_bytes = 0;
 | 
			
		||||
exports.ws_total_bytes = 0;
 | 
			
		||||
exports.ws_sended_packs = 0;
 | 
			
		||||
exports.ws_recaived_packs = 0;
 | 
			
		||||
exports.ws_total_packs = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
process.send({
 | 
			
		||||
    core: "writestat",
 | 
			
		||||
    ws_writed_bytes: exports.ws_writed_bytes,
 | 
			
		||||
    ws_readed_bytes: exports.ws_readed_bytes,
 | 
			
		||||
    ws_total_bytes: exports.ws_total_bytes,
 | 
			
		||||
    ws_sended_packs: exports.ws_sended_packs,
 | 
			
		||||
    ws_recaived_packs: exports.ws_recaived_packs,
 | 
			
		||||
    ws_total_packs: exports.ws_total_packs
 | 
			
		||||
});
 | 
			
		||||
setInterval(()=>{
 | 
			
		||||
    process.send({
 | 
			
		||||
        core: "writestat",
 | 
			
		||||
        ws_writed_bytes: exports.ws_writed_bytes,
 | 
			
		||||
        ws_readed_bytes: exports.ws_readed_bytes,
 | 
			
		||||
        ws_total_bytes: exports.ws_total_bytes,
 | 
			
		||||
        ws_sended_packs: exports.ws_sended_packs,
 | 
			
		||||
        ws_recaived_packs: exports.ws_recaived_packs,
 | 
			
		||||
        ws_total_packs: exports.ws_total_packs
 | 
			
		||||
    })
 | 
			
		||||
    mlog(`writed ${exports.ws_writed_bytes} bytes, readed ${exports.ws_readed_bytes} bytes`);
 | 
			
		||||
    exports.ws_writed_bytes = 0;
 | 
			
		||||
    exports.ws_readed_bytes = 0;
 | 
			
		||||
    exports.ws_total_bytes = 0;
 | 
			
		||||
    exports.ws_sended_packs = 0;
 | 
			
		||||
    exports.ws_recaived_packs = 0;
 | 
			
		||||
    exports.ws_total_packs = 0;
 | 
			
		||||
    process.send({
 | 
			
		||||
        core: "readstat",
 | 
			
		||||
        ws_writed_bytes: exports.ws_writed_bytes,
 | 
			
		||||
        ws_readed_bytes: exports.ws_readed_bytes,
 | 
			
		||||
        ws_total_bytes: exports.ws_total_bytes,
 | 
			
		||||
        ws_sended_packs: exports.ws_sended_packs,
 | 
			
		||||
        ws_recaived_packs: exports.ws_recaived_packs,
 | 
			
		||||
        ws_total_packs: exports.ws_total_packs
 | 
			
		||||
    })
 | 
			
		||||
}, 3000)
 | 
			
		||||
 | 
			
		||||
process.on('message', stat => {
 | 
			
		||||
    if(stat.type == ':stats:')
 | 
			
		||||
    {
 | 
			
		||||
        exports.others = stat.data;
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
/** @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
 | 
			
		||||
                                    }
 | 
			
		||||
                                })
 | 
			
		||||
                            })
 | 
			
		||||
                            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);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,678 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html lang="tr">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Network meter</title>
 | 
			
		||||
</head>
 | 
			
		||||
<body style="background-color: #333333;">
 | 
			
		||||
    <div id="container">
 | 
			
		||||
        <div class="speed-container">
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <style>
 | 
			
		||||
        html,body,#container{
 | 
			
		||||
            height: 100%;
 | 
			
		||||
            margin: 0;
 | 
			
		||||
        }
 | 
			
		||||
        #container{
 | 
			
		||||
            display: flex;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container{
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: row;
 | 
			
		||||
            max-width: 1200px;
 | 
			
		||||
            flex-wrap: wrap;
 | 
			
		||||
            margin: auto;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div{
 | 
			
		||||
            flex: 1 1 25%;
 | 
			
		||||
            max-width: 100%;
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            margin-bottom: 50px;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div canvas{
 | 
			
		||||
            max-width: 100%;
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div .text{
 | 
			
		||||
            display: flex;
 | 
			
		||||
            color: white;
 | 
			
		||||
            vertical-align: middle;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div .text > .text1{
 | 
			
		||||
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
 | 
			
		||||
            font-size: 2em;
 | 
			
		||||
            text-align: center;
 | 
			
		||||
            vertical-align: middle;
 | 
			
		||||
            flex: 1;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            justify-content: center;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div .text > .text2{
 | 
			
		||||
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
 | 
			
		||||
            font-size: 2em;
 | 
			
		||||
            text-align: center;
 | 
			
		||||
            vertical-align: middle;
 | 
			
		||||
            flex: 1;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            justify-content: center;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div .text1::after{
 | 
			
		||||
            content:' FLOW';
 | 
			
		||||
            font-size: 0.4em;
 | 
			
		||||
            margin: auto 0 auto 5px;
 | 
			
		||||
        }
 | 
			
		||||
        .speed-container > div .text2::after{
 | 
			
		||||
            content:' PRESSURE';
 | 
			
		||||
            font-size: 0.4em;
 | 
			
		||||
            margin: auto 0 auto 5px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script>
 | 
			
		||||
        function CreateMeter()
 | 
			
		||||
        {
 | 
			
		||||
            var iCurrentSpeed = 0,
 | 
			
		||||
            iTargetSpeed = 0,
 | 
			
		||||
            bDecrement = null,
 | 
			
		||||
            job = null;
 | 
			
		||||
 | 
			
		||||
            function degToRad(angle) {
 | 
			
		||||
                // Degrees to radians
 | 
			
		||||
                return ((angle * Math.PI) / 180);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function radToDeg(angle) {
 | 
			
		||||
                // Radians to degree
 | 
			
		||||
                return ((angle * 180) / Math.PI);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawLine(options, line) {
 | 
			
		||||
                // Draw a line using the line object passed in
 | 
			
		||||
                options.ctx.beginPath();
 | 
			
		||||
 | 
			
		||||
                // Set attributes of open
 | 
			
		||||
                options.ctx.globalAlpha = line.alpha;
 | 
			
		||||
                options.ctx.lineWidth = line.lineWidth;
 | 
			
		||||
                options.ctx.fillStyle = line.fillStyle;
 | 
			
		||||
                options.ctx.strokeStyle = line.fillStyle;
 | 
			
		||||
                options.ctx.moveTo(line.from.X,
 | 
			
		||||
                    line.from.Y);
 | 
			
		||||
 | 
			
		||||
                // Plot the line
 | 
			
		||||
                options.ctx.lineTo(
 | 
			
		||||
                    line.to.X,
 | 
			
		||||
                    line.to.Y
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                options.ctx.stroke();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function createLine(fromX, fromY, toX, toY, fillStyle, lineWidth, alpha) {
 | 
			
		||||
                // Create a line object using Javascript object notation
 | 
			
		||||
                return {
 | 
			
		||||
                    from: {
 | 
			
		||||
                        X: fromX,
 | 
			
		||||
                        Y: fromY
 | 
			
		||||
                    },
 | 
			
		||||
                    to:    {
 | 
			
		||||
                        X: toX,
 | 
			
		||||
                        Y: toY
 | 
			
		||||
                    },
 | 
			
		||||
                    fillStyle: fillStyle,
 | 
			
		||||
                    lineWidth: lineWidth,
 | 
			
		||||
                    alpha: alpha
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawOuterMetallicArc(options) {
 | 
			
		||||
                /* Draw the metallic border of the speedometer
 | 
			
		||||
                * Outer grey area
 | 
			
		||||
                */
 | 
			
		||||
                options.ctx.beginPath();
 | 
			
		||||
 | 
			
		||||
                // Nice shade of grey
 | 
			
		||||
                options.ctx.fillStyle = "rgb(127,127,127)";
 | 
			
		||||
 | 
			
		||||
                // Draw the outer circle
 | 
			
		||||
                options.ctx.arc(options.center.X,
 | 
			
		||||
                    options.center.Y,
 | 
			
		||||
                    options.radius,
 | 
			
		||||
                    0,
 | 
			
		||||
                    Math.PI,
 | 
			
		||||
                    true);
 | 
			
		||||
 | 
			
		||||
                // Fill the last object
 | 
			
		||||
                options.ctx.fill();
 | 
			
		||||
        /* */
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawInnerMetallicArc(options) {
 | 
			
		||||
                /* Draw the metallic border of the speedometer
 | 
			
		||||
                * Inner white area
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                options.ctx.beginPath();
 | 
			
		||||
 | 
			
		||||
                // White
 | 
			
		||||
                options.ctx.fillStyle = "rgb(255,255,255)";
 | 
			
		||||
 | 
			
		||||
                // Outer circle (subtle edge in the grey)
 | 
			
		||||
                options.ctx.arc(options.center.X,
 | 
			
		||||
                                options.center.Y,
 | 
			
		||||
                                (options.radius / 100) * 90,
 | 
			
		||||
                                0,
 | 
			
		||||
                                Math.PI,
 | 
			
		||||
                                true);
 | 
			
		||||
 | 
			
		||||
                options.ctx.fill();
 | 
			
		||||
                
 | 
			
		||||
            /* */
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawMetallicArc(options) {
 | 
			
		||||
                /* Draw the metallic border of the speedometer
 | 
			
		||||
                * by drawing two semi-circles, one over lapping
 | 
			
		||||
                * the other with a bot of alpha transparency
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                drawOuterMetallicArc(options);
 | 
			
		||||
                drawInnerMetallicArc(options);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawBackground(options) {
 | 
			
		||||
                /* Black background with alphs transparency to
 | 
			
		||||
                * blend the edges of the metallic edge and
 | 
			
		||||
                * black background
 | 
			
		||||
                */
 | 
			
		||||
            var i = 0;
 | 
			
		||||
 | 
			
		||||
                options.ctx.globalAlpha = 0.2;
 | 
			
		||||
                options.ctx.fillStyle = "rgb(0,0,0)";
 | 
			
		||||
 | 
			
		||||
                // Draw semi-transparent circles
 | 
			
		||||
                for (i = 170; i < 180; i++) {
 | 
			
		||||
                    options.ctx.beginPath();
 | 
			
		||||
 | 
			
		||||
                    options.ctx.arc(options.center.X,
 | 
			
		||||
                        options.center.Y,
 | 
			
		||||
                        i,
 | 
			
		||||
                        0,
 | 
			
		||||
                        Math.PI,
 | 
			
		||||
                        true);
 | 
			
		||||
 | 
			
		||||
                    options.ctx.fill();
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function applyDefaultContextSettings(options) {
 | 
			
		||||
                /* Helper function to revert to gauges
 | 
			
		||||
                * default settings
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                options.ctx.lineWidth = 2;
 | 
			
		||||
                options.ctx.globalAlpha = 0.5;
 | 
			
		||||
                options.ctx.strokeStyle = "rgb(255, 255, 255)";
 | 
			
		||||
                options.ctx.fillStyle = 'rgb(255,255,255)';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawSmallTickMarks(options) {
 | 
			
		||||
                /* The small tick marks against the coloured
 | 
			
		||||
                * arc drawn every 5 mph from 10 degrees to
 | 
			
		||||
                * 170 degrees.
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                var tickvalue = options.levelRadius - 8,
 | 
			
		||||
                    iTick = 0,
 | 
			
		||||
                    gaugeOptions = options.gaugeOptions,
 | 
			
		||||
                    iTickRad = 0,
 | 
			
		||||
                    onArchX,
 | 
			
		||||
                    onArchY,
 | 
			
		||||
                    innerTickX,
 | 
			
		||||
                    innerTickY,
 | 
			
		||||
                    fromX,
 | 
			
		||||
                    fromY,
 | 
			
		||||
                    line,
 | 
			
		||||
                    toX,
 | 
			
		||||
                    toY;
 | 
			
		||||
 | 
			
		||||
                applyDefaultContextSettings(options);
 | 
			
		||||
 | 
			
		||||
                // Tick every 20 degrees (small ticks)
 | 
			
		||||
                for (iTick = 10; iTick < 180; iTick += 10) {
 | 
			
		||||
 | 
			
		||||
                    iTickRad = degToRad(iTick);
 | 
			
		||||
 | 
			
		||||
                    /* Calculate the X and Y of both ends of the
 | 
			
		||||
                    * line I need to draw at angle represented at Tick.
 | 
			
		||||
                    * The aim is to draw the a line starting on the
 | 
			
		||||
                    * coloured arc and continueing towards the outer edge
 | 
			
		||||
                    * in the direction from the center of the gauge.
 | 
			
		||||
                    */
 | 
			
		||||
 | 
			
		||||
                    onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue);
 | 
			
		||||
                    onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue);
 | 
			
		||||
                    innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius);
 | 
			
		||||
                    innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius);
 | 
			
		||||
 | 
			
		||||
                    fromX = (options.center.X - gaugeOptions.radius) + onArchX;
 | 
			
		||||
                    fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY;
 | 
			
		||||
                    toX = (options.center.X - gaugeOptions.radius) + innerTickX;
 | 
			
		||||
                    toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY;
 | 
			
		||||
 | 
			
		||||
                    // Create a line expressed in JSON
 | 
			
		||||
                    line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6);
 | 
			
		||||
 | 
			
		||||
                    // Draw the line
 | 
			
		||||
                    drawLine(options, line);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawLargeTickMarks(options) {
 | 
			
		||||
                /* The large tick marks against the coloured
 | 
			
		||||
                * arc drawn every 10 mph from 10 degrees to
 | 
			
		||||
                * 170 degrees.
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                var tickvalue = options.levelRadius - 8,
 | 
			
		||||
                    iTick = 0,
 | 
			
		||||
                    gaugeOptions = options.gaugeOptions,
 | 
			
		||||
                    iTickRad = 0,
 | 
			
		||||
                    innerTickY,
 | 
			
		||||
                    innerTickX,
 | 
			
		||||
                    onArchX,
 | 
			
		||||
                    onArchY,
 | 
			
		||||
                    fromX,
 | 
			
		||||
                    fromY,
 | 
			
		||||
                    toX,
 | 
			
		||||
                    toY,
 | 
			
		||||
                    line;
 | 
			
		||||
 | 
			
		||||
                applyDefaultContextSettings(options);
 | 
			
		||||
 | 
			
		||||
                tickvalue = options.levelRadius - 2;
 | 
			
		||||
 | 
			
		||||
                // 10 units (major ticks)
 | 
			
		||||
                for (iTick = 20; iTick < 180; iTick += 20) {
 | 
			
		||||
 | 
			
		||||
                    iTickRad = degToRad(iTick);
 | 
			
		||||
 | 
			
		||||
                    /* Calculate the X and Y of both ends of the
 | 
			
		||||
                    * line I need to draw at angle represented at Tick.
 | 
			
		||||
                    * The aim is to draw the a line starting on the
 | 
			
		||||
                    * coloured arc and continueing towards the outer edge
 | 
			
		||||
                    * in the direction from the center of the gauge.
 | 
			
		||||
                    */
 | 
			
		||||
 | 
			
		||||
                    onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue);
 | 
			
		||||
                    onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue);
 | 
			
		||||
                    innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius);
 | 
			
		||||
                    innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius);
 | 
			
		||||
 | 
			
		||||
                    fromX = (options.center.X - gaugeOptions.radius) + onArchX;
 | 
			
		||||
                    fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY;
 | 
			
		||||
                    toX = (options.center.X - gaugeOptions.radius) + innerTickX;
 | 
			
		||||
                    toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY;
 | 
			
		||||
 | 
			
		||||
                    // Create a line expressed in JSON
 | 
			
		||||
                    line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6);
 | 
			
		||||
 | 
			
		||||
                    // Draw the line
 | 
			
		||||
                    drawLine(options, line);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawTicks(options) {
 | 
			
		||||
                /* Two tick in the coloured arc!
 | 
			
		||||
                * Small ticks every 5
 | 
			
		||||
                * Large ticks every 10
 | 
			
		||||
                */
 | 
			
		||||
                drawSmallTickMarks(options);
 | 
			
		||||
                drawLargeTickMarks(options);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawTextMarkers(options) {
 | 
			
		||||
                /* The text labels marks above the coloured
 | 
			
		||||
                * arc drawn every 10 mph from 10 degrees to
 | 
			
		||||
                * 170 degrees.
 | 
			
		||||
                */
 | 
			
		||||
                var innerTickX = 0,
 | 
			
		||||
                    innerTickY = 0,
 | 
			
		||||
                    iTick = 0,
 | 
			
		||||
                    gaugeOptions = options.gaugeOptions,
 | 
			
		||||
                    iTickToPrint = 00;
 | 
			
		||||
 | 
			
		||||
                applyDefaultContextSettings(options);
 | 
			
		||||
 | 
			
		||||
                // Font styling
 | 
			
		||||
                options.ctx.font = 'italic 10px sans-serif';
 | 
			
		||||
                options.ctx.textBaseline = 'top';
 | 
			
		||||
 | 
			
		||||
                options.ctx.beginPath();
 | 
			
		||||
 | 
			
		||||
                // Tick every 20 (small ticks)
 | 
			
		||||
                for (iTick = 10; iTick < 160; iTick += 20) {
 | 
			
		||||
 | 
			
		||||
                    innerTickX = gaugeOptions.radius - (Math.cos(degToRad(iTick)) * gaugeOptions.radius);
 | 
			
		||||
                    innerTickY = gaugeOptions.radius - (Math.sin(degToRad(iTick)) * gaugeOptions.radius);
 | 
			
		||||
 | 
			
		||||
                    // Some cludging to center the values (TODO: Improve)
 | 
			
		||||
                    if (iTick <= 10) {
 | 
			
		||||
                        options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX,
 | 
			
		||||
                                (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
 | 
			
		||||
                    } else if (iTick < 50) {
 | 
			
		||||
                        options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX - 5,
 | 
			
		||||
                                (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
 | 
			
		||||
                    } else if (iTick < 90) {
 | 
			
		||||
                        options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX,
 | 
			
		||||
                                (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
 | 
			
		||||
                    } else if (iTick === 90) {
 | 
			
		||||
                        options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 4,
 | 
			
		||||
                                (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
 | 
			
		||||
                    } else if (iTick < 145) {
 | 
			
		||||
                        options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 10,
 | 
			
		||||
                                (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 15,
 | 
			
		||||
                                (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // MPH increase by 10 every 20 degrees
 | 
			
		||||
                    //iTickToPrint += Math.round(2160 / 9);
 | 
			
		||||
                    iTickToPrint += 30;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                options.ctx.stroke();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawSpeedometerPart(options, alphaValue, strokeStyle, startPos) {
 | 
			
		||||
                /* Draw part of the arc that represents
 | 
			
		||||
                * the colour speedometer arc
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                options.ctx.beginPath();
 | 
			
		||||
 | 
			
		||||
                options.ctx.globalAlpha = alphaValue;
 | 
			
		||||
                options.ctx.lineWidth = 5;
 | 
			
		||||
                options.ctx.strokeStyle = strokeStyle;
 | 
			
		||||
 | 
			
		||||
                options.ctx.arc(options.center.X,
 | 
			
		||||
                    options.center.Y,
 | 
			
		||||
                    options.levelRadius,
 | 
			
		||||
                    Math.PI + (Math.PI / 360 * startPos),
 | 
			
		||||
                    0 - (Math.PI / 360 * 10),
 | 
			
		||||
                    false);
 | 
			
		||||
 | 
			
		||||
                options.ctx.stroke();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawSpeedometerColourArc(options) {
 | 
			
		||||
                /* Draws the colour arc.  Three different colours
 | 
			
		||||
                * used here; thus, same arc drawn 3 times with
 | 
			
		||||
                * different colours.
 | 
			
		||||
                * TODO: Gradient possible?
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                drawSpeedometerPart(options, 1.0, "rgb(255,255,255)", 10);
 | 
			
		||||
                drawSpeedometerPart(options, 0.9, "rgb(0,255,0)", 80);
 | 
			
		||||
                drawSpeedometerPart(options, 0.9, "rgb(255,128,0)", 250);
 | 
			
		||||
                drawSpeedometerPart(options, 0.9, "rgb(255,0,0)", 300);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function drawNeedleDial(options, alphaValue, strokeStyle, fillStyle) {
 | 
			
		||||
                /* Draws the metallic dial that covers the base of the
 | 
			
		||||
                * needle.
 | 
			
		||||
                */
 | 
			
		||||
                var i = 0;
 | 
			
		||||
 | 
			
		||||
                options.ctx.globalAlpha = alphaValue;
 | 
			
		||||
                options.ctx.lineWidth = 3;
 | 
			
		||||
                options.ctx.strokeStyle = strokeStyle;
 | 
			
		||||
                options.ctx.fillStyle = fillStyle;
 | 
			
		||||
 | 
			
		||||
                // Draw several transparent circles with alpha
 | 
			
		||||
                for (i = 0; i < 30; i++) {
 | 
			
		||||
 | 
			
		||||
                    options.ctx.beginPath();
 | 
			
		||||
                    options.ctx.arc(options.center.X,
 | 
			
		||||
                        options.center.Y,
 | 
			
		||||
                        i,
 | 
			
		||||
                        0,
 | 
			
		||||
                        Math.PI,
 | 
			
		||||
                        true);
 | 
			
		||||
 | 
			
		||||
                    options.ctx.fill();
 | 
			
		||||
                    options.ctx.stroke();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            function drawNeedle(options) {
 | 
			
		||||
                /* Draw the needle in a nice read colour at the
 | 
			
		||||
                * angle that represents the options.speed value.
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                var iSpeedAsAngle = convertSpeedToAngle(options),
 | 
			
		||||
                    iSpeedAsAngleRad = degToRad(iSpeedAsAngle),
 | 
			
		||||
                    gaugeOptions = options.gaugeOptions,
 | 
			
		||||
                    innerTickX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * 20),
 | 
			
		||||
                    innerTickY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * 20),
 | 
			
		||||
                    fromX = (options.center.X - gaugeOptions.radius) + innerTickX,
 | 
			
		||||
                    fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY,
 | 
			
		||||
                    endNeedleX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * gaugeOptions.radius),
 | 
			
		||||
                    endNeedleY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * gaugeOptions.radius),
 | 
			
		||||
                    toX = (options.center.X - gaugeOptions.radius) + endNeedleX,
 | 
			
		||||
                    toY = (gaugeOptions.center.Y - gaugeOptions.radius) + endNeedleY,
 | 
			
		||||
                    line = createLine(fromX, fromY, toX, toY, "rgb(255, 0, 0)", 5, 0.6);
 | 
			
		||||
 | 
			
		||||
                drawLine(options, line);
 | 
			
		||||
 | 
			
		||||
                // Two circle to draw the dial at the base (give its a nice effect?)
 | 
			
		||||
                drawNeedleDial(options, 0.6, "rgb(127, 127, 127)", "rgb(255,255,255)");
 | 
			
		||||
                drawNeedleDial(options, 0.2, "rgb(127, 127, 127)", "rgb(127,127,127)");
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function buildOptionsAsJSON(canvas, iSpeed) {
 | 
			
		||||
                /* Setting for the speedometer
 | 
			
		||||
                * Alter these to modify its look and feel
 | 
			
		||||
                */
 | 
			
		||||
 | 
			
		||||
                var centerX = 210,
 | 
			
		||||
                    centerY = 210,
 | 
			
		||||
                    radius = 150,
 | 
			
		||||
                    outerRadius = 200;
 | 
			
		||||
 | 
			
		||||
                // Create a speedometer object using Javascript object notation
 | 
			
		||||
                return {
 | 
			
		||||
                    ctx: canvas.getContext('2d'),
 | 
			
		||||
                    speed: iSpeed,
 | 
			
		||||
                    center:    {
 | 
			
		||||
                        X: centerX,
 | 
			
		||||
                        Y: centerY
 | 
			
		||||
                    },
 | 
			
		||||
                    levelRadius: radius - 10,
 | 
			
		||||
                    gaugeOptions: {
 | 
			
		||||
                        center:    {
 | 
			
		||||
                            X: centerX,
 | 
			
		||||
                            Y: centerY
 | 
			
		||||
                        },
 | 
			
		||||
                        radius: radius
 | 
			
		||||
                    },
 | 
			
		||||
                    radius: outerRadius
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function clearCanvas(options) {
 | 
			
		||||
                options.ctx.clearRect(0, 0, 800, 600);
 | 
			
		||||
                applyDefaultContextSettings(options);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function draw() {
 | 
			
		||||
                /* Main entry point for drawing the speedometer
 | 
			
		||||
                * If canvas is not support alert the user.
 | 
			
		||||
                */  
 | 
			
		||||
                var canvas = createCanvas.value,
 | 
			
		||||
                    options = null;
 | 
			
		||||
 | 
			
		||||
                // Canvas good?
 | 
			
		||||
                if (canvas !== null && canvas.getContext) {
 | 
			
		||||
                    options = buildOptionsAsJSON(canvas, iCurrentSpeed);
 | 
			
		||||
 | 
			
		||||
                    // Clear canvas
 | 
			
		||||
                    clearCanvas(options);
 | 
			
		||||
 | 
			
		||||
                    // Draw the metallic styled edge
 | 
			
		||||
                    drawMetallicArc(options);
 | 
			
		||||
 | 
			
		||||
                    // Draw thw background
 | 
			
		||||
                    drawBackground(options);
 | 
			
		||||
 | 
			
		||||
                    // Draw tick marks
 | 
			
		||||
                    drawTicks(options);
 | 
			
		||||
 | 
			
		||||
                    // Draw labels on markers
 | 
			
		||||
                    drawTextMarkers(options);
 | 
			
		||||
 | 
			
		||||
                    // Draw speeometer colour arc
 | 
			
		||||
                    drawSpeedometerColourArc(options);
 | 
			
		||||
 | 
			
		||||
                    // Draw the needle and base
 | 
			
		||||
                    drawNeedle(options);
 | 
			
		||||
                    
 | 
			
		||||
                } else {
 | 
			
		||||
                    alert("Canvas not supported by your browser!");
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if(iTargetSpeed == iCurrentSpeed) {
 | 
			
		||||
                    cancelAnimationFrame(job);
 | 
			
		||||
                    return;
 | 
			
		||||
                } else if(iTargetSpeed < iCurrentSpeed) {
 | 
			
		||||
                    bDecrement = true;
 | 
			
		||||
                } else if(iTargetSpeed > iCurrentSpeed) {
 | 
			
		||||
                    bDecrement = false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                console.log(iTargetSpeed,bDecrement)
 | 
			
		||||
                
 | 
			
		||||
                if(bDecrement) {
 | 
			
		||||
                    iCurrentSpeed = iCurrentSpeed - 1;
 | 
			
		||||
                } else {
 | 
			
		||||
                 iCurrentSpeed = iCurrentSpeed + 1;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                job = requestAnimationFrame(draw);
 | 
			
		||||
            };
 | 
			
		||||
            function createCanvas()
 | 
			
		||||
            {
 | 
			
		||||
                let container = document.createElement("div");
 | 
			
		||||
                container.classList.add("boxmodel")
 | 
			
		||||
                let canvas = document.createElement("canvas");
 | 
			
		||||
 | 
			
		||||
                let text = document.createElement("div");
 | 
			
		||||
                let text1 = document.createElement("div");
 | 
			
		||||
                let text2 = document.createElement("div");
 | 
			
		||||
                text.classList.add("text")
 | 
			
		||||
                text1.classList.add("text1")
 | 
			
		||||
                text2.classList.add("text2")
 | 
			
		||||
                text.append(text1);
 | 
			
		||||
                text.append(text2);
 | 
			
		||||
 | 
			
		||||
                canvas.setAttribute("width", "440px");
 | 
			
		||||
                canvas.setAttribute("height", "220px");
 | 
			
		||||
                container.append(canvas);
 | 
			
		||||
                container.append(text);
 | 
			
		||||
                createCanvas.value = canvas;
 | 
			
		||||
                createCanvas.container = container;
 | 
			
		||||
                createCanvas.ps = text1;
 | 
			
		||||
                createCanvas.pw = text2;
 | 
			
		||||
                return container;
 | 
			
		||||
            };
 | 
			
		||||
            function update(value, pressure)
 | 
			
		||||
            {
 | 
			
		||||
                iTargetSpeed = value;
 | 
			
		||||
                createCanvas.ps.innerText = value;
 | 
			
		||||
                createCanvas.pw.innerText = pressure + '%';
 | 
			
		||||
                draw()
 | 
			
		||||
            }
 | 
			
		||||
            function convertSpeedToAngle(options) {
 | 
			
		||||
                /* Helper function to convert a speed to the
 | 
			
		||||
                * equivelant angle.
 | 
			
		||||
                */
 | 
			
		||||
                let m = 150;
 | 
			
		||||
                let value = (m/10) + Math.min(
 | 
			
		||||
                    Math.max(
 | 
			
		||||
                        options.speed,
 | 
			
		||||
                        0
 | 
			
		||||
                    ),
 | 
			
		||||
                    240
 | 
			
		||||
                );
 | 
			
		||||
                iSpeedAsAngle = (
 | 
			
		||||
                    (100 / m) * value
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Ensure the angle is within range
 | 
			
		||||
                if (iSpeedAsAngle > 180) {
 | 
			
		||||
                    iSpeedAsAngle = iSpeedAsAngle - 180;
 | 
			
		||||
                } else if (iSpeedAsAngle < 0) {
 | 
			
		||||
                    iSpeedAsAngle = iSpeedAsAngle + 180;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return iSpeedAsAngle;
 | 
			
		||||
            }
 | 
			
		||||
            return {
 | 
			
		||||
                createCanvas,
 | 
			
		||||
                update
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        /*
 | 
			
		||||
        let elem = document.querySelector(".speed-container");
 | 
			
		||||
        for(let e = 0; e < 8; e++)
 | 
			
		||||
        {
 | 
			
		||||
            let meter = CreateMeter();
 | 
			
		||||
            let container = meter.createCanvas();
 | 
			
		||||
            elem.appendChild(container);
 | 
			
		||||
            meter.update(54,25)
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        let elem = document.querySelector(".speed-container");
 | 
			
		||||
       let meters = new Map();
 | 
			
		||||
       async function reloadData()
 | 
			
		||||
       {
 | 
			
		||||
            let data = await fetchData();
 | 
			
		||||
            setTimeout(reloadData, 3000)
 | 
			
		||||
       };
 | 
			
		||||
       let isFirst = true;
 | 
			
		||||
       async function fetchData()
 | 
			
		||||
       {
 | 
			
		||||
        let response = await fetch("/stats",{
 | 
			
		||||
            method: "post",
 | 
			
		||||
            credentials: "same-origin",
 | 
			
		||||
            cache: "no-cache",
 | 
			
		||||
            mode:"no-cors"
 | 
			
		||||
        }).then(e => e.json());
 | 
			
		||||
        for (const {
 | 
			
		||||
            ws_total_packs,
 | 
			
		||||
            core
 | 
			
		||||
        } of response) {
 | 
			
		||||
            if(!meters.has(core))
 | 
			
		||||
            {
 | 
			
		||||
                let meter = CreateMeter();
 | 
			
		||||
                let container = meter.createCanvas();
 | 
			
		||||
                elem.appendChild(container);
 | 
			
		||||
                meters.set(core, meter)
 | 
			
		||||
            };
 | 
			
		||||
            let _meter = meters.get(core);
 | 
			
		||||
            _meter.update(ws_total_packs,ws_total_packs < 30 ? 0 : ws_total_packs < 60 ? 1 : ws_total_packs < 90 ? 2 : 3)
 | 
			
		||||
        }
 | 
			
		||||
       }
 | 
			
		||||
       reloadData();
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -7,12 +7,13 @@
 | 
			
		|||
    <title>Document</title>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <script src="./script/index.js"></script>
 | 
			
		||||
    <h2><pre id="log"></pre></h2>
 | 
			
		||||
    <h1 id="message"></h1>
 | 
			
		||||
    <script src="http://ws.saqut.com/script"></script>
 | 
			
		||||
    <script>
 | 
			
		||||
        var wsjs, iroom;
 | 
			
		||||
        async function main(){
 | 
			
		||||
            wsjs = new MWSE({
 | 
			
		||||
                endpoint: "ws://localhost:7707"
 | 
			
		||||
            const wsjs = new MWSE({
 | 
			
		||||
                endpoint: "ws://ws.saqut.com"
 | 
			
		||||
            });
 | 
			
		||||
            wsjs.scope(async ()=>{
 | 
			
		||||
                let me = wsjs.peer('me');
 | 
			
		||||
| 
						 | 
				
			
			@ -30,16 +31,29 @@
 | 
			
		|||
                });
 | 
			
		||||
                await room.createRoom();
 | 
			
		||||
                room.on('message',(...args)=>{
 | 
			
		||||
                    console.log(args)
 | 
			
		||||
                    gg.r++
 | 
			
		||||
                    gg()
 | 
			
		||||
                });
 | 
			
		||||
                iroom = room;
 | 
			
		||||
                setInterval(()=>{
 | 
			
		||||
                    room.send({
 | 
			
		||||
                        type: "merhaba"
 | 
			
		||||
                    }, true)
 | 
			
		||||
                    gg.w++;
 | 
			
		||||
                    gg()
 | 
			
		||||
                }, 200)
 | 
			
		||||
            });
 | 
			
		||||
            wsjs.on('peer',(peer)=>{
 | 
			
		||||
                peer.on('message',(...args)=>{
 | 
			
		||||
                    console.log(args);
 | 
			
		||||
                })
 | 
			
		||||
            })
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        function gg()
 | 
			
		||||
        {
 | 
			
		||||
            log.innerHTML = `${gg.w} packet writed\n${gg.r} packet recaived`
 | 
			
		||||
        }
 | 
			
		||||
        gg.w = 0;
 | 
			
		||||
        gg.r = 0;
 | 
			
		||||
        /*setInterval(()=>{
 | 
			
		||||
            window.location.reload();
 | 
			
		||||
        }, 30000)*/
 | 
			
		||||
        main();
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
		Loading…
	
		Reference in New Issue