Skip to main content
Glama
progressTrackingService.ts4.35 kB
import { EventEmitter } from 'events'; import logger from '@src/logger/logger.js'; /** * Progress tracking service for server management operations * Provides step-by-step progress indicators with dynamic progress bars */ export interface OperationProgress { operationId: string; operationType: string; currentStep: number; totalSteps: number; stepName: string; progress: number; // 0-100 message?: string; startedAt: Date; updatedAt: Date; } export interface OperationResult { success: boolean; operationId: string; duration: number; message?: string; error?: Error; } export type OperationType = 'install' | 'update' | 'uninstall' | 'search'; export class ProgressTrackingService extends EventEmitter { private operations: Map<string, OperationProgress> = new Map(); /** * Start tracking an operation */ startOperation(operationId: string, operationType: OperationType, totalSteps: number = 5): void { const progress: OperationProgress = { operationId, operationType, currentStep: 0, totalSteps, stepName: 'Initializing...', progress: 0, startedAt: new Date(), updatedAt: new Date(), }; this.operations.set(operationId, progress); this.emit('operation-started', progress); logger.info( `🚀 ${operationType.charAt(0).toUpperCase() + operationType.slice(1)} operation started: ${operationId}`, ); } /** * Update progress for an operation */ updateProgress(operationId: string, currentStep: number, stepName: string, message?: string): void { const progress = this.operations.get(operationId); if (!progress) { logger.warn(`No progress tracked for operation: ${operationId}`); return; } const newProgress = progress.totalSteps > 0 ? Math.round((currentStep / progress.totalSteps) * 100) : 0; progress.currentStep = currentStep; progress.stepName = stepName; progress.progress = Math.max(0, Math.min(100, newProgress)); progress.message = message; progress.updatedAt = new Date(); this.emit('progress-updated', progress); const progressPercentage = Math.max(0, Math.min(100, newProgress)); const progressBarWidth = Math.floor(progressPercentage / 5); const progressBar = '█'.repeat(Math.max(0, progressBarWidth)) + '░'.repeat(Math.max(0, 20 - progressBarWidth)); logger.info(` [${progressBar}] ${progressPercentage}% - ${stepName}`); } /** * Complete an operation */ completeOperation(operationId: string, result?: OperationResult): void { const progress = this.operations.get(operationId); if (!progress) { logger.warn(`No progress tracked for operation: ${operationId}`); return; } const duration = new Date().getTime() - progress.startedAt.getTime(); const operationResult: OperationResult = { success: true, operationId, duration, ...result, }; this.emit('operation-completed', operationResult); this.operations.delete(operationId); logger.info(`✅ Operation completed in ${duration}ms: ${operationId}`); } /** * Fail an operation */ failOperation(operationId: string, error: Error): void { const progress = this.operations.get(operationId); if (!progress) { logger.warn(`No progress tracked for operation: ${operationId}`); return; } const duration = new Date().getTime() - progress.startedAt.getTime(); const operationResult: OperationResult = { success: false, operationId, duration, error, message: error.message, }; this.emit('operation-failed', operationResult); this.operations.delete(operationId); logger.error(`❌ Operation failed after ${duration}ms: ${operationId} - ${error.message}`); } /** * Get operation status */ getOperationStatus(operationId: string): OperationProgress | undefined { return this.operations.get(operationId); } } /** * Singleton instance of progress tracking service */ let progressTrackingServiceInstance: ProgressTrackingService | null = null; export function getProgressTrackingService(): ProgressTrackingService { if (!progressTrackingServiceInstance) { progressTrackingServiceInstance = new ProgressTrackingService(); } return progressTrackingServiceInstance; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/1mcp-app/agent'

If you have feedback or need assistance with the MCP directory API, please join our Discord server