multitasking #7
|
@ -1,3 +1,5 @@
|
||||||
|
const { CLIENT_SEND_MESSAGE, CLIENT_UPDATE_PROP } = require("./IPC");
|
||||||
|
const stats = require("./stats");
|
||||||
function Client()
|
function Client()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +23,17 @@ function Client()
|
||||||
this.APNumber = 0;
|
this.APNumber = 0;
|
||||||
this.APShortCode = 0;
|
this.APShortCode = 0;
|
||||||
this.APIPAddress = 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>}
|
* @type {Map<string, Client>}
|
||||||
|
@ -34,6 +47,7 @@ Client.prototype.peerRequest = function(client){
|
||||||
let info = {};
|
let info = {};
|
||||||
this.store.forEach((value, name) => info[name] = value);
|
this.store.forEach((value, name) => info[name] = value);
|
||||||
this.pairs.add(client.id);
|
this.pairs.add(client.id);
|
||||||
|
this.sync('pairs');
|
||||||
client.send([{
|
client.send([{
|
||||||
from: this.id,
|
from: this.id,
|
||||||
info
|
info
|
||||||
|
@ -45,6 +59,7 @@ Client.prototype.peerRequest = function(client){
|
||||||
*/
|
*/
|
||||||
Client.prototype.acceptPeerRequest = function(client){
|
Client.prototype.acceptPeerRequest = function(client){
|
||||||
this.pairs.add(client.id);
|
this.pairs.add(client.id);
|
||||||
|
this.sync('pairs');
|
||||||
client.send([{
|
client.send([{
|
||||||
from: this.id
|
from: this.id
|
||||||
},'accepted/pair']);
|
},'accepted/pair']);
|
||||||
|
@ -55,6 +70,7 @@ Client.prototype.peerRequest = function(client){
|
||||||
Client.prototype.rejectPeerRequest = function(client){
|
Client.prototype.rejectPeerRequest = function(client){
|
||||||
this.pairs.delete(client.id);
|
this.pairs.delete(client.id);
|
||||||
client.pairs.delete(this.id);
|
client.pairs.delete(this.id);
|
||||||
|
this.sync('pairs');
|
||||||
client.send([{
|
client.send([{
|
||||||
from: this.id
|
from: this.id
|
||||||
},'rejected/pair']);
|
},'rejected/pair']);
|
||||||
|
@ -75,7 +91,13 @@ Client.prototype.pairList = function(){
|
||||||
};
|
};
|
||||||
|
|
||||||
Client.prototype.send = function(obj){
|
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;
|
exports.Client = Client;
|
|
@ -6,19 +6,27 @@ let compression = require("compression");
|
||||||
let {resolve} = require("path");
|
let {resolve} = require("path");
|
||||||
const { termoutput } = require("./config");
|
const { termoutput } = require("./config");
|
||||||
let server = http.createServer();
|
let server = http.createServer();
|
||||||
|
const stats = require("./stats");
|
||||||
let app = express();
|
let app = express();
|
||||||
server.addListener("request", app);
|
server.addListener("request", app);
|
||||||
app.use(compression({
|
app.use(compression({
|
||||||
level: 9
|
level: 9
|
||||||
}));
|
}));
|
||||||
|
|
||||||
server.listen(7707,'0.0.0.0',() => {
|
server.listen(7707,'0.0.0.0',() => {
|
||||||
termoutput && console.log("HTTP Service Running...");
|
termoutput && console.log("HTTP Service Running...");
|
||||||
});
|
});
|
||||||
|
server.addListener("error",(err)=> {
|
||||||
|
console.err(err)
|
||||||
|
})
|
||||||
exports.http = server;
|
exports.http = server;
|
||||||
|
|
||||||
app.get("/script",(request, response)=>{
|
app.get("/script",(request, response)=>{
|
||||||
response.sendFile(resolve("./script/index.js"))
|
response.sendFile(resolve("./script/index.js"))
|
||||||
});
|
});
|
||||||
|
app.get("/test",(request, response)=>{
|
||||||
|
response.sendFile(resolve("./script/test.html"))
|
||||||
|
});
|
||||||
app.get("/index.js.map",(request, response)=>{
|
app.get("/index.js.map",(request, response)=>{
|
||||||
response.sendFile(resolve("./script/index.js.map"))
|
response.sendFile(resolve("./script/index.js.map"))
|
||||||
});
|
});
|
||||||
|
@ -28,6 +36,12 @@ app.get("/webrtc.js",(request, response)=>{
|
||||||
app.get("/webrtc.adapter.js",(request, response)=>{
|
app.get("/webrtc.adapter.js",(request, response)=>{
|
||||||
response.sendFile(resolve("./script/webrtc.adapter.js"))
|
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)=>{
|
app.get("*",(request, response)=>{
|
||||||
response.sendFile(resolve("./script/status.xml"))
|
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 } = require("../Client.js");
|
||||||
|
const { CLIENT_UPDATE_PROP } = require("../IPC.js");
|
||||||
let {addService, addListener} = require("../WebSocket.js");
|
let {addService, addListener} = require("../WebSocket.js");
|
||||||
|
|
||||||
addService(({
|
addService(({
|
||||||
|
@ -13,13 +14,16 @@ addService(({
|
||||||
case "auth/pair-system":{
|
case "auth/pair-system":{
|
||||||
if(value == 'everybody')
|
if(value == 'everybody')
|
||||||
{
|
{
|
||||||
client.requiredPair = true;
|
client.requiredPair = true;
|
||||||
end({status:"success"});
|
end({status:"success"});
|
||||||
|
client.sync('requiredPair');
|
||||||
}
|
}
|
||||||
if(value == 'disable')
|
if(value == 'disable')
|
||||||
{
|
{
|
||||||
client.requiredPair = false;
|
client.requiredPair = false;
|
||||||
end({status:"success"});
|
end({status:"success"});
|
||||||
|
client.sync('requiredPair');
|
||||||
|
//CLIENT_UPDATE_PROP(client.id, 'requiredPair', client.requiredPair);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +33,7 @@ addService(({
|
||||||
}
|
}
|
||||||
case 'auth/public':{
|
case 'auth/public':{
|
||||||
client.requiredPair = false;
|
client.requiredPair = false;
|
||||||
|
client.sync('requiredPair');
|
||||||
return end({
|
return end({
|
||||||
value: 'success',
|
value: 'success',
|
||||||
mode: 'public'
|
mode: 'public'
|
||||||
|
@ -36,6 +41,7 @@ addService(({
|
||||||
}
|
}
|
||||||
case 'auth/private':{
|
case 'auth/private':{
|
||||||
client.requiredPair = true;
|
client.requiredPair = true;
|
||||||
|
client.sync('requiredPair');
|
||||||
return end({
|
return end({
|
||||||
value: 'success',
|
value: 'success',
|
||||||
mode: 'private'
|
mode: 'private'
|
||||||
|
|
|
@ -94,9 +94,9 @@ addService(({
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
Room.rooms.get(to).send([{
|
Room.rooms.get(to).send([{
|
||||||
from: client.id,
|
from: to,
|
||||||
pack: pack
|
pack: pack
|
||||||
}, 'pack'], wom ? client.id : void 0);
|
}, 'pack/room'], wom ? client.id : void 0);
|
||||||
handshake && end({
|
handshake && end({
|
||||||
type: 'success'
|
type: 'success'
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,6 +3,7 @@ let {addService, addListener} = require("../WebSocket.js");
|
||||||
let {
|
let {
|
||||||
randomBytes
|
randomBytes
|
||||||
} = require("node:crypto");
|
} = require("node:crypto");
|
||||||
|
const { slog } = require("../IPC");
|
||||||
|
|
||||||
class APNumber{
|
class APNumber{
|
||||||
/**
|
/**
|
||||||
|
@ -11,14 +12,20 @@ class APNumber{
|
||||||
static busyNumbers = new Map();
|
static busyNumbers = new Map();
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number}
|
||||||
|
* @param {Client} client
|
||||||
*/
|
*/
|
||||||
static lock()
|
static lock(client)
|
||||||
{
|
{
|
||||||
let c = 24;
|
let c = 24;
|
||||||
while(true){
|
while(true){
|
||||||
if(!APNumber.busyNumbers.has(c))
|
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;
|
return c;
|
||||||
}
|
}
|
||||||
c++;
|
c++;
|
||||||
|
@ -30,6 +37,11 @@ class APNumber{
|
||||||
static release(num)
|
static release(num)
|
||||||
{
|
{
|
||||||
APNumber.busyNumbers.delete(num);
|
APNumber.busyNumbers.delete(num);
|
||||||
|
process.send({
|
||||||
|
type: 'AP_NUMBER/RELEASE',
|
||||||
|
uuid: APNumber.busyNumbers.get(num).id,
|
||||||
|
value: num
|
||||||
|
})
|
||||||
}
|
}
|
||||||
static whois(num){
|
static whois(num){
|
||||||
return APNumber.busyNumbers.get(num)?.id;
|
return APNumber.busyNumbers.get(num)?.id;
|
||||||
|
@ -56,6 +68,11 @@ class APShortCode{
|
||||||
if(APShortCode.busyCodes.has(code) == false)
|
if(APShortCode.busyCodes.has(code) == false)
|
||||||
{
|
{
|
||||||
APShortCode.busyCodes.set(code, client);
|
APShortCode.busyCodes.set(code, client);
|
||||||
|
process.send({
|
||||||
|
type: 'AP_SHORTCODE/LOCK',
|
||||||
|
uuid: APShortCode.busyCodes.get(num).id,
|
||||||
|
value: code
|
||||||
|
})
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
if(!thirdLetter.end())
|
if(!thirdLetter.end())
|
||||||
|
@ -79,7 +96,15 @@ class APShortCode{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static release(code){
|
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){
|
static whois(num){
|
||||||
return APShortCode.busyCodes.get(num)?.id;
|
return APShortCode.busyCodes.get(num)?.id;
|
||||||
|
@ -122,6 +147,11 @@ class APIPAddress{
|
||||||
if(APIPAddress.busyIP.has(code) == false)
|
if(APIPAddress.busyIP.has(code) == false)
|
||||||
{
|
{
|
||||||
APIPAddress.busyIP.set(code, client);
|
APIPAddress.busyIP.set(code, client);
|
||||||
|
process.send({
|
||||||
|
type: 'AP_IPADDRESS/LOCK',
|
||||||
|
uuid: APIPAddress.busyIP.get(code).id,
|
||||||
|
value: code
|
||||||
|
})
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
if(D != 255)
|
if(D != 255)
|
||||||
|
@ -156,7 +186,15 @@ class APIPAddress{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static release(code){
|
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){
|
static whois(num){
|
||||||
return APIPAddress.busyIP.get(num)?.id;
|
return APIPAddress.busyIP.get(num)?.id;
|
||||||
|
@ -167,7 +205,6 @@ exports.APNumber = APNumber;
|
||||||
exports.APShortCode = APShortCode;
|
exports.APShortCode = APShortCode;
|
||||||
exports.APIPAddress = APIPAddress;
|
exports.APIPAddress = APIPAddress;
|
||||||
|
|
||||||
|
|
||||||
addService(({
|
addService(({
|
||||||
client,
|
client,
|
||||||
message,
|
message,
|
||||||
|
@ -186,6 +223,7 @@ addService(({
|
||||||
};
|
};
|
||||||
let value = APIPAddress.lock(client);
|
let value = APIPAddress.lock(client);
|
||||||
client.APIPAddress = value;
|
client.APIPAddress = value;
|
||||||
|
client.sync('APIPAddress');
|
||||||
end({
|
end({
|
||||||
status : "success",
|
status : "success",
|
||||||
ip : value
|
ip : value
|
||||||
|
@ -201,6 +239,7 @@ addService(({
|
||||||
};
|
};
|
||||||
let value = APNumber.lock(client);
|
let value = APNumber.lock(client);
|
||||||
client.APNumber = value;
|
client.APNumber = value;
|
||||||
|
client.sync('APNumber');
|
||||||
end({
|
end({
|
||||||
status : "success",
|
status : "success",
|
||||||
number : value
|
number : value
|
||||||
|
@ -216,6 +255,7 @@ addService(({
|
||||||
};
|
};
|
||||||
let value = APShortCode.lock(client);
|
let value = APShortCode.lock(client);
|
||||||
client.APShortCode = value;
|
client.APShortCode = value;
|
||||||
|
client.sync('APShortCode');
|
||||||
end({
|
end({
|
||||||
status : "success",
|
status : "success",
|
||||||
code : value
|
code : value
|
||||||
|
@ -230,6 +270,7 @@ addService(({
|
||||||
}
|
}
|
||||||
APIPAddress.release(client.APIPAddress);
|
APIPAddress.release(client.APIPAddress);
|
||||||
let value = APIPAddress.lock(client);
|
let value = APIPAddress.lock(client);
|
||||||
|
client.sync('APIPAddress');
|
||||||
end({
|
end({
|
||||||
status : "success",
|
status : "success",
|
||||||
ip : value
|
ip : value
|
||||||
|
@ -244,6 +285,7 @@ addService(({
|
||||||
}
|
}
|
||||||
APNumber.release(client.APNumber);
|
APNumber.release(client.APNumber);
|
||||||
let value = APNumber.lock(client);
|
let value = APNumber.lock(client);
|
||||||
|
client.sync('APNumber');
|
||||||
end({
|
end({
|
||||||
status : "success",
|
status : "success",
|
||||||
number : value
|
number : value
|
||||||
|
@ -258,6 +300,7 @@ addService(({
|
||||||
}
|
}
|
||||||
APShortCode.release(client.APShortCode);
|
APShortCode.release(client.APShortCode);
|
||||||
let value = APShortCode.lock(client);
|
let value = APShortCode.lock(client);
|
||||||
|
client.sync('APShortCode');
|
||||||
end({
|
end({
|
||||||
status : "success",
|
status : "success",
|
||||||
code : value
|
code : value
|
||||||
|
@ -266,6 +309,8 @@ addService(({
|
||||||
}
|
}
|
||||||
case "release/APIPAddress":{
|
case "release/APIPAddress":{
|
||||||
APIPAddress.release(client.APIPAddress);
|
APIPAddress.release(client.APIPAddress);
|
||||||
|
client.APIPAddress = void 0;
|
||||||
|
client.sync('APShortCode');
|
||||||
end({
|
end({
|
||||||
status : "success"
|
status : "success"
|
||||||
})
|
})
|
||||||
|
@ -273,6 +318,8 @@ addService(({
|
||||||
}
|
}
|
||||||
case "release/APNumber":{
|
case "release/APNumber":{
|
||||||
APNumber.release(client.APNumber);
|
APNumber.release(client.APNumber);
|
||||||
|
client.APNumber = void 0;
|
||||||
|
client.sync('APIPAddress');
|
||||||
end({
|
end({
|
||||||
status : "success"
|
status : "success"
|
||||||
})
|
})
|
||||||
|
@ -280,6 +327,8 @@ addService(({
|
||||||
}
|
}
|
||||||
case "release/APShortCode":{
|
case "release/APShortCode":{
|
||||||
APShortCode.release(client.APShortCode);
|
APShortCode.release(client.APShortCode);
|
||||||
|
client.APShortCode = void 0;
|
||||||
|
client.sync('APIPAddress');
|
||||||
end({
|
end({
|
||||||
status : "success"
|
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)=>{
|
addListener('disconnect',(global, client)=>{
|
||||||
if(client.APIPAddress != 0)
|
if(client.APIPAddress != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@ let {randomUUID,createHash} = require("crypto");
|
||||||
const joi = require("joi");
|
const joi = require("joi");
|
||||||
let {addService,addListener} = require("../WebSocket.js");
|
let {addService,addListener} = require("../WebSocket.js");
|
||||||
const { termoutput } = require("../config.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;
|
let term = require("terminal-kit").terminal;
|
||||||
|
|
||||||
function Sha256(update)
|
function Sha256(update)
|
||||||
|
@ -64,15 +65,24 @@ function Room()
|
||||||
* @type {string[]}
|
* @type {string[]}
|
||||||
*/
|
*/
|
||||||
this.waitingInvited = new Set();
|
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
|
* @param {Room} room
|
||||||
*/
|
*/
|
||||||
Room.prototype.publish = function(room){
|
Room.prototype.publish = function(room){
|
||||||
Room.rooms.set(this.id, this);
|
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');
|
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 = {};
|
let obj = {};
|
||||||
obj.id = this.id;
|
obj.id = this.id;
|
||||||
obj.accessType = this.accessType;
|
obj.accessType = this.accessType;
|
||||||
|
@ -82,8 +92,47 @@ Room.prototype.toJSON = function(){
|
||||||
obj.name = this.name;
|
obj.name = this.name;
|
||||||
obj.owner = this.owner.id;
|
obj.owner = this.owner.id;
|
||||||
obj.waitingInvited = [...this.waitingInvited];
|
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;
|
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){
|
Room.prototype.send = function(obj, withOut){
|
||||||
for (const client of this.clients.values()) {
|
for (const client of this.clients.values()) {
|
||||||
if(client.id != withOut)
|
if(client.id != withOut)
|
||||||
|
@ -107,6 +156,7 @@ Room.prototype.join = function(client){
|
||||||
};
|
};
|
||||||
client.rooms.add(this.id);
|
client.rooms.add(this.id);
|
||||||
this.clients.set(client.id, client);
|
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');
|
termoutput && term.green("Client Room joined ").white(this.name," in ").yellow(this.clients.size + "").white(" clients")('\n');
|
||||||
};
|
};
|
||||||
Room.prototype.down = function(){
|
Room.prototype.down = function(){
|
||||||
|
@ -116,6 +166,7 @@ Room.prototype.down = function(){
|
||||||
ownerid: this.owner.id
|
ownerid: this.owner.id
|
||||||
},'room/closed']);
|
},'room/closed']);
|
||||||
Room.rooms.delete(this.id);
|
Room.rooms.delete(this.id);
|
||||||
|
ROOM_DESTROY(this)
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @param {Client} client
|
* @param {Client} client
|
||||||
|
@ -131,6 +182,7 @@ Room.prototype.eject = function(client){
|
||||||
}
|
}
|
||||||
client.rooms.delete(this.id);
|
client.rooms.delete(this.id);
|
||||||
this.clients.delete(client.id);
|
this.clients.delete(client.id);
|
||||||
|
ROOM_EJECT_CLIENT(this.id, client.id);
|
||||||
|
|
||||||
if(this.clients.size == 0)
|
if(this.clients.size == 0)
|
||||||
{
|
{
|
||||||
|
@ -154,8 +206,8 @@ addListener('connect',(global, client)=>{
|
||||||
room.id = client.id;
|
room.id = client.id;
|
||||||
room.name = "Your Room | " + client.id;
|
room.name = "Your Room | " + client.id;
|
||||||
room.owner = client;
|
room.owner = client;
|
||||||
room.join(client);
|
|
||||||
room.publish();
|
room.publish();
|
||||||
|
room.join(client);
|
||||||
});
|
});
|
||||||
|
|
||||||
addListener('disconnect',(global, client)=>{
|
addListener('disconnect',(global, client)=>{
|
||||||
|
@ -296,8 +348,8 @@ addService(({
|
||||||
{
|
{
|
||||||
room.credential = Sha256(message.credential + "");
|
room.credential = Sha256(message.credential + "");
|
||||||
}
|
}
|
||||||
room.join(client);
|
|
||||||
room.publish();
|
room.publish();
|
||||||
|
room.join(client);
|
||||||
end({
|
end({
|
||||||
status: "success",
|
status: "success",
|
||||||
room: room.toJSON()
|
room: room.toJSON()
|
||||||
|
|
|
@ -5,6 +5,8 @@ let {http} = require("./HTTPServer");
|
||||||
let {randomUUID} = require("crypto");
|
let {randomUUID} = require("crypto");
|
||||||
const { Client } = require("./Client.js");
|
const { Client } = require("./Client.js");
|
||||||
const { termoutput } = require("./config");
|
const { termoutput } = require("./config");
|
||||||
|
const { CLIENT_CREATED, CLIENT_DESTROY } = require("./IPC");
|
||||||
|
const stats = require("./stats");
|
||||||
termoutput && console.log("Web Socket Protocol is ready");
|
termoutput && console.log("Web Socket Protocol is ready");
|
||||||
|
|
||||||
http.addListener("upgrade",() => {
|
http.addListener("upgrade",() => {
|
||||||
|
@ -15,11 +17,22 @@ let wsServer = new websocket.server({
|
||||||
httpServer: http,
|
httpServer: http,
|
||||||
autoAcceptConnections: true
|
autoAcceptConnections: true
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
|
process.send({
|
||||||
|
core: "writestat",
|
||||||
|
writeBytes:0,
|
||||||
|
readBytes:0,
|
||||||
|
totalBytes:0,
|
||||||
|
recaivedPacket:0,
|
||||||
|
sendedPacket:0,
|
||||||
|
totalPacket:0
|
||||||
|
})*/
|
||||||
|
|
||||||
let global = new Map();
|
let global = new Map();
|
||||||
let clients = new Map();
|
let clients = new Map();
|
||||||
wsServer.addListener("connect",(socket) => {
|
|
||||||
|
|
||||||
|
|
||||||
|
wsServer.addListener("connect",(socket) => {
|
||||||
let xClient = new Client();
|
let xClient = new Client();
|
||||||
let id = randomUUID();
|
let id = randomUUID();
|
||||||
socket.id = id;
|
socket.id = id;
|
||||||
|
@ -29,12 +42,34 @@ wsServer.addListener("connect",(socket) => {
|
||||||
Client.clients.set(id, xClient);
|
Client.clients.set(id, xClient);
|
||||||
clients.set(id, xClient);
|
clients.set(id, xClient);
|
||||||
|
|
||||||
|
console.log("Client:", id,"on worker pid:",process.pid)
|
||||||
|
|
||||||
|
CLIENT_CREATED(id);
|
||||||
|
|
||||||
emit("connect", global, xClient);
|
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",()=>{
|
socket.addListener("close",()=>{
|
||||||
emit("disconnect", global, xClient);
|
emit("disconnect", global, xClient);
|
||||||
|
CLIENT_DESTROY(id);
|
||||||
Client.clients.set(id, xClient);
|
Client.clients.set(id, xClient);
|
||||||
|
clearInterval(timer);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.addListener("message",({type,utf8Data}) => {
|
socket.addListener("message",({type,utf8Data}) => {
|
||||||
|
stats.ws_recaived_packs++;
|
||||||
|
stats.ws_total_packs++;
|
||||||
|
|
||||||
if(type == "utf8")
|
if(type == "utf8")
|
||||||
{
|
{
|
||||||
let json;
|
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;
|
||||||
|
}
|
||||||
|
})
|
|
@ -70,9 +70,9 @@ export default class MWSE extends EventTarget {
|
||||||
this.peer(from, true).emit('request', scope);
|
this.peer(from, true).emit('request', scope);
|
||||||
this.peer('me').emit('request', scope);
|
this.peer('me').emit('request', scope);
|
||||||
})
|
})
|
||||||
this.EventPooling.signal('pack/room',(payload : {to:string,pack:any}) => {
|
this.EventPooling.signal('pack/room',(payload : {from:string,pack:any}) => {
|
||||||
let {to,pack} = payload;
|
let {from,pack} = payload;
|
||||||
this.room(to).emit('message', pack);
|
this.room(from).emit('message', pack);
|
||||||
})
|
})
|
||||||
this.EventPooling.signal('room/joined',(payload : {id:string,roomid:any,ownerid:string}) => {
|
this.EventPooling.signal('room/joined',(payload : {id:string,roomid:any,ownerid:string}) => {
|
||||||
let {id,roomid} = payload;
|
let {id,roomid} = payload;
|
||||||
|
|
|
@ -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>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -7,12 +7,13 @@
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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>
|
<script>
|
||||||
var wsjs, iroom;
|
|
||||||
async function main(){
|
async function main(){
|
||||||
wsjs = new MWSE({
|
const wsjs = new MWSE({
|
||||||
endpoint: "ws://localhost:7707"
|
endpoint: "ws://ws.saqut.com"
|
||||||
});
|
});
|
||||||
wsjs.scope(async ()=>{
|
wsjs.scope(async ()=>{
|
||||||
let me = wsjs.peer('me');
|
let me = wsjs.peer('me');
|
||||||
|
@ -30,16 +31,29 @@
|
||||||
});
|
});
|
||||||
await room.createRoom();
|
await room.createRoom();
|
||||||
room.on('message',(...args)=>{
|
room.on('message',(...args)=>{
|
||||||
console.log(args)
|
gg.r++
|
||||||
|
gg()
|
||||||
});
|
});
|
||||||
iroom = room;
|
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();
|
main();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
Loading…
Reference in New Issue