From 20e3017c64bf38a9f9e5fb6784d9917ddbb05f89 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Thu, 11 Jun 2026 18:29:00 +0300 Subject: [PATCH] add posibility to choose witch tools should used --- config.yml | 13 +++++++-- index.js | 80 +++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/config.yml b/config.yml index 20cb343..775f44c 100644 --- a/config.yml +++ b/config.yml @@ -10,12 +10,21 @@ targets: hosts: - url: http://127.0.0.1:7088 name: proxy-city + metadata: + location: Moscow + provider: CityNet + country: RU + tags: [primary, city] - url: http://127.0.0.1:7089 name: proxy-optima - + metadata: + location: Saint-Petersburg + provider: Optima + country: RU + tags: [secondary] endpoints: - /testmontools/curl - /testmontools/traceroute - /testmontools/ping - timeout: 120000 \ No newline at end of file + timeout: 120000 diff --git a/index.js b/index.js index 958529e..85dd7dd 100644 --- a/index.js +++ b/index.js @@ -12,12 +12,41 @@ const configPath = path.join(__dirname, "config.yml"); const config = yaml.load(fs.readFileSync(configPath, "utf8")); const PORT = config.server?.port || 4000; -const HOSTS = config.targets?.hosts || [{url: "http://127.0.0.1:7088", name: "my-server"}]; +const HOSTS = config.targets?.hosts || [{ url: "http://127.0.0.1:7088", name: "my-server", metadata: {} }]; const ENDPOINTS = config.targets?.endpoints || []; const TIMEOUT = config.targets?.timeout || 120_000; +// ─── Check name → endpoint suffix mapping ──────────────────────────────────── +// Allows the client to pass ["ping", "curl", "tracert"] in any casing +const CHECK_MAP = { + ping: "/testmontools/ping", + curl: "/testmontools/curl", + tracert: "/testmontools/traceroute", + traceroute: "/testmontools/traceroute", +}; + +/** + * Resolve the list of endpoints to run. + * @param {string[]} checks - e.g. ["ping", "curl"] or [] (= all) + * @returns {string[]} deduplicated endpoint paths present in ENDPOINTS + */ +function resolveEndpoints(checks) { + if (!Array.isArray(checks) || checks.length === 0) { + return ENDPOINTS; // run everything declared in config + } + + const requested = new Set( + checks + .map((c) => CHECK_MAP[c.toLowerCase().trim()]) + .filter(Boolean) + ); + + // keep only endpoints that are both requested AND declared in config + return ENDPOINTS.filter((ep) => requested.has(ep)); +} + console.log(`[config] loaded from ${configPath}`); -console.log(`[config] hosts (${HOSTS.length}):`, HOSTS); +console.log(`[config] hosts (${HOSTS.length}):`, HOSTS.map(h => `${h.name} (${h.url})`)); console.log(`[config] endpoints:`, ENDPOINTS); // ─── Express + Socket.io ────────────────────────────────────────────────────── @@ -32,7 +61,7 @@ app.use(express.json()); // ─── POST /api/parallel-fetch ───────────────────────────────────────────────── app.post("/api/parallel-fetch", async (req, res) => { - const { socketId, url, timeout = TIMEOUT } = req.body; + const { socketId, url, timeout = TIMEOUT, checks = [] } = req.body; if (!socketId || !url) { return res.status(400).json({ error: "socketId and url are required" }); @@ -43,13 +72,22 @@ app.post("/api/parallel-fetch", async (req, res) => { return res.status(400).json({ error: `Socket ${socketId} not found` }); } - res.json({ status: "started" }); + const activeEndpoints = resolveEndpoints(checks); + + if (activeEndpoints.length === 0) { + return res.status(400).json({ + error: "No valid endpoints resolved. Check 'checks' values or config endpoints.", + validCheckNames: Object.keys(CHECK_MAP), + }); + } + + res.json({ status: "started", endpoints: activeEndpoints }); const tasks = HOSTS.flatMap((host) => - ENDPOINTS.map((endpoint) => ({ host, endpoint })) + activeEndpoints.map((endpoint) => ({ host, endpoint })) ); - socket.emit("batch:start", { url, total: tasks.length }); + socket.emit("batch:start", { url, total: tasks.length, endpoints: activeEndpoints }); const promises = tasks.map(({ host, endpoint }) => { const fullUrl = host.url + endpoint; @@ -64,27 +102,31 @@ app.post("/api/parallel-fetch", async (req, res) => { }) .then((response) => { const elapsed = Date.now() - start; - console.log(`[OK] ${host} ${endpoint} (${elapsed}ms)`); + console.log(`[OK] ${host.name} ${endpoint} (${elapsed}ms)`); + socket.emit("tool:response", { - host: host.url, + host: host.url, serverName: host.name, + metadata: host.metadata ?? {}, // ← метаданные хоста endpoint, - ok: true, - status: response.status, - data: response.data, + ok: true, + status: response.status, + data: response.data, elapsed, }); }) .catch((err) => { const elapsed = Date.now() - start; - console.log(`[ERROR] ${host} ${endpoint} (${elapsed}ms) — ${err.message}`); + console.log(`[ERROR] ${host.name} ${endpoint} (${elapsed}ms) — ${err.message}`); + socket.emit("tool:error", { - host: host.url, - serverName: host.name, + host: host.url, + serverName: host.name, + metadata: host.metadata ?? {}, // ← метаданные хоста endpoint, - ok: false, - error: err.message, - code: err.code || null, + ok: false, + error: err.message, + code: err.code || null, elapsed, }); }); @@ -98,7 +140,7 @@ app.post("/api/parallel-fetch", async (req, res) => { // ─── Health ─────────────────────────────────────────────────────────────────── app.get("/health", (_req, res) => - res.json({ ok: true, hosts: HOSTS, endpoints: ENDPOINTS }) + res.json({ ok: true, hosts: HOSTS, endpoints: ENDPOINTS, checkMap: CHECK_MAP }) ); // ─── Socket lifecycle ───────────────────────────────────────────────────────── @@ -112,4 +154,4 @@ io.on("connection", (socket) => { // ─── Start ──────────────────────────────────────────────────────────────────── server.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`) -); \ No newline at end of file +);