Skip to main content
Glama
operation.js7.85 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Operation = void 0; const uuid_1 = require("uuid"); const types_1 = require("./types"); const logger_1 = __importDefault(require("../utils/logger")); const timeout_util_1 = require("./timeout-util"); /** * Operation class * * Represents an asynchronous operation that can be executed, cancelled, and report progress. */ class Operation { /** * Constructor * * @param executor Function that executes the operation * @param options Operation options */ constructor(executor, options) { this.cancelablePromise = null; this.timeoutPromise = null; this.latestProgress = null; this.startTime = 0; this.endTime = 0; this.status = types_1.OperationStatus.RUNNING; this.error = null; this.logId = (0, uuid_1.v4)(); this.executor = executor; this.options = options; this.abortController = new AbortController(); } /** * Execute the operation * * @returns Promise that resolves with the operation result */ async execute() { this.startTime = Date.now(); this.status = types_1.OperationStatus.RUNNING; try { // Create a cancelable promise this.cancelablePromise = (0, timeout_util_1.createCancelablePromise)((resolve, reject, onCancel) => { // Handle cancellation onCancel(() => { this.abortController.abort(); this.status = types_1.OperationStatus.CANCELLED; this.endTime = Date.now(); logger_1.default.info(`Operation cancelled: ${this.logId}`); }); // Create a progress callback const onProgress = (progress) => { try { this.latestProgress = progress; if (this.options.onProgress) { this.options.onProgress(progress); } } catch (error) { logger_1.default.error(`Error in progress callback: ${error instanceof Error ? error.message : String(error)}`); } }; // Execute the operation this.executor({ onProgress, signal: this.abortController.signal }) .then(resolve) .catch(reject); }); // Create a timeout promise this.timeoutPromise = (0, timeout_util_1.timeout)(this.cancelablePromise, { milliseconds: this.options.timeoutMs, message: `Operation timed out after ${this.options.timeoutMs}ms` }); // Execute the operation with timeout try { this.result = await this.timeoutPromise; this.status = types_1.OperationStatus.SUCCESS; this.endTime = Date.now(); return this.createSuccessResult(); } catch (error) { // Check if the error is a timeout error if (error instanceof Error && error.message.includes('timed out')) { this.status = types_1.OperationStatus.TIMEOUT; return this.createTimeoutResult(); } // Handle other errors this.error = error instanceof Error ? error : new Error(String(error)); this.status = types_1.OperationStatus.ERROR; this.endTime = Date.now(); return this.createErrorResult(); } } catch (error) { // Handle unexpected errors this.error = error instanceof Error ? error : new Error(String(error)); this.status = types_1.OperationStatus.ERROR; this.endTime = Date.now(); return this.createErrorResult(); } } /** * Cancel the operation */ cancel() { if (this.cancelablePromise) { this.cancelablePromise.cancel(); } } /** * Get the operation result * * @returns Operation result */ getResult() { switch (this.status) { case types_1.OperationStatus.SUCCESS: return this.createSuccessResult(); case types_1.OperationStatus.ERROR: return this.createErrorResult(); case types_1.OperationStatus.TIMEOUT: return this.createTimeoutResult(); case types_1.OperationStatus.CANCELLED: return this.createCancelledResult(); case types_1.OperationStatus.RUNNING: default: return this.createRunningResult(); } } /** * Get the operation log ID * * @returns Operation log ID */ getLogId() { return this.logId; } /** * Get the operation status * * @returns Operation status */ getStatus() { return this.status; } /** * Check if the operation is complete * * @returns True if the operation is complete, false otherwise */ isComplete() { return this.status !== types_1.OperationStatus.RUNNING; } /** * Get the latest progress * * @returns Latest progress */ getLatestProgress() { return this.latestProgress; } /** * Create a success result * * @returns Success result */ createSuccessResult() { return { status: types_1.OperationStatus.SUCCESS, logId: this.logId, result: this.result, isComplete: true, startTime: this.startTime, endTime: this.endTime, message: 'Operation completed successfully' }; } /** * Create an error result * * @returns Error result */ createErrorResult() { return { status: types_1.OperationStatus.ERROR, logId: this.logId, error: this.error?.message || 'Unknown error', isComplete: true, startTime: this.startTime, endTime: this.endTime }; } /** * Create a timeout result * * @returns Timeout result */ createTimeoutResult() { return { status: types_1.OperationStatus.TIMEOUT, logId: this.logId, partialResult: this.latestProgress, isComplete: false, startTime: this.startTime, message: `Operation timed out after ${this.options.timeoutMs}ms, but is still running in the background` }; } /** * Create a cancelled result * * @returns Cancelled result */ createCancelledResult() { return { status: types_1.OperationStatus.CANCELLED, logId: this.logId, partialResult: this.latestProgress, isComplete: true, startTime: this.startTime, endTime: this.endTime, message: 'Operation was cancelled' }; } /** * Create a running result * * @returns Running result */ createRunningResult() { return { status: types_1.OperationStatus.RUNNING, logId: this.logId, partialResult: this.latestProgress, isComplete: false, startTime: this.startTime, message: 'Operation is still running' }; } } exports.Operation = Operation;

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/TSavo/Unity-MCP'

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