add support of config.yml
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-05-25 16:24:54 +03:00
parent cc506c94e9
commit a18e24c594
4 changed files with 70 additions and 34 deletions
+2 -1
View File
@@ -1 +1,2 @@
node_modules/ node_modules/
config.yml
+49 -32
View File
@@ -1,21 +1,38 @@
const fs = require("fs");
const path = require("path");
const yaml = require("js-yaml");
const express = require("express"); const express = require("express");
const http = require("http"); const http = require("http");
const { Server } = require("socket.io"); const { Server } = require("socket.io");
const cors = require("cors"); const cors = require("cors");
const axios = require("axios"); const axios = require("axios");
const app = express(); // ─── Config ───────────────────────────────────────────────────────────────────
const server = http.createServer(app); const configPath = path.join(__dirname, "config.yml");
const config = yaml.load(fs.readFileSync(configPath, "utf8"));
const io = new Server(server, { const PORT = config.server?.port || 4000;
const HOSTS = config.targets?.hosts || ["http://127.0.0.1:7088"];
const ENDPOINTS = config.targets?.endpoints || [];
const TIMEOUT = config.targets?.timeout || 120_000;
console.log(`[config] loaded from ${configPath}`);
console.log(`[config] hosts (${HOSTS.length}):`, HOSTS);
console.log(`[config] endpoints:`, ENDPOINTS);
// ─── Express + Socket.io ──────────────────────────────────────────────────────
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: { origin: "*", methods: ["GET", "POST"] }, cors: { origin: "*", methods: ["GET", "POST"] },
}); });
app.use(cors()); app.use(cors());
app.use(express.json()); app.use(express.json());
// ─── POST /api/parallel-fetch ─────────────────────────────────────────────────
app.post("/api/parallel-fetch", async (req, res) => { app.post("/api/parallel-fetch", async (req, res) => {
const { socketId, url, timeout = 120_000 } = req.body; const { socketId, url, timeout = TIMEOUT } = req.body;
if (!socketId || !url) { if (!socketId || !url) {
return res.status(400).json({ error: "socketId and url are required" }); return res.status(400).json({ error: "socketId and url are required" });
@@ -28,19 +45,15 @@ app.post("/api/parallel-fetch", async (req, res) => {
res.json({ status: "started" }); res.json({ status: "started" });
const baseUrl = "http://127.0.0.1:7088"; const tasks = HOSTS.flatMap((host) =>
const endpoints = [ ENDPOINTS.map((endpoint) => ({ host, endpoint }))
"/testmontools/curl", );
"/testmontools/traceroute",
"/testmontools/ping",
];
// Сообщаем клиенту сколько запросов будет socket.emit("batch:start", { url, total: tasks.length });
socket.emit("batch:start", { url, total: endpoints.length });
const localTasks = endpoints.map((endpoint) => { const promises = tasks.map(({ host, endpoint }) => {
const fullUrl = baseUrl + endpoint; const fullUrl = host + endpoint;
const start = Date.now(); const start = Date.now();
return axios({ return axios({
method: "POST", method: "POST",
@@ -51,11 +64,9 @@ app.post("/api/parallel-fetch", async (req, res) => {
}) })
.then((response) => { .then((response) => {
const elapsed = Date.now() - start; const elapsed = Date.now() - start;
console.log(`[OK] ${endpoint} (${elapsed}ms)`); console.log(`[OK] ${host} ${endpoint} (${elapsed}ms)`);
console.log("data:", response.data);
socket.emit("tool:response", { socket.emit("tool:response", {
endpoint, host, endpoint,
ok: true, ok: true,
status: response.status, status: response.status,
data: response.data, data: response.data,
@@ -64,10 +75,9 @@ app.post("/api/parallel-fetch", async (req, res) => {
}) })
.catch((err) => { .catch((err) => {
const elapsed = Date.now() - start; const elapsed = Date.now() - start;
console.log(`[ERROR] ${endpoint} (${elapsed}ms) — ${err.message}`); console.log(`[ERROR] ${host} ${endpoint} (${elapsed}ms) — ${err.message}`);
socket.emit("tool:error", { socket.emit("tool:error", {
endpoint, host, endpoint,
ok: false, ok: false,
error: err.message, error: err.message,
code: err.code || null, code: err.code || null,
@@ -76,19 +86,26 @@ app.post("/api/parallel-fetch", async (req, res) => {
}); });
}); });
// Когда все завершились — шлём финальное событие Promise.allSettled(promises).then(() => {
Promise.allSettled(localTasks).then(() => {
console.log("=== ALL DONE ==="); console.log("=== ALL DONE ===");
socket.emit("batch:done", { url, total: endpoints.length }); socket.emit("batch:done", { url, total: tasks.length });
}); });
}); });
app.get("/health", (_req, res) => res.json({ ok: true })); // ─── Health ───────────────────────────────────────────────────────────────────
app.get("/health", (_req, res) =>
res.json({ ok: true, hosts: HOSTS, endpoints: ENDPOINTS })
);
// ─── Socket lifecycle ─────────────────────────────────────────────────────────
io.on("connection", (socket) => { io.on("connection", (socket) => {
console.log(`[socket] connected ${socket.id}`); console.log(`[socket] connected ${socket.id}`);
socket.on("disconnect", () => console.log(`[socket] disconnected ${socket.id}`)); socket.on("disconnect", () =>
console.log(`[socket] disconnected ${socket.id}`)
);
}); });
const PORT = process.env.PORT || 4000; // ─── Start ────────────────────────────────────────────────────────────────────
server.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`)); server.listen(PORT, () =>
console.log(`Server running on http://localhost:${PORT}`)
);
+17
View File
@@ -11,6 +11,7 @@
"axios": "^1.6.0", "axios": "^1.6.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
"js-yaml": "^4.1.1",
"socket.io": "^4.6.1" "socket.io": "^4.6.1"
}, },
"devDependencies": { "devDependencies": {
@@ -103,6 +104,11 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/array-flatten": { "node_modules/array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -853,6 +859,17 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+2 -1
View File
@@ -11,7 +11,8 @@
"axios": "^1.6.0", "axios": "^1.6.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
"socket.io": "^4.6.1" "socket.io": "^4.6.1",
"js-yaml": "^4.1.1"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.0.2" "nodemon": "^3.0.2"