UNPKG

cs2inspects

Version:

openskindb inspect sdk with bulk processing capabilities

233 lines (221 loc) 8.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.workerManager = exports.WorkerManager = void 0; const worker_threads_1 = require("worker_threads"); const events_1 = require("events"); const stats_1 = require("./stats"); class WorkerManager extends events_1.EventEmitter { workers = new Map(); workerStats = new Map(); workerEnabled; maxWorkers; currentWorkerIndex = 0; constructor(workerEnabled = false, maxWorkers = 4) { super(); this.workerEnabled = workerEnabled; this.maxWorkers = maxWorkers; } async init() { if (!this.workerEnabled) { return; } for (let i = 0; i < this.maxWorkers; i++) { await this.createWorker(`worker-${i}`); } } async createWorker(id) { if (!this.workerEnabled) { return; } try { const workerScript = ` const { parentPort } = require('worker_threads'); const { request } = require('undici'); const API_BASE_URL = "https://inspect.openskindb.com/"; async function processInspection(inspectUrl) { try { const encodedUrl = encodeURIComponent(inspectUrl); const apiUrl = \`\${API_BASE_URL}?url=\${encodedUrl}\`; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 30000); const { statusCode, body } = await request(apiUrl, { method: "GET", headers: { "User-Agent": "cs2inspects/1.0.0", "Accept": "application/json", }, signal: controller.signal, }); clearTimeout(timeoutId); const data = await body.json(); if (statusCode === 200 && data && data.iteminfo) { return { success: true, data }; } return { success: false, error: data?.message || data?.error || \`Request failed with status \${statusCode}\` }; } catch (error) { return { success: false, error: error.message || "Unknown error occurred" }; } } parentPort.on('message', async (message) => { const { type, data, id } = message; try { switch (type) { case 'inspect': const result = await processInspection(data.url); parentPort.postMessage({ type: 'result', data: result, id }); break; case 'shutdown': process.exit(0); break; default: parentPort.postMessage({ type: 'error', error: \`Unknown message type: \${type}\`, id }); } } catch (error) { parentPort.postMessage({ type: 'error', error: error.message || "Worker error", id }); } }); parentPort.postMessage({ type: 'ready' }); `; const worker = new worker_threads_1.Worker(workerScript, { eval: true }); const stats = { id, active: true, processed: 0, errors: 0, lastActivity: Date.now(), }; worker.on("message", (response) => { this.handleWorkerMessage(id, response); }); worker.on("error", (error) => { console.error(`Worker ${id} error:`, error); stats.errors++; stats.active = false; this.emit("workerError", { id, error }); }); worker.on("exit", (code) => { if (code !== 0) { console.error(`Worker ${id} exited with code ${code}`); } stats.active = false; this.workers.delete(id); this.workerStats.delete(id); stats_1.statsManager.removeWorker(id); }); this.workers.set(id, worker); this.workerStats.set(id, stats); stats_1.statsManager.addWorker(id); } catch (error) { console.error(`Failed to create worker ${id}:`, error); } } handleWorkerMessage(workerId, response) { const stats = this.workerStats.get(workerId); if (stats) { stats.lastActivity = Date.now(); if (response.type === "result") { stats.processed++; stats_1.statsManager.updateWorker(workerId, true, false); } else if (response.type === "error") { stats.errors++; stats_1.statsManager.updateWorker(workerId, false, true); } } this.emit("workerMessage", { workerId, response }); } async processInWorker(inspectUrl) { if (!this.workerEnabled || this.workers.size === 0) { throw new Error("Workers not available"); } return new Promise((resolve, reject) => { const workerId = this.getNextWorker(); const worker = this.workers.get(workerId); if (!worker) { reject(new Error("No available workers")); return; } const messageId = `${Date.now()}-${Math.random() .toString(36) .substr(2, 9)}`; const timeout = setTimeout(() => { reject(new Error("Worker timeout")); }, 35000); const messageHandler = (response) => { if (response.id === messageId) { clearTimeout(timeout); this.off("workerMessage", messageHandler); if (response.type === "result") { resolve(response.data); } else { reject(new Error(response.error || "Worker error")); } } }; this.on("workerMessage", messageHandler); worker.postMessage({ type: "inspect", data: { url: inspectUrl }, id: messageId, }); }); } getNextWorker() { const workerIds = Array.from(this.workers.keys()); if (workerIds.length === 0) { throw new Error("No workers available"); } const workerId = workerIds[this.currentWorkerIndex]; this.currentWorkerIndex = (this.currentWorkerIndex + 1) % workerIds.length; return workerId; } getWorkerStats() { return Array.from(this.workerStats.values()); } getActiveWorkerCount() { return Array.from(this.workerStats.values()).filter((s) => s.active).length; } async shutdown() { for (const [id, worker] of this.workers) { worker.postMessage({ type: "shutdown", data: null, id: "shutdown" }); } await new Promise((resolve) => setTimeout(resolve, 1000)); for (const [id, worker] of this.workers) { await worker.terminate(); } this.workers.clear(); this.workerStats.clear(); } isEnabled() { return this.workerEnabled; } enable() { this.workerEnabled = true; } disable() { this.workerEnabled = false; } } exports.WorkerManager = WorkerManager; exports.workerManager = new WorkerManager(process.env.WORKER_ENABLED === "true", parseInt(process.env.MAX_WORKERS || "4", 10)); //# sourceMappingURL=worker.js.map