UNPKG

rjweb-server

Version:

Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS

166 lines (165 loc) 5.73 kB
import parseURL from "../parseURL"; import { getFilesRecursively } from "rjutils-collection"; import { getPreviousHours } from "../../classes/dataStat"; import Path from "../../classes/path"; import { Readable } from "stream"; import { Version } from "../../index"; import fs from "fs/promises"; import os from "os"; const dashboardIndexRoute = (ctg) => ({ type: "http", method: "GET", path: new Path("GET", "/"), onRequest: async (ctr) => await statsRoute(ctr, ctg, "http"), data: { validations: [], headers: {} }, context: { data: {}, keep: true } }); const dashboardWsRoute = (ctg) => ({ type: "websocket", path: new Path("GET", "/"), onConnect: async (ctr) => await statsRoute(ctr, ctg, "socket"), data: { validations: [], headers: {} }, context: { data: {}, keep: true } }); const hashCode = (value) => { return value.split("").reduce((a, b) => { a = (a << 5) - a + b.charCodeAt(0); return a & a; }, 0).toString(16).replace("-", "M"); }; const runStats = async (ctg) => { const date = /* @__PURE__ */ new Date(); const startTime = date.getTime(); const startUsage = process.cpuUsage(); const previousHours = getPreviousHours(); const staticFiles = await new Promise(async (resolve) => { let staticFiles2 = 0; for (let staticNumber = 0; staticNumber < ctg.routes.static.length; staticNumber++) { staticFiles2 += (await getFilesRecursively(ctg.routes.static[staticNumber].location, true)).length; } resolve(staticFiles2); }); const cpuUsage = await new Promise((resolve) => setTimeout(() => { const currentUsage = process.cpuUsage(startUsage); const currentTime = (/* @__PURE__ */ new Date()).getTime(); const timeDelta = (currentTime - startTime) * 5 * coreCount; resolve((currentUsage.system + currentUsage.user) / timeDelta); }, 500)); return { requests: { total: ctg.requests.stats.total, perSecond: ctg.requests.stats.perSecond, hours: Array.from({ length: 5 }, (value, index) => ({ hour: previousHours[index], amount: ctg.requests.stats[previousHours[index]] })) }, webSockets: { opened: { total: ctg.webSockets.opened.stats.total, perSecond: ctg.webSockets.opened.stats.perSecond, hours: Array.from({ length: 5 }, (value, index) => ({ hour: previousHours[index], amount: ctg.webSockets.opened.stats[previousHours[index]] })) }, messages: { incoming: { total: ctg.webSockets.messages.incoming.stats.total, perSecond: ctg.webSockets.messages.incoming.stats.perSecond, hours: Array.from({ length: 5 }, (value, index) => ({ hour: previousHours[index], amount: ctg.webSockets.messages.incoming.stats[previousHours[index]] })) }, outgoing: { total: ctg.webSockets.messages.outgoing.stats.total, perSecond: ctg.webSockets.messages.outgoing.stats.perSecond, hours: Array.from({ length: 5 }, (value, index) => ({ hour: previousHours[index], amount: ctg.webSockets.messages.outgoing.stats[previousHours[index]] })) } } }, data: { incoming: { total: ctg.data.incoming.stats.total, perSecond: ctg.data.incoming.stats.perSecond, hours: Array.from({ length: 5 }, (value, index) => ({ hour: previousHours[index], amount: ctg.data.incoming.stats[previousHours[index]] })) }, outgoing: { total: ctg.data.outgoing.stats.total, perSecond: ctg.data.outgoing.stats.perSecond, hours: Array.from({ length: 5 }, (value, index) => ({ hour: previousHours[index], amount: ctg.data.outgoing.stats[previousHours[index]] })) } }, cpu: { time: `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`, usage: cpuUsage.toFixed(2) }, memory: { time: `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`, usage: process.memoryUsage().heapUsed + process.memoryUsage().external }, routes: { user: ctg.routes.normal.length + ctg.routes.websocket.length, automatic: ctg.routes.htmlBuilder.length }, staticFiles, internalLogs: ctg.logger["logs"], middlewares: ctg.middlewares.length, cached: ctg.cache.files.objectCount + ctg.cache.middlewares.objectCount + ctg.cache.routes.objectCount }; }; const coreCount = os.cpus().length; async function statsRoute(ctr, ctg, type) { switch (type) { case "http": { if (ctr.type !== "http") return; const dashboard = (await fs.readFile(`${__dirname}/dashboard.html`, "utf8")).replaceAll("/rjweb-dashboard", parseURL(ctg.options.dashboard.path).path).replace("1.1.1", Version); ctr.headers.set("content-type", "text/html"); return ctr.print(dashboard); } case "socket": { if (ctr.type !== "connect") return; if (ctg.options.dashboard.password && ctr.queries.get("password") !== hashCode(ctg.options.dashboard.password)) return ctr.close(1, { error: "password" }); let interval = null; ctr.printStream((() => { const readable = new Readable({ objectMode: true, read() { }, destroy() { clearInterval(interval); } }); interval = setInterval(() => readable.push(runStats(ctg)), ctg.options.dashboard.updateInterval); setImmediate(() => readable.push(runStats(ctg))); return readable; })()); } } } export { dashboardIndexRoute, dashboardWsRoute, statsRoute as default };