Compare commits

..

No commits in common. "dff0d92474ddcc991df2d51c93c994558c782c8b" and "a37029228a2a0f24effaa3aea7c1ee1799f1b28b" have entirely different histories.

10 changed files with 48 additions and 257 deletions

View File

@ -1,11 +1,10 @@
{ {
"motd": "Welcome to Soqet v2.1", "motd": "Welcome to Soqet v2.0",
"httpPort": 3004, "httpPort": 3004,
"tcpPort": 25555, "tcpPort": 25555,
"enableWebsocket": true, "enableWebsocket": true,
"enableTCPSocket": true, "enableTCPSocket": true,
"enablePolling": true, "enablePolling": true,
"wildcardChannel": "*", "wildcardChannel": "*",
"pollingInterval": 3600, "pollingInterval": 3600
"enablePrometheus": true
} }

157
package-lock.json generated
View File

@ -1,31 +1,26 @@
{ {
"name": "soqet", "name": "soqet",
"version": "2.1.0", "version": "2.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "soqet", "name": "soqet",
"version": "2.1.0", "version": "2.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"prom-client": "^14.0.1", "ws": "^7.5.5"
"ws": "^7.5.6"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^14.17.34", "@types/node": "^14.17.19",
"@types/ws": "^7.4.7", "@types/ws": "^7.4.7",
"typescript": "^4.5.2" "typescript": "^4.4.3"
},
"optionalDependencies": {
"bufferutil": "^4.0.5",
"utf-8-validate": "^5.0.7"
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "14.17.34", "version": "14.17.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.34.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.19.tgz",
"integrity": "sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg==", "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==",
"dev": true "dev": true
}, },
"node_modules/@types/ws": { "node_modules/@types/ws": {
@ -37,58 +32,10 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/bintrees": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz",
"integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ="
},
"node_modules/bufferutil": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz",
"integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/node-gyp-build": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/prom-client": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.0.1.tgz",
"integrity": "sha512-HxTArb6fkOntQHoRGvv4qd/BkorjliiuO2uSWC2KC17MUTKYttWdDoXX/vxOhQdkoECEM9BBH0pj2l8G8kev6w==",
"dependencies": {
"tdigest": "^0.1.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/tdigest": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz",
"integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=",
"dependencies": {
"bintrees": "1.0.1"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.5.2", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
"integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -98,23 +45,10 @@
"node": ">=4.2.0" "node": ">=4.2.0"
} }
}, },
"node_modules/utf-8-validate": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz",
"integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/ws": { "node_modules/ws": {
"version": "7.5.6", "version": "7.5.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
"integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
"engines": { "engines": {
"node": ">=8.3.0" "node": ">=8.3.0"
}, },
@ -134,9 +68,9 @@
}, },
"dependencies": { "dependencies": {
"@types/node": { "@types/node": {
"version": "14.17.34", "version": "14.17.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.34.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.19.tgz",
"integrity": "sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg==", "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==",
"dev": true "dev": true
}, },
"@types/ws": { "@types/ws": {
@ -148,61 +82,16 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"bintrees": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz",
"integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ="
},
"bufferutil": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz",
"integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
"optional": true,
"requires": {
"node-gyp-build": "^4.3.0"
}
},
"node-gyp-build": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
"optional": true
},
"prom-client": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.0.1.tgz",
"integrity": "sha512-HxTArb6fkOntQHoRGvv4qd/BkorjliiuO2uSWC2KC17MUTKYttWdDoXX/vxOhQdkoECEM9BBH0pj2l8G8kev6w==",
"requires": {
"tdigest": "^0.1.1"
}
},
"tdigest": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz",
"integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=",
"requires": {
"bintrees": "1.0.1"
}
},
"typescript": { "typescript": {
"version": "4.5.2", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
"integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
"dev": true "dev": true
}, },
"utf-8-validate": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz",
"integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
"optional": true,
"requires": {
"node-gyp-build": "^4.3.0"
}
},
"ws": { "ws": {
"version": "7.5.6", "version": "7.5.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
"integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
"requires": {} "requires": {}
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "soqet", "name": "soqet",
"version": "2.1.0", "version": "2.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@ -11,16 +11,11 @@
"author": "AlexDevs", "author": "AlexDevs",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"prom-client": "^14.0.1", "ws": "^7.5.5"
"ws": "^7.5.6"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^14.17.34", "@types/node": "^14.17.19",
"@types/ws": "^7.4.7", "@types/ws": "^7.4.7",
"typescript": "^4.5.2" "typescript": "^4.4.3"
},
"optionalDependencies": {
"bufferutil": "^4.0.5",
"utf-8-validate": "^5.0.7"
} }
} }

View File

@ -1,7 +1,6 @@
import http from "http"; import http from "http";
import crypto from "crypto"; import crypto from "crypto";
import Timeout = NodeJS.Timeout; import Timeout = NodeJS.Timeout;
import Prometheus from "./prometheus";
export interface Client { export interface Client {
uuid: string, uuid: string,
@ -10,7 +9,7 @@ export interface Client {
channelsAmount: number, channelsAmount: number,
send: (data: any) => void, send: (data: any) => void,
guest: boolean, guest: boolean,
ip?: string,
socket?: any, socket?: any,
} }
@ -32,8 +31,6 @@ export interface Server {
httpServer: http.Server, httpServer: http.Server,
prometheus: Prometheus,
config: { config: {
motd: string, motd: string,
httpPort: number, httpPort: number,
@ -43,7 +40,6 @@ export interface Server {
enablePolling: boolean, enablePolling: boolean,
wildcardChannel: string, wildcardChannel: string,
pollingInterval: number, pollingInterval: number,
enablePrometheus: boolean,
}, },
log: (...data: any) => void, log: (...data: any) => void,

View File

@ -9,8 +9,6 @@ import websocket from "./protocols/websocket";
import tcpsocket from "./protocols/tcpsocket"; import tcpsocket from "./protocols/tcpsocket";
import pollingsocket from "./protocols/pollingsocket"; import pollingsocket from "./protocols/pollingsocket";
import Prometheus from "./prometheus";
const config = require("../config.json"); const config = require("../config.json");
const pack = require("../package.json"); const pack = require("../package.json");
@ -32,10 +30,7 @@ function openChannel(sessionId: string, channel: string | number) {
} }
// Create channel if it does not exist // Create channel if it does not exist
if (!server.channels[channel]) { if (!server.channels[channel]) server.channels[channel] = [];
server.channels[channel] = [];
server.prometheus.openChannelsGauge.inc();
}
// Add client to channel // Add client to channel
let channelArray = server.channels[channel]; let channelArray = server.channels[channel];
@ -93,7 +88,6 @@ function closeChannel(sessionId: string, channel: string | number) {
if (channelArray.length === 0) { if (channelArray.length === 0) {
delete server.channels[channel]; delete server.channels[channel];
server.prometheus.openChannelsGauge.dec();
} }
let client: Client = server.clients[sessionId]; let client: Client = server.clients[sessionId];
@ -129,10 +123,6 @@ function transmitMessage(sessionId: string, channel: string | number, message: a
meta.channel = channel; meta.channel = channel;
meta.guest = client.guest; meta.guest = client.guest;
server.prometheus.messagesTrafficCounter.labels('incoming').inc();
server.prometheus.clientIdMessagesCounter.labels(client.uuid).inc();
server.prometheus.clientIPMessagesCounter.labels(client.ip || "localhost").inc();
// Send message to the channel // Send message to the channel
if (server.channels[channel]) { if (server.channels[channel]) {
@ -140,15 +130,12 @@ function transmitMessage(sessionId: string, channel: string | number, message: a
channelArray.forEach(recipientId => { channelArray.forEach(recipientId => {
if (recipientId === sessionId) return; if (recipientId === sessionId) return;
server.clients[recipientId]?.send({ server.clients[recipientId].send({
type: "message", type: "message",
channel: channel, channel: channel,
message: message, message: message,
meta: meta, meta: meta,
}) })
server.prometheus.messagesTrafficCounter.labels('outgoing').inc();
server.prometheus.channelMessagesCounter.labels(channel.toString()).inc();
}) })
} }
@ -157,13 +144,12 @@ function transmitMessage(sessionId: string, channel: string | number, message: a
let wildcardChannelArray = server.channels[config.wildcardChannel]; let wildcardChannelArray = server.channels[config.wildcardChannel];
if (wildcardChannelArray) { if (wildcardChannelArray) {
wildcardChannelArray.forEach(recipientId => { wildcardChannelArray.forEach(recipientId => {
server.clients[recipientId]?.send({ server.clients[recipientId].send({
type: "message", type: "message",
channel: config.wildcardChannel, channel: config.wildcardChannel,
message: message, message: message,
meta: meta, meta: meta,
}) })
server.prometheus.messagesTrafficCounter.labels('outgoing').inc();
}) })
} }
@ -196,14 +182,10 @@ function authenticateClient(sessionId: string, token: string) {
} }
function destroyClient(sessionId: string) { function destroyClient(sessionId: string) {
let client = server.clients[sessionId] let channels = server.clients[sessionId].channels;
let channels = client.channels;
for (let channelName in channels) { for (let channelName in channels) {
closeChannel(sessionId, channelName); closeChannel(sessionId, channelName);
} }
server.prometheus.clientCountGauge.dec()
server.prometheus.clientIdMessagesCounter.remove(client.uuid)
server.prometheus.clientIPMessagesCounter.remove(client.ip || "localhost")
delete server.clients[sessionId]; delete server.clients[sessionId];
} }
@ -219,8 +201,6 @@ function buildClient(send: (data: any) => void, token?: string): Client {
server.clients[client.sessionId] = client; server.clients[client.sessionId] = client;
server.prometheus.clientCountGauge.inc()
if (token) { if (token) {
authenticateClient(client.sessionId, token); authenticateClient(client.sessionId, token);
} }
@ -308,7 +288,6 @@ const server: Server = {
channels: {}, channels: {},
config: config, config: config,
httpServer: http.createServer(), httpServer: http.createServer(),
prometheus: new Prometheus(),
log: function (...data) { log: function (...data) {
console.log(...data); console.log(...data);
}, },

View File

@ -1,44 +0,0 @@
import client from "prom-client";
export default class Prometheus {
client = client;
prefix = "soqet_"
openChannelsGauge = new client.Gauge({
name: this.prefix + "open_channels",
help: "Amount of open channels"
});
clientCountGauge = new client.Gauge({
name: this.prefix + "client_count",
help: "Amount of connected clients"
})
messagesTrafficCounter = new client.Counter({
name: this.prefix + "messages_traffic",
help: "Counter of incoming and outcoming messages",
labelNames: ["side"]
})
channelMessagesCounter = new client.Counter({
name: this.prefix + "channel_messages",
help: "Amount of messages by channel",
labelNames: ["channel_name"]
});
clientIdMessagesCounter = new client.Counter({
name: this.prefix + "client_id_messages",
help: "Amount of messages by client id",
labelNames: ["client_id"]
})
clientIPMessagesCounter = new client.Counter({
name: this.prefix + "client_ip_messages",
help: "Amount of messages by client IP",
labelNames: ["client_ip"]
})
constructor() {
client.collectDefaultMetrics({ prefix: this.prefix })
}
}

View File

@ -76,7 +76,10 @@ let app = {
export default function run(srv: common.Server) { export default function run(srv: common.Server) {
server = srv; server = srv;
if (!server.config.enablePolling) {
console.log("HTTP Long Polling is disabled!");
return;
}
routers(srv, app); routers(srv, app);

View File

@ -1,34 +1,17 @@
import * as common from "../../common"; import * as common from "../../common";
import { Request, Response } from "./common"; import {Request, Response} from "./common";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
export default function routes(server: common.Server, app: any) { export default function routes(server: common.Server, app: any) {
app.get("/", function (req: Request, res: Response) { app.get("/", function(req: Request, res: Response) {
res.writeHead(302, { res.writeHead(302, {
'Location': 'index.html' 'Location': 'index.html'
}); });
res.end(); res.end();
}); });
if (server.config.enablePrometheus) {
app.get("/metrics", async function (req: Request, res: Response) {
try {
res.setHeader('Content-Type', server.prometheus.client.register.contentType);
res.end(await server.prometheus.client.register.metrics());
} catch (e: any) {
console.error(e);
res.status(500).end(e.message);
}
})
}
if (!server.config.enablePolling) {
console.log("HTTP Long Polling is disabled!");
return;
}
app.get("/api/connect", function (req: Request, res: Response) { app.get("/api/connect", function (req: Request, res: Response) {
let query = req.query; let query = req.query;
let queue: any[] = []; let queue: any[] = [];
@ -38,9 +21,6 @@ export default function routes(server: common.Server, app: any) {
} }
let client: common.PollingClient = server.buildClient(send, query.token) as common.PollingClient; let client: common.PollingClient = server.buildClient(send, query.token) as common.PollingClient;
try {
client.ip = req.headers['x-forwarded-for']?.toString() || req.socket.remoteAddress;
} catch (_) { }
client.pollingQueue = queue; client.pollingQueue = queue;
client.pollingToken = "$" + common.randomString(63); client.pollingToken = "$" + common.randomString(63);
@ -55,7 +35,7 @@ export default function routes(server: common.Server, app: any) {
}) })
}); });
// POST PATHS HERE // POST PATHS HERE
app.post("/api/send", function (req: Request, res: Response) { app.post("/api/send", function (req: Request, res: Response) {
let client = app.getClient(req, res); let client = app.getClient(req, res);

View File

@ -17,7 +17,6 @@ export default function run(server: common.Server) {
} }
let client = server.buildClient(send); let client = server.buildClient(send);
client.ip = socket.remoteAddress;
client.socket = socket; client.socket = socket;
let pingInterval = setInterval(function () { let pingInterval = setInterval(function () {
@ -49,7 +48,6 @@ export default function run(server: common.Server) {
socket.on("close", () => { socket.on("close", () => {
server.log("[TCP Close]", client.sessionId); server.log("[TCP Close]", client.sessionId);
server.destroyClient(client.sessionId)
clearInterval(pingInterval); clearInterval(pingInterval);
}) })

View File

@ -1,7 +1,5 @@
import * as common from "../common"; import * as common from "../common";
import WebSocket from "ws"; import WebSocket from "ws";
import { IncomingMessage } from "http";
import { Socket } from "net";
export default function run(server: common.Server): void { export default function run(server: common.Server): void {
if (!server.config.enableWebsocket) { if (!server.config.enableWebsocket) {
@ -18,13 +16,13 @@ export default function run(server: common.Server): void {
return; return;
} }
server.httpServer.on("upgrade", (req: IncomingMessage, socket: Socket, head: Buffer) => { server.httpServer.on("upgrade", (req: any, socket: any, head: any) => {
wss.handleUpgrade(req, socket, head, ws => { wss.handleUpgrade(req, socket, head, ws => {
wss.emit("connection", ws, req); wss.emit("connection", ws);
}) })
}); });
wss.on("connection", (ws, req) => { wss.on("connection", (ws) => {
function send (data: any) { function send (data: any) {
if (ws.readyState === WebSocket.OPEN) { if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data)); ws.send(JSON.stringify(data));
@ -33,7 +31,6 @@ export default function run(server: common.Server): void {
let client = server.buildClient(send); let client = server.buildClient(send);
client.socket = ws; client.socket = ws;
client.ip = req.headers['x-forwarded-for']?.toString() || req.socket.remoteAddress;
let pingInterval = setInterval(function () { let pingInterval = setInterval(function () {
send({ send({
@ -63,7 +60,6 @@ export default function run(server: common.Server): void {
ws.on("close", (code, reason) => { ws.on("close", (code, reason) => {
server.log("[WS Close]", client.sessionId, code, reason); server.log("[WS Close]", client.sessionId, code, reason);
server.destroyClient(client.sessionId)
clearInterval(pingInterval); clearInterval(pingInterval);
}) })