UNPKG

node-osc

Version:

pyOSC inspired library for sending and receiving OSC messages

179 lines (173 loc) 4.9 kB
import { createSocket } from 'node:dgram'; import { EventEmitter } from 'node:events'; import { encode } from './osc.mjs'; import Message from './Message.mjs'; /** * OSC Client for sending messages and bundles over UDP. * * Extends EventEmitter and emits the following events: * - 'error': Emitted when a socket error occurs * * @class * @extends EventEmitter * @example * // Create a client * const client = new Client('127.0.0.1', 3333); * * // Send a message with callback * client.send('/oscAddress', 200, (err) => { * if (err) console.error(err); * client.close(); * }); * * @example * // Send a message with async/await * const client = new Client('127.0.0.1', 3333); * await client.send('/oscAddress', 200); * await client.close(); */ class Client extends EventEmitter { /** * Create an OSC Client. * * @param {string} host - The hostname or IP address of the OSC server. * @param {number} port - The port number of the OSC server. * * @example * const client = new Client('127.0.0.1', 3333); */ constructor(host, port) { super(); this.host = host; this.port = port; this._sock = createSocket({ type: 'udp4', reuseAddr: true }); this._sock.on('error', (err) => { this.emit('error', err); }); } /** * Close the client socket. * * This method can be used with either a callback or as a Promise. * * @param {Function} [cb] - Optional callback function called when socket is closed. * @returns {Promise<void>|undefined} Returns a Promise if no callback is provided. * * @example * // With callback * client.close((err) => { * if (err) console.error(err); * }); * * @example * // With async/await * await client.close(); */ close(cb) { if (cb) { this._sock.close(cb); } else { return new Promise((resolve, reject) => { this._sock.close((err) => { if (err) reject(err); else resolve(); }); }); } } _performSend(message, args, callback) { let mes; let buf; try { switch (typeof message) { case 'object': buf = encode(message); this._sock.send(buf, 0, buf.length, this.port, this.host, callback); break; case 'string': mes = new Message(args[0]); for (let i = 1; i < args.length; i++) { mes.append(args[i]); } buf = encode(mes); this._sock.send(buf, 0, buf.length, this.port, this.host, callback); break; default: throw new TypeError('That Message Just Doesn\'t Seem Right'); } } catch (e) { if (e.code !== 'ERR_SOCKET_DGRAM_NOT_RUNNING') throw e; const error = new ReferenceError('Cannot send message on closed socket.'); error.code = e.code; callback(error); } } /** * Send an OSC message or bundle to the server. * * This method can be used with either a callback or as a Promise. * Messages can be sent in several formats: * - As separate arguments: address followed by values * - As a Message or Bundle object * - As an array: [address, ...values] * * @param {...*} args - The message to send. Can be: * - (address: string, ...values: any[], callback?: Function) * - (message: Message|Bundle, callback?: Function) * - (array: Array, callback?: Function) * @returns {Promise<void>|undefined} Returns a Promise if no callback is provided. * * @throws {TypeError} If the message format is invalid. * @throws {ReferenceError} If attempting to send on a closed socket. * * @example * // Send with address and arguments * client.send('/oscAddress', 200, 'hello', (err) => { * if (err) console.error(err); * }); * * @example * // Send with async/await * await client.send('/oscAddress', 200, 'hello'); * * @example * // Send a Message object * const msg = new Message('/test', 1, 2, 3); * await client.send(msg); * * @example * // Send a Bundle object * const bundle = new Bundle(['/one', 1], ['/two', 2]); * await client.send(bundle); */ send(...args) { let message = args[0]; let callback; // Convert array syntax to message object if (message instanceof Array) { message = { address: message[0], args: message.slice(1) }; } if (typeof args[args.length - 1] === 'function') { callback = args.pop(); this._performSend(message, args, callback); } else { // No callback provided, return a Promise return new Promise((resolve, reject) => { callback = (err) => { if (err) reject(err); else resolve(); }; this._performSend(message, args, callback); }); } } } export default Client;