UNPKG

@iqai/mcp-near-agent

Version:
190 lines โ€ข 6.79 kB
export class SubscriptionManager { static instance; subscriptions = new Map(); DEFAULT_CRON_EXPRESSION = "*/10 * * * * *"; DEFAULT_RESPONSE_METHOD = "agent_response"; DEFAULT_RESPONSE_PARAMETER_NAME = "response"; constructor() { } /** * Get singleton instance of SubscriptionManager */ static getInstance() { if (!SubscriptionManager.instance) { SubscriptionManager.instance = new SubscriptionManager(); } return SubscriptionManager.instance; } /** * Subscribe to a new event */ subscribe(config) { const subscriptionId = this.generateSubscriptionId(config.contractId, config.eventName); if (this.subscriptions.has(subscriptionId)) { throw new Error(`Already subscribed to event '${config.eventName}' on contract '${config.contractId}'`); } const subscription = { id: subscriptionId, contractId: config.contractId, eventName: config.eventName, responseMethodName: config.responseMethodName || this.DEFAULT_RESPONSE_METHOD, responseParameterName: config.responseParameterName || this.DEFAULT_RESPONSE_PARAMETER_NAME, cronExpression: config.cronExpression || this.DEFAULT_CRON_EXPRESSION, server: config.server, isActive: true, createdAt: Date.now(), }; this.subscriptions.set(subscriptionId, subscription); console.log(`๐Ÿ“ Subscribed to event '${config.eventName}' on contract '${config.contractId}'`); return subscription; } /** * Unsubscribe from an event */ unsubscribe(contractId, eventName) { const subscriptionId = this.generateSubscriptionId(contractId, eventName); const subscription = this.subscriptions.get(subscriptionId); if (!subscription) { return false; } // Stop the cron job if it exists if (subscription.cronJob) { subscription.cronJob.stop(); subscription.cronJob.destroy(); } this.subscriptions.delete(subscriptionId); console.log(`๐Ÿ—‘๏ธ Unsubscribed from event '${eventName}' on contract '${contractId}'`); return true; } /** * Check if a subscription exists */ hasSubscription(contractId, eventName) { const subscriptionId = this.generateSubscriptionId(contractId, eventName); return this.subscriptions.has(subscriptionId); } /** * Get a specific subscription */ getSubscription(contractId, eventName) { const subscriptionId = this.generateSubscriptionId(contractId, eventName); return this.subscriptions.get(subscriptionId); } /** * Get all active subscriptions */ getActiveSubscriptions() { return Array.from(this.subscriptions.values()).filter((sub) => sub.isActive); } /** * Get all subscriptions for a specific contract */ getSubscriptionsByContract(contractId) { return Array.from(this.subscriptions.values()).filter((sub) => sub.contractId === contractId && sub.isActive); } /** * Update subscription's cron job */ updateCronJob(contractId, eventName, cronJob) { const subscription = this.getSubscription(contractId, eventName); if (!subscription) { return false; } // Stop existing cron job if it exists if (subscription.cronJob) { subscription.cronJob.stop(); subscription.cronJob.destroy(); } subscription.cronJob = cronJob; return true; } /** * Mark subscription as having received an event */ markEventReceived(contractId, eventName) { const subscription = this.getSubscription(contractId, eventName); if (subscription) { subscription.lastEventAt = Date.now(); } } /** * Pause a subscription (keeps it in memory but marks as inactive) */ pauseSubscription(contractId, eventName) { const subscription = this.getSubscription(contractId, eventName); if (!subscription) { return false; } subscription.isActive = false; // Stop the cron job but don't destroy the subscription if (subscription.cronJob) { subscription.cronJob.stop(); } console.log(`โธ๏ธ Paused subscription for event '${eventName}' on contract '${contractId}'`); return true; } /** * Resume a paused subscription */ resumeSubscription(contractId, eventName) { const subscription = this.getSubscription(contractId, eventName); if (!subscription) { return false; } subscription.isActive = true; // Restart the cron job if it exists if (subscription.cronJob) { subscription.cronJob.start(); } console.log(`โ–ถ๏ธ Resumed subscription for event '${eventName}' on contract '${contractId}'`); return true; } /** * Get subscription statistics */ getStats() { const allSubs = Array.from(this.subscriptions.values()); const activeSubs = allSubs.filter((sub) => sub.isActive); const contractCounts = new Map(); for (const sub of allSubs) { contractCounts.set(sub.contractId, (contractCounts.get(sub.contractId) || 0) + 1); } return { total: allSubs.length, active: activeSubs.length, paused: allSubs.length - activeSubs.length, contractCounts: Object.fromEntries(contractCounts), oldestSubscription: allSubs.length > 0 ? Math.min(...allSubs.map((s) => s.createdAt)) : null, }; } /** * Clean up all subscriptions (useful for shutdown) */ cleanup() { console.log(`๐Ÿงน Cleaning up ${this.subscriptions.size} subscriptions...`); for (const subscription of this.subscriptions.values()) { if (subscription.cronJob) { subscription.cronJob.stop(); subscription.cronJob.destroy(); } } this.subscriptions.clear(); console.log("โœ… All subscriptions cleaned up"); } /** * Generate a unique subscription ID */ generateSubscriptionId(contractId, eventName) { return `${contractId}:${eventName}`; } /** * Get all subscription IDs (useful for debugging) */ getSubscriptionIds() { return Array.from(this.subscriptions.keys()); } } // Export singleton instance export const subscriptionManager = SubscriptionManager.getInstance(); //# sourceMappingURL=subscription-manager.js.map