trojanhorse-js
Version:
A comprehensive JavaScript library for fetching, managing, and analyzing global threat intelligence from multiple open-source feeds and security news sources. Unlike its mythological namesake, this Trojan protects your digital fortress.
410 lines (341 loc) • 11 kB
text/typescript
/**
* TrojanHorse.js Distributed Processing Engine
* Enterprise-grade distributed threat analysis and processing
*/
import { EventEmitter } from 'events';
import { Worker } from 'worker_threads';
import { ThreatIndicator } from '../types';
// ===== PROCESSING INTERFACES =====
export interface ProcessingConfig {
maxWorkers: number;
minWorkers: number;
queueSize: number;
taskTimeout: number;
retryAttempts: number;
scalingStrategy: 'fixed' | 'dynamic' | 'adaptive';
}
export interface Task {
id: string;
type: 'threat_analysis' | 'data_processing' | 'correlation' | 'enrichment';
priority: 'low' | 'medium' | 'high' | 'critical';
data: any;
createdAt: Date;
timeout?: number;
retries?: number;
}
export interface TaskResult {
taskId: string;
success: boolean;
result?: any;
error?: string;
processingTime: number;
workerId: string;
completedAt: Date;
}
export interface WorkerPoolConfig {
maxWorkers: number;
minWorkers: number;
workerScript: string;
taskTimeout: number;
idleTimeout: number;
autoScale: boolean;
}
// ===== WORKER POOL =====
class WorkerPool extends EventEmitter {
private config: WorkerPoolConfig;
private workers: Map<string, Worker> = new Map();
private taskQueue: Task[] = [];
private activeTasks: Map<string, Task> = new Map();
private workerStats: Map<string, any> = new Map();
constructor(config: WorkerPoolConfig) {
super();
this.config = config;
this.initializeWorkers();
}
private initializeWorkers(): void {
for (let i = 0; i < this.config.minWorkers; i++) {
this.createWorker();
}
}
private createWorker(): string {
const workerId = `worker_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
try {
const worker = new Worker(this.config.workerScript, {
workerData: { workerId }
});
worker.on('message', (message) => {
this.handleWorkerMessage(workerId, message);
});
worker.on('error', (error) => {
this.handleWorkerError(workerId, error);
});
worker.on('exit', (code) => {
this.handleWorkerExit(workerId, code);
});
this.workers.set(workerId, worker);
this.workerStats.set(workerId, {
created: new Date(),
tasksCompleted: 0,
tasksInProgress: 0,
lastActivity: new Date()
});
this.emit('worker_created', { workerId });
return workerId;
} catch (error) {
this.emit('worker_creation_failed', { workerId, error });
throw error;
}
}
private handleWorkerMessage(workerId: string, message: any): void {
const stats = this.workerStats.get(workerId);
if (stats) {
stats.lastActivity = new Date();
stats.tasksInProgress--;
stats.tasksCompleted++;
}
if (message.type === 'task_completed') {
this.handleTaskCompletion(workerId, message);
} else if (message.type === 'task_error') {
this.handleTaskError(workerId, message);
}
this.processNextTask();
}
private handleTaskCompletion(workerId: string, message: any): void {
const task = this.activeTasks.get(message.taskId);
if (task) {
const result: TaskResult = {
taskId: message.taskId,
success: true,
result: message.result,
processingTime: message.processingTime,
workerId,
completedAt: new Date()
};
this.activeTasks.delete(message.taskId);
this.emit('task_completed', result);
}
}
private handleTaskError(workerId: string, message: any): void {
const task = this.activeTasks.get(message.taskId);
if (task) {
const result: TaskResult = {
taskId: message.taskId,
success: false,
error: message.error,
processingTime: message.processingTime || 0,
workerId,
completedAt: new Date()
};
this.activeTasks.delete(message.taskId);
// Retry logic
if ((task.retries || 0) < 3) {
task.retries = (task.retries || 0) + 1;
this.addTask(task);
} else {
this.emit('task_failed', result);
}
}
}
private handleWorkerError(workerId: string, error: Error): void {
this.emit('worker_error', { workerId, error: error.message });
this.removeWorker(workerId);
// Replace failed worker if needed
if (this.workers.size < this.config.minWorkers) {
this.createWorker();
}
}
private handleWorkerExit(workerId: string, code: number): void {
this.emit('worker_exit', { workerId, exitCode: code });
this.removeWorker(workerId);
}
private removeWorker(workerId: string): void {
const worker = this.workers.get(workerId);
if (worker) {
worker.terminate();
this.workers.delete(workerId);
this.workerStats.delete(workerId);
}
}
public addTask(task: Task): void {
this.taskQueue.push(task);
this.processNextTask();
}
private processNextTask(): void {
if (this.taskQueue.length === 0) {
return;
}
const availableWorker = this.findAvailableWorker();
if (!availableWorker) {
if (this.shouldScaleUp()) {
this.scaleUp();
}
return;
}
const task = this.taskQueue.shift()!;
this.assignTaskToWorker(task, availableWorker);
}
private findAvailableWorker(): string | null {
for (const [workerId, stats] of this.workerStats) {
if (stats.tasksInProgress < 1) {
return workerId;
}
}
return null;
}
private shouldScaleUp(): boolean {
return this.workers.size < this.config.maxWorkers &&
this.taskQueue.length > this.workers.size * 2;
}
private scaleUp(): void {
if (this.workers.size < this.config.maxWorkers) {
this.createWorker();
}
}
private assignTaskToWorker(task: Task, workerId: string): void {
const worker = this.workers.get(workerId);
const stats = this.workerStats.get(workerId);
if (worker && stats) {
stats.tasksInProgress++;
this.activeTasks.set(task.id, task);
worker.postMessage({
type: 'execute_task',
task
});
// Set timeout for task
setTimeout(() => {
if (this.activeTasks.has(task.id)) {
this.handleTaskTimeout(task.id, workerId);
}
}, task.timeout || this.config.taskTimeout);
}
}
private handleTaskTimeout(taskId: string, workerId: string): void {
const task = this.activeTasks.get(taskId);
if (task) {
this.activeTasks.delete(taskId);
const result: TaskResult = {
taskId,
success: false,
error: 'Task timeout',
processingTime: task.timeout || this.config.taskTimeout,
workerId,
completedAt: new Date()
};
this.emit('task_timeout', result);
}
}
public getStats(): any {
return {
totalWorkers: this.workers.size,
queueSize: this.taskQueue.length,
activeTasks: this.activeTasks.size,
workerStats: Object.fromEntries(this.workerStats)
};
}
public async shutdown(): Promise<void> {
const shutdownPromises = Array.from(this.workers.values()).map(worker =>
worker.terminate()
);
await Promise.all(shutdownPromises);
this.workers.clear();
this.workerStats.clear();
this.activeTasks.clear();
}
}
// ===== DISTRIBUTED PROCESSOR =====
class DistributedProcessor extends EventEmitter {
private config: ProcessingConfig;
private workerPool: WorkerPool;
private taskCounter = 0;
constructor(config: ProcessingConfig) {
super();
this.config = config;
this.workerPool = new WorkerPool({
maxWorkers: config.maxWorkers,
minWorkers: config.minWorkers,
workerScript: require.resolve('./threat-analysis-worker.js'),
taskTimeout: config.taskTimeout,
idleTimeout: 60000,
autoScale: config.scalingStrategy !== 'fixed'
});
this.setupEventHandlers();
}
private setupEventHandlers(): void {
this.workerPool.on('task_completed', (result) => {
this.emit('task_completed', result);
});
this.workerPool.on('task_failed', (result) => {
this.emit('task_failed', result);
});
this.workerPool.on('worker_error', (event) => {
this.emit('worker_error', event);
});
}
public async processThreatData(threats: ThreatIndicator[]): Promise<TaskResult[]> {
const tasks = threats.map(threat => this.createTask('threat_analysis', threat));
return this.processTasks(tasks);
}
public async processCorrelation(data: any): Promise<TaskResult> {
const task = this.createTask('correlation', data, 'high');
this.workerPool.addTask(task);
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Correlation task timeout'));
}, this.config.taskTimeout);
const handler = (result: TaskResult) => {
if (result.taskId === task.id) {
clearTimeout(timeout);
this.removeListener('task_completed', handler);
this.removeListener('task_failed', handler);
if (result.success) {
resolve(result);
} else {
reject(new Error(result.error));
}
}
};
this.on('task_completed', handler);
this.on('task_failed', handler);
});
}
private async processTasks(tasks: Task[]): Promise<TaskResult[]> {
const results: TaskResult[] = [];
for (const task of tasks) {
this.workerPool.addTask(task);
}
return new Promise((resolve) => {
const handler = (result: TaskResult) => {
results.push(result);
if (results.length === tasks.length) {
this.removeListener('task_completed', handler);
this.removeListener('task_failed', handler);
resolve(results);
}
};
this.on('task_completed', handler);
this.on('task_failed', handler);
});
}
private createTask(type: Task['type'], data: any, priority: Task['priority'] = 'medium'): Task {
return {
id: `task_${++this.taskCounter}_${Date.now()}`,
type,
priority,
data,
createdAt: new Date(),
timeout: this.config.taskTimeout
};
}
public getStats(): any {
return {
config: this.config,
workerPool: this.workerPool.getStats(),
tasksCreated: this.taskCounter
};
}
public async shutdown(): Promise<void> {
await this.workerPool.shutdown();
}
}
// Export classes and types
export { DistributedProcessor, WorkerPool };