osc-mcp-server
Version:
Model Context Protocol server for OSC (Open Sound Control) endpoint management
170 lines • 5.76 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OSCEndpoint = void 0;
exports.createOSCEndpoint = createOSCEndpoint;
const dgram_1 = require("dgram");
const events_1 = require("events");
const index_1 = require("../types/index");
const parser_1 = require("./parser");
const buffer_1 = require("./buffer");
const index_2 = require("../errors/index");
class OSCEndpoint extends events_1.EventEmitter {
id;
port;
bufferSize;
addressFilters;
createdAt;
socket = null;
status = 'stopped';
messageBuffer;
messageCount = 0;
constructor(id, config) {
super();
this.id = id;
this.port = config.port;
this.bufferSize = config.bufferSize || 1000;
this.addressFilters = config.addressFilters || [];
this.createdAt = new Date();
if (!this.isValidPort(this.port)) {
const error = index_2.NetworkErrors.portInvalid(this.port);
throw new Error(error.message);
}
const bufferConfig = {
maxSize: this.bufferSize,
addressFilters: this.addressFilters,
};
this.messageBuffer = (0, buffer_1.createMessageBuffer)(bufferConfig);
}
async startListening() {
if (this.status === 'active') {
const error = index_2.EndpointErrors.alreadyActive(this.id);
throw new Error(error.message);
}
return new Promise((resolve, reject) => {
try {
this.socket = (0, dgram_1.createSocket)('udp4');
this.socket.on('error', (error) => {
this.handleSocketError(error);
reject(error);
});
this.socket.on('message', (data, rinfo) => {
this.handleIncomingMessage(data, rinfo);
});
this.socket.bind(this.port, () => {
this.status = 'active';
this.emit('statusChange', this.status);
resolve();
});
}
catch (error) {
this.status = 'error';
this.emit('statusChange', this.status);
const startError = index_2.EndpointErrors.startFailed(this.id, error instanceof Error ? error.message : 'Unknown error');
reject(new Error(startError.message));
}
});
}
async stopListening() {
if (this.status === 'stopped') {
return;
}
return new Promise(resolve => {
if (this.socket) {
this.socket.close(() => {
this.socket = null;
this.status = 'stopped';
this.emit('statusChange', this.status);
resolve();
});
}
else {
this.status = 'stopped';
this.emit('statusChange', this.status);
resolve();
}
});
}
getStatus() {
return {
id: this.id,
port: this.port,
status: this.status,
bufferSize: this.bufferSize,
addressFilters: [...this.addressFilters],
createdAt: this.createdAt,
messageCount: this.messageCount,
};
}
getMessageBuffer() {
return this.messageBuffer;
}
getId() {
return this.id;
}
getPort() {
return this.port;
}
isActive() {
return this.status === 'active';
}
handleIncomingMessage(data, rinfo) {
try {
const parseResult = (0, parser_1.parseOSCMessage)(data, rinfo.address, rinfo.port);
if (parseResult.error) {
this.emit('error', parseResult.error);
return;
}
if (parseResult.message) {
this.messageBuffer.addMessage(parseResult.message);
this.messageCount++;
this.emit('message', parseResult.message);
}
}
catch (error) {
const oscError = {
code: index_1.ErrorCode.MESSAGE_PARSE_ERROR,
message: `Unexpected error processing message: ${error instanceof Error ? error.message : 'Unknown error'}`,
details: { originalError: error },
};
this.emit('error', oscError);
}
}
handleSocketError(error) {
this.status = 'error';
this.emit('statusChange', this.status);
let oscError;
if (error.message.includes('EADDRINUSE')) {
oscError = index_2.NetworkErrors.portInUse(this.port, this.getSuggestedPorts());
}
else if (error.message.includes('EACCES')) {
oscError = index_2.NetworkErrors.permissionDenied(this.port);
}
else {
oscError = index_2.NetworkErrors.networkError(`Network error on endpoint ${this.id}: ${error.message}`, {
originalError: error,
port: this.port,
endpointId: this.id,
});
}
this.emit('error', oscError);
}
isValidPort(port) {
return Number.isInteger(port) && port >= 1024 && port <= 65535;
}
getSuggestedPorts() {
const suggestions = [];
const basePort = this.port;
for (let i = 1; i <= 3; i++) {
const suggestedPort = basePort + i;
if (suggestedPort <= 65535) {
suggestions.push(suggestedPort);
}
}
return suggestions;
}
}
exports.OSCEndpoint = OSCEndpoint;
function createOSCEndpoint(id, config) {
return new OSCEndpoint(id, config);
}
//# sourceMappingURL=endpoint.js.map