UNPKG

osc-mcp-server

Version:

Model Context Protocol server for OSC (Open Sound Control) endpoint management

227 lines 8.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OSCManager = void 0; exports.createOSCManager = createOSCManager; const events_1 = require("events"); const endpoint_1 = require("./endpoint"); const index_1 = require("../errors/index"); class OSCManager extends events_1.EventEmitter { endpoints = new Map(); nextEndpointId = 1; async createEndpoint(config) { try { const existingEndpoint = this.findEndpointByPort(config.port); if (existingEndpoint && existingEndpoint.isActive()) { const error = index_1.NetworkErrors.portInUse(config.port, this.getSuggestedPorts(config.port)); return { endpointId: '', port: config.port, status: 'error', message: error.message, }; } const endpointId = this.generateEndpointId(); const endpoint = (0, endpoint_1.createOSCEndpoint)(endpointId, config); this.setupEndpointEventHandlers(endpoint); await endpoint.startListening(); this.endpoints.set(endpointId, endpoint); const endpointInfo = endpoint.getStatus(); this.emit('endpointCreated', endpointInfo); return { endpointId, port: config.port, status: 'active', message: `OSC endpoint created successfully on port ${config.port}`, }; } catch (error) { if (error instanceof Error) { if (error.message.includes('EADDRINUSE')) { const networkError = index_1.NetworkErrors.portInUse(config.port, this.getSuggestedPorts(config.port)); return { endpointId: '', port: config.port, status: 'error', message: networkError.message, }; } else if (error.message.includes('EACCES')) { const networkError = index_1.NetworkErrors.permissionDenied(config.port); return { endpointId: '', port: config.port, status: 'error', message: networkError.message, }; } else if (error.message.includes('Invalid port')) { const networkError = index_1.NetworkErrors.portInvalid(config.port); return { endpointId: '', port: config.port, status: 'error', message: networkError.message, }; } } const operationError = index_1.OperationErrors.operationFailed('createEndpoint', error instanceof Error ? error.message : 'Unknown error'); return { endpointId: '', port: config.port, status: 'error', message: operationError.message, }; } } async stopEndpoint(endpointId) { const endpoint = this.endpoints.get(endpointId); if (!endpoint) { const error = index_1.EndpointErrors.notFound(endpointId); return { endpointId, message: error.message, }; } try { if (!endpoint.isActive()) { const error = index_1.EndpointErrors.alreadyStopped(endpointId); return { endpointId, message: error.message, }; } await endpoint.stopListening(); this.endpoints.delete(endpointId); this.emit('endpointStopped', endpointId); return { endpointId, message: `Endpoint ${endpointId} stopped successfully`, }; } catch (error) { const operationError = index_1.OperationErrors.operationFailed('stopEndpoint', error instanceof Error ? error.message : 'Unknown error'); return { endpointId, message: operationError.message, }; } } getEndpointStatus(endpointId) { if (endpointId) { const endpoint = this.endpoints.get(endpointId); if (!endpoint) { return { endpoints: [] }; } return { endpoints: [endpoint.getStatus()] }; } const endpoints = Array.from(this.endpoints.values()).map(endpoint => endpoint.getStatus()); return { endpoints }; } getMessages(endpointId, query = {}) { let allMessages = []; let totalCount = 0; if (endpointId) { const endpoint = this.endpoints.get(endpointId); if (endpoint) { const buffer = endpoint.getMessageBuffer(); allMessages = buffer.getMessages(query); totalCount = buffer.getMessageCount(); } } else { for (const endpoint of this.endpoints.values()) { const buffer = endpoint.getMessageBuffer(); const endpointMessages = buffer.getMessages(query); allMessages.push(...endpointMessages); totalCount += buffer.getMessageCount(); } allMessages.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()); if (query.limit !== undefined && query.limit > 0) { allMessages = allMessages.slice(0, query.limit); } } return { messages: allMessages, totalCount, filteredCount: allMessages.length, }; } getRecentMessages(timeWindowSeconds, endpointId, limit) { const since = new Date(Date.now() - timeWindowSeconds * 1000); const query = { since }; if (limit !== undefined) { query.limit = limit; } const response = this.getMessages(endpointId, query); return response.messages; } async shutdown() { const stopPromises = []; for (const [endpointId, endpoint] of this.endpoints) { stopPromises.push(endpoint.stopListening().catch(error => { console.error(`Error stopping endpoint ${endpointId}:`, error); })); } await Promise.all(stopPromises); this.endpoints.clear(); } getActiveEndpointCount() { return Array.from(this.endpoints.values()).filter(endpoint => endpoint.isActive()).length; } getTotalEndpointCount() { return this.endpoints.size; } isPortInUse(port) { const endpoint = this.findEndpointByPort(port); return endpoint !== null && endpoint.isActive(); } getUsedPorts() { return Array.from(this.endpoints.values()) .filter(endpoint => endpoint.isActive()) .map(endpoint => endpoint.getPort()); } findEndpointByPort(port) { for (const endpoint of this.endpoints.values()) { if (endpoint.getPort() === port) { return endpoint; } } return null; } generateEndpointId() { const id = `endpoint-${this.nextEndpointId}`; this.nextEndpointId++; return id; } getSuggestedPorts(requestedPort) { const suggestions = []; const usedPorts = this.getUsedPorts(); let candidate = requestedPort + 1; while (suggestions.length < 3 && candidate <= 65535) { if (!usedPorts.includes(candidate)) { suggestions.push(candidate); } candidate++; } return suggestions; } setupEndpointEventHandlers(endpoint) { const endpointId = endpoint.getId(); endpoint.on('message', (message) => { this.emit('messageReceived', endpointId, message); }); endpoint.on('error', (error) => { this.emit('endpointError', endpointId, error); }); endpoint.on('statusChange', status => { if (status === 'error') { console.warn(`Endpoint ${endpointId} encountered an error and changed status to: ${status}`); } }); } } exports.OSCManager = OSCManager; function createOSCManager() { return new OSCManager(); } //# sourceMappingURL=manager.js.map