@iqai/mcp-near-agent
Version:
Mcp server for Near
190 lines โข 6.79 kB
JavaScript
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