Initial commit of my folder
This commit is contained in:
92
backend/node_modules/node-osc/dist/lib/Bundle.js
generated
vendored
Normal file
92
backend/node_modules/node-osc/dist/lib/Bundle.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
var Message = require('./Message.js');
|
||||
|
||||
/**
|
||||
* Convert array notation to Message object.
|
||||
* @private
|
||||
* @param {Array|Message|Bundle} element - The element to sanitize.
|
||||
* @returns {Message|Bundle} The sanitized element.
|
||||
*/
|
||||
function sanitize(element) {
|
||||
if (element instanceof Array) element = new Message(element[0], ...element.slice(1));
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an OSC bundle containing multiple messages or nested bundles.
|
||||
*
|
||||
* OSC bundles allow multiple messages to be sent together, optionally with
|
||||
* a timetag indicating when the bundle should be processed.
|
||||
*
|
||||
* @class
|
||||
*
|
||||
* @example
|
||||
* // Create a bundle without a timetag
|
||||
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
||||
*
|
||||
* @example
|
||||
* // Create a bundle with a timetag
|
||||
* const bundle = new Bundle(10, ['/one', 1], ['/two', 2]);
|
||||
*
|
||||
* @example
|
||||
* // Nest bundles
|
||||
* const bundle1 = new Bundle(['/one', 1]);
|
||||
* const bundle2 = new Bundle(['/two', 2]);
|
||||
* bundle1.append(bundle2);
|
||||
*/
|
||||
class Bundle {
|
||||
/**
|
||||
* Create an OSC Bundle.
|
||||
*
|
||||
* @param {number|Message|Bundle|Array} [timetagOrElement=0] - Timetag, or if not a number, the first element and timetag will default to 0.
|
||||
* @param {...(Message|Bundle|Array)} elements - Messages or bundles to include.
|
||||
* Arrays will be automatically converted to Message objects.
|
||||
*
|
||||
* @example
|
||||
* // Bundle without timetag
|
||||
* const bundle = new Bundle(['/test', 1], ['/test2', 2]);
|
||||
*
|
||||
* @example
|
||||
* // Bundle with timetag of 10
|
||||
* const bundle = new Bundle(10, ['/test', 1]);
|
||||
*
|
||||
* @example
|
||||
* // Bundle with Message objects
|
||||
* const msg1 = new Message('/one', 1);
|
||||
* const msg2 = new Message('/two', 2);
|
||||
* const bundle = new Bundle(msg1, msg2);
|
||||
*/
|
||||
constructor(timetag, ...elements) {
|
||||
if (!(typeof timetag === 'number')) {
|
||||
elements.unshift(timetag);
|
||||
timetag = 0;
|
||||
}
|
||||
this.oscType = 'bundle';
|
||||
this.timetag = timetag;
|
||||
this.elements = elements.map(sanitize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a message or bundle to this bundle.
|
||||
*
|
||||
* @param {Message|Bundle|Array} element - The message or bundle to append.
|
||||
* Arrays will be automatically converted to Message objects.
|
||||
*
|
||||
* @example
|
||||
* const bundle = new Bundle();
|
||||
* bundle.append(['/test', 1]);
|
||||
* bundle.append(new Message('/test2', 2));
|
||||
*
|
||||
* @example
|
||||
* // Append a nested bundle
|
||||
* const bundle1 = new Bundle(['/one', 1]);
|
||||
* const bundle2 = new Bundle(['/two', 2]);
|
||||
* bundle1.append(bundle2);
|
||||
*/
|
||||
append(element) {
|
||||
this.elements.push(sanitize(element));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Bundle;
|
||||
180
backend/node_modules/node-osc/dist/lib/Client.js
generated
vendored
Normal file
180
backend/node_modules/node-osc/dist/lib/Client.js
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
'use strict';
|
||||
|
||||
var node_dgram = require('node:dgram');
|
||||
var node_events = require('node:events');
|
||||
var osc = require('./osc.js');
|
||||
var Message = require('./Message.js');
|
||||
|
||||
/**
|
||||
* 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 node_events.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 = node_dgram.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 = osc.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 = osc.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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Client;
|
||||
145
backend/node_modules/node-osc/dist/lib/Message.js
generated
vendored
Normal file
145
backend/node_modules/node-osc/dist/lib/Message.js
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
'use strict';
|
||||
|
||||
const typeTags = {
|
||||
s: 'string',
|
||||
f: 'float',
|
||||
i: 'integer',
|
||||
b: 'blob',
|
||||
m: 'midi'
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a typed argument for an OSC message.
|
||||
*
|
||||
* @class
|
||||
* @private
|
||||
*/
|
||||
class Argument {
|
||||
/**
|
||||
* @param {string} type - The type of the argument (string, float, integer, blob, boolean).
|
||||
* @param {*} value - The value of the argument.
|
||||
*/
|
||||
constructor(type, value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an OSC message with an address and arguments.
|
||||
*
|
||||
* OSC messages consist of an address pattern (string starting with '/')
|
||||
* and zero or more arguments of various types.
|
||||
*
|
||||
* @class
|
||||
*
|
||||
* @example
|
||||
* // Create a message with constructor arguments
|
||||
* const msg = new Message('/test', 1, 2, 'hello');
|
||||
*
|
||||
* @example
|
||||
* // Create a message and append arguments
|
||||
* const msg = new Message('/test');
|
||||
* msg.append(1);
|
||||
* msg.append('hello');
|
||||
* msg.append(3.14);
|
||||
*/
|
||||
class Message {
|
||||
/**
|
||||
* Create an OSC Message.
|
||||
*
|
||||
* @param {string} address - The OSC address pattern (e.g., '/oscillator/frequency').
|
||||
* @param {...*} args - Optional arguments to include in the message.
|
||||
*
|
||||
* @example
|
||||
* const msg = new Message('/test');
|
||||
*
|
||||
* @example
|
||||
* const msg = new Message('/test', 1, 2, 3);
|
||||
*
|
||||
* @example
|
||||
* const msg = new Message('/synth', 'note', 60, 0.5);
|
||||
*/
|
||||
constructor(address, ...args) {
|
||||
this.oscType = 'message';
|
||||
this.address = address;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an argument to the message.
|
||||
*
|
||||
* Automatically detects the type based on the JavaScript type:
|
||||
* - Integers are encoded as OSC integers
|
||||
* - Floats are encoded as OSC floats
|
||||
* - Strings are encoded as OSC strings
|
||||
* - Booleans are encoded as OSC booleans
|
||||
* - Buffers are encoded as OSC blobs
|
||||
* - Arrays are recursively appended
|
||||
* - Objects with a 'type' property are used as-is
|
||||
*
|
||||
* @param {*} arg - The argument to append. Can be:
|
||||
* - A primitive value (number, string, boolean)
|
||||
* - A Buffer (encoded as blob)
|
||||
* - An array of values (will be recursively appended)
|
||||
* - An object with 'type' and 'value' properties for explicit type control
|
||||
*
|
||||
* @throws {Error} If the argument type cannot be encoded.
|
||||
*
|
||||
* @example
|
||||
* const msg = new Message('/test');
|
||||
* msg.append(42); // Integer
|
||||
* msg.append(3.14); // Float
|
||||
* msg.append('hello'); // String
|
||||
* msg.append(true); // Boolean
|
||||
*
|
||||
* @example
|
||||
* // Append multiple values at once
|
||||
* msg.append([1, 2, 3]);
|
||||
*
|
||||
* @example
|
||||
* // Explicitly specify type
|
||||
* msg.append({ type: 'float', value: 42 });
|
||||
* msg.append({ type: 'blob', value: Buffer.from('data') });
|
||||
*
|
||||
* @example
|
||||
* // MIDI messages (4 bytes: port, status, data1, data2)
|
||||
* msg.append({ type: 'midi', value: { port: 0, status: 144, data1: 60, data2: 127 } });
|
||||
* msg.append({ type: 'm', value: Buffer.from([0, 144, 60, 127]) });
|
||||
*/
|
||||
append(arg) {
|
||||
let argOut;
|
||||
switch (typeof arg) {
|
||||
case 'object':
|
||||
if (Buffer.isBuffer(arg)) {
|
||||
this.args.push(arg);
|
||||
} else if (arg instanceof Array) {
|
||||
arg.forEach(a => this.append(a));
|
||||
} else if (arg.type) {
|
||||
if (typeTags[arg.type]) arg.type = typeTags[arg.type];
|
||||
this.args.push(arg);
|
||||
} else {
|
||||
throw new Error(`don't know how to encode object ${arg}`);
|
||||
}
|
||||
break;
|
||||
case 'number':
|
||||
if (Math.floor(arg) === arg) {
|
||||
argOut = new Argument('integer', arg);
|
||||
} else {
|
||||
argOut = new Argument('float', arg);
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
argOut = new Argument('string', arg);
|
||||
break;
|
||||
case 'boolean':
|
||||
argOut = new Argument('boolean', arg);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`don't know how to encode ${arg}`);
|
||||
}
|
||||
if (argOut) this.args.push(argOut);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Message;
|
||||
156
backend/node_modules/node-osc/dist/lib/Server.js
generated
vendored
Normal file
156
backend/node_modules/node-osc/dist/lib/Server.js
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
'use strict';
|
||||
|
||||
var node_dgram = require('node:dgram');
|
||||
var node_events = require('node:events');
|
||||
var decode = require('#decode');
|
||||
|
||||
/**
|
||||
* OSC Server for receiving messages and bundles over UDP.
|
||||
*
|
||||
* Emits the following events:
|
||||
* - 'listening': Emitted when the server starts listening
|
||||
* - 'message': Emitted when an OSC message is received (receives msg array and rinfo object)
|
||||
* - 'bundle': Emitted when an OSC bundle is received (receives bundle object and rinfo object)
|
||||
* - 'error': Emitted when a socket error or decoding error occurs (receives error and rinfo)
|
||||
* - Address-specific events: Emitted for each message address (e.g., '/test')
|
||||
*
|
||||
* @class
|
||||
* @extends EventEmitter
|
||||
*
|
||||
* @fires Server#listening
|
||||
* @fires Server#message
|
||||
* @fires Server#bundle
|
||||
* @fires Server#error
|
||||
*
|
||||
* @example
|
||||
* // Create and listen for messages
|
||||
* const server = new Server(3333, '0.0.0.0', () => {
|
||||
* console.log('Server is listening');
|
||||
* });
|
||||
*
|
||||
* server.on('message', (msg, rinfo) => {
|
||||
* console.log('Message:', msg);
|
||||
* console.log('From:', rinfo.address, rinfo.port);
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Using async/await with events.once
|
||||
* import { once } from 'node:events';
|
||||
*
|
||||
* const server = new Server(3333, '0.0.0.0');
|
||||
* await once(server, 'listening');
|
||||
*
|
||||
* server.on('message', (msg) => {
|
||||
* console.log('Message:', msg);
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Listen for specific OSC addresses
|
||||
* server.on('/note', (msg) => {
|
||||
* const [address, pitch, velocity] = msg;
|
||||
* console.log(`Note: ${pitch}, Velocity: ${velocity}`);
|
||||
* });
|
||||
*/
|
||||
class Server extends node_events.EventEmitter {
|
||||
/**
|
||||
* Create an OSC Server.
|
||||
*
|
||||
* @param {number} port - The port to listen on.
|
||||
* @param {string} [host='127.0.0.1'] - The host address to bind to. Use '0.0.0.0' to listen on all interfaces.
|
||||
* @param {Function} [cb] - Optional callback function called when server starts listening.
|
||||
*
|
||||
* @example
|
||||
* // Basic server
|
||||
* const server = new Server(3333);
|
||||
*
|
||||
* @example
|
||||
* // Server on all interfaces with callback
|
||||
* const server = new Server(3333, '0.0.0.0', () => {
|
||||
* console.log('Server started');
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Host parameter can be omitted, callback as second parameter
|
||||
* const server = new Server(3333, () => {
|
||||
* console.log('Server started on 127.0.0.1');
|
||||
* });
|
||||
*/
|
||||
constructor(port, host='127.0.0.1', cb) {
|
||||
super();
|
||||
if (typeof host === 'function') {
|
||||
cb = host;
|
||||
host = '127.0.0.1';
|
||||
}
|
||||
|
||||
let decoded;
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
this._sock = node_dgram.createSocket({
|
||||
type: 'udp4',
|
||||
reuseAddr: true
|
||||
});
|
||||
this._sock.bind(port, host);
|
||||
|
||||
// Update port and emit listening event when socket is ready
|
||||
this._sock.on('listening', () => {
|
||||
// Update port with actual bound port (important when using port 0)
|
||||
this.port = this._sock.address().port;
|
||||
this.emit('listening');
|
||||
if (cb) cb();
|
||||
});
|
||||
|
||||
this._sock.on('message', (msg, rinfo) => {
|
||||
try {
|
||||
decoded = decode(msg);
|
||||
}
|
||||
catch (e) {
|
||||
const error = new Error(`can't decode incoming message: ${e.message}`);
|
||||
this.emit('error', error, rinfo);
|
||||
return;
|
||||
}
|
||||
if (decoded.elements) {
|
||||
this.emit('bundle', decoded, rinfo);
|
||||
}
|
||||
else if (decoded) {
|
||||
this.emit('message', decoded, rinfo);
|
||||
this.emit(decoded[0], decoded, rinfo);
|
||||
}
|
||||
});
|
||||
|
||||
this._sock.on('error', (err) => {
|
||||
this.emit('error', err);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Close the server 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
|
||||
* server.close((err) => {
|
||||
* if (err) console.error(err);
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // With async/await
|
||||
* await server.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();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Server;
|
||||
16
backend/node_modules/node-osc/dist/lib/index.js
generated
vendored
Normal file
16
backend/node_modules/node-osc/dist/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var Message = require('./Message.js');
|
||||
var Bundle = require('./Bundle.js');
|
||||
var Server = require('./Server.js');
|
||||
var Client = require('./Client.js');
|
||||
var osc = require('./osc.js');
|
||||
|
||||
|
||||
|
||||
exports.Message = Message;
|
||||
exports.Bundle = Bundle;
|
||||
exports.Server = Server;
|
||||
exports.Client = Client;
|
||||
exports.decode = osc.decode;
|
||||
exports.encode = osc.encode;
|
||||
37
backend/node_modules/node-osc/dist/lib/internal/decode.js
generated
vendored
Normal file
37
backend/node_modules/node-osc/dist/lib/internal/decode.js
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
var osc = require('../osc.js');
|
||||
|
||||
function sanitizeMessage(decoded) {
|
||||
const message = [];
|
||||
message.push(decoded.address);
|
||||
const args = decoded.args ?? [];
|
||||
args.forEach(arg => {
|
||||
message.push(arg.value);
|
||||
});
|
||||
return message;
|
||||
}
|
||||
|
||||
function sanitizeBundle(decoded) {
|
||||
decoded.elements = decoded.elements.map(element => {
|
||||
if (element.oscType === 'bundle') return sanitizeBundle(element);
|
||||
else if (element.oscType === 'message') return sanitizeMessage(element);
|
||||
throw new Error('Malformed Packet');
|
||||
});
|
||||
return decoded;
|
||||
}
|
||||
|
||||
function decodeAndSanitize(data, customDecode = osc.decode) {
|
||||
const decoded = customDecode(data);
|
||||
if (decoded.oscType === 'bundle') {
|
||||
return sanitizeBundle(decoded);
|
||||
}
|
||||
else if (decoded.oscType === 'message') {
|
||||
return sanitizeMessage(decoded);
|
||||
}
|
||||
else {
|
||||
throw new Error ('Malformed Packet');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = decodeAndSanitize;
|
||||
424
backend/node_modules/node-osc/dist/lib/osc.js
generated
vendored
Normal file
424
backend/node_modules/node-osc/dist/lib/osc.js
generated
vendored
Normal file
@ -0,0 +1,424 @@
|
||||
'use strict';
|
||||
|
||||
var node_buffer = require('node:buffer');
|
||||
|
||||
// OSC 1.0 Protocol Implementation
|
||||
// Based on http://opensoundcontrol.org/spec-1_0
|
||||
|
||||
|
||||
function padString(str) {
|
||||
const nullTerminated = str + '\0';
|
||||
const byteLength = node_buffer.Buffer.byteLength(nullTerminated);
|
||||
const padding = (4 - (byteLength % 4)) % 4;
|
||||
return nullTerminated + '\0'.repeat(padding);
|
||||
}
|
||||
|
||||
function readString(buffer, offset) {
|
||||
let end = offset;
|
||||
while (end < buffer.length && buffer[end] !== 0) {
|
||||
end++;
|
||||
}
|
||||
if (end >= buffer.length) {
|
||||
throw new Error('Malformed Packet: Missing null terminator for string');
|
||||
}
|
||||
const str = buffer.subarray(offset, end).toString('utf8');
|
||||
// Find next 4-byte boundary
|
||||
const paddedLength = Math.ceil((end - offset + 1) / 4) * 4;
|
||||
return { value: str, offset: offset + paddedLength };
|
||||
}
|
||||
|
||||
function writeInt32(value) {
|
||||
const buffer = node_buffer.Buffer.alloc(4);
|
||||
buffer.writeInt32BE(value, 0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readInt32(buffer, offset) {
|
||||
if (offset + 4 > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for int32');
|
||||
}
|
||||
const value = buffer.readInt32BE(offset);
|
||||
return { value, offset: offset + 4 };
|
||||
}
|
||||
|
||||
function writeFloat32(value) {
|
||||
const buffer = node_buffer.Buffer.alloc(4);
|
||||
buffer.writeFloatBE(value, 0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readFloat32(buffer, offset) {
|
||||
if (offset + 4 > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for float32');
|
||||
}
|
||||
const value = buffer.readFloatBE(offset);
|
||||
return { value, offset: offset + 4 };
|
||||
}
|
||||
|
||||
function writeBlob(value) {
|
||||
const length = value.length;
|
||||
const lengthBuffer = writeInt32(length);
|
||||
const padding = 4 - (length % 4);
|
||||
const paddingBuffer = node_buffer.Buffer.alloc(padding === 4 ? 0 : padding);
|
||||
return node_buffer.Buffer.concat([lengthBuffer, value, paddingBuffer]);
|
||||
}
|
||||
|
||||
function readBlob(buffer, offset) {
|
||||
const lengthResult = readInt32(buffer, offset);
|
||||
const length = lengthResult.value;
|
||||
if (length < 0) {
|
||||
throw new Error('Malformed Packet: Invalid blob length');
|
||||
}
|
||||
if (lengthResult.offset + length > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for blob');
|
||||
}
|
||||
const data = buffer.subarray(lengthResult.offset, lengthResult.offset + length);
|
||||
const padding = 4 - (length % 4);
|
||||
const nextOffset = lengthResult.offset + length + (padding === 4 ? 0 : padding);
|
||||
if (nextOffset > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for blob padding');
|
||||
}
|
||||
return { value: data, offset: nextOffset };
|
||||
}
|
||||
|
||||
function writeTimeTag(value) {
|
||||
// For now, treat timetag as a double (8 bytes)
|
||||
// OSC timetag is 64-bit: 32-bit seconds since 1900, 32-bit fractional
|
||||
const buffer = node_buffer.Buffer.alloc(8);
|
||||
if (value === 0 || value === null || value === undefined) {
|
||||
// Immediate execution
|
||||
buffer.writeUInt32BE(0, 0);
|
||||
buffer.writeUInt32BE(1, 4);
|
||||
} else if (typeof value === 'number') {
|
||||
// Convert to OSC timetag format
|
||||
const seconds = Math.floor(value);
|
||||
const fraction = Math.floor((value - seconds) * 0x100000000);
|
||||
buffer.writeUInt32BE(seconds + 2208988800, 0); // Add epoch offset (1900 vs 1970)
|
||||
buffer.writeUInt32BE(fraction, 4);
|
||||
} else {
|
||||
// If not a number, write zeros (immediate execution)
|
||||
buffer.writeUInt32BE(0, 0);
|
||||
buffer.writeUInt32BE(1, 4);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readTimeTag(buffer, offset) {
|
||||
if (offset + 8 > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for timetag');
|
||||
}
|
||||
const seconds = buffer.readUInt32BE(offset);
|
||||
const fraction = buffer.readUInt32BE(offset + 4);
|
||||
|
||||
let value;
|
||||
if (seconds === 0 && fraction === 1) {
|
||||
// Immediate execution
|
||||
value = 0;
|
||||
} else {
|
||||
// Convert from OSC epoch (1900) to Unix epoch (1970)
|
||||
const unixSeconds = seconds - 2208988800;
|
||||
const fractionalSeconds = fraction / 0x100000000;
|
||||
value = unixSeconds + fractionalSeconds;
|
||||
}
|
||||
|
||||
return { value, offset: offset + 8 };
|
||||
}
|
||||
|
||||
function writeMidi(value) {
|
||||
// MIDI message is 4 bytes: port id, status byte, data1, data2
|
||||
const buffer = node_buffer.Buffer.alloc(4);
|
||||
|
||||
if (node_buffer.Buffer.isBuffer(value)) {
|
||||
if (value.length !== 4) {
|
||||
throw new Error('MIDI message must be exactly 4 bytes');
|
||||
}
|
||||
value.copy(buffer);
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// Allow object format: { port: 0, status: 144, data1: 60, data2: 127 }
|
||||
buffer.writeUInt8(value.port || 0, 0);
|
||||
buffer.writeUInt8(value.status || 0, 1);
|
||||
buffer.writeUInt8(value.data1 || 0, 2);
|
||||
buffer.writeUInt8(value.data2 || 0, 3);
|
||||
} else {
|
||||
throw new Error('MIDI value must be a 4-byte Buffer or object with port, status, data1, data2 properties');
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readMidi(buffer, offset) {
|
||||
if (offset + 4 > buffer.length) {
|
||||
throw new Error('Not enough bytes for MIDI message');
|
||||
}
|
||||
|
||||
const value = buffer.subarray(offset, offset + 4);
|
||||
return { value, offset: offset + 4 };
|
||||
}
|
||||
|
||||
function encodeArgument(arg) {
|
||||
if (typeof arg === 'object' && arg.type && arg.value !== undefined) {
|
||||
// Explicit type specification
|
||||
switch (arg.type) {
|
||||
case 'i':
|
||||
case 'integer':
|
||||
return { tag: 'i', data: writeInt32(arg.value) };
|
||||
case 'f':
|
||||
case 'float':
|
||||
return { tag: 'f', data: writeFloat32(arg.value) };
|
||||
case 's':
|
||||
case 'string':
|
||||
return { tag: 's', data: node_buffer.Buffer.from(padString(arg.value)) };
|
||||
case 'b':
|
||||
case 'blob':
|
||||
return { tag: 'b', data: writeBlob(arg.value) };
|
||||
case 'd':
|
||||
case 'double':
|
||||
// For doubles, use float for now (OSC 1.0 doesn't have double)
|
||||
return { tag: 'f', data: writeFloat32(arg.value) };
|
||||
case 'T':
|
||||
return { tag: 'T', data: node_buffer.Buffer.alloc(0) };
|
||||
case 'F':
|
||||
return { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
||||
case 'boolean':
|
||||
return arg.value ? { tag: 'T', data: node_buffer.Buffer.alloc(0) } : { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
||||
case 'm':
|
||||
case 'midi':
|
||||
return { tag: 'm', data: writeMidi(arg.value) };
|
||||
default:
|
||||
throw new Error(`Unknown argument type: ${arg.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Infer type from JavaScript type
|
||||
switch (typeof arg) {
|
||||
case 'number':
|
||||
if (Number.isInteger(arg)) {
|
||||
return { tag: 'i', data: writeInt32(arg) };
|
||||
} else {
|
||||
return { tag: 'f', data: writeFloat32(arg) };
|
||||
}
|
||||
case 'string':
|
||||
return { tag: 's', data: node_buffer.Buffer.from(padString(arg)) };
|
||||
case 'boolean':
|
||||
return arg ? { tag: 'T', data: node_buffer.Buffer.alloc(0) } : { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
||||
default:
|
||||
if (node_buffer.Buffer.isBuffer(arg)) {
|
||||
return { tag: 'b', data: writeBlob(arg) };
|
||||
}
|
||||
throw new Error(`Don't know how to encode argument: ${arg}`);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeArgument(tag, buffer, offset) {
|
||||
switch (tag) {
|
||||
case 'i':
|
||||
return readInt32(buffer, offset);
|
||||
case 'f':
|
||||
return readFloat32(buffer, offset);
|
||||
case 's':
|
||||
return readString(buffer, offset);
|
||||
case 'b':
|
||||
return readBlob(buffer, offset);
|
||||
case 'T':
|
||||
return { value: true, offset };
|
||||
case 'F':
|
||||
return { value: false, offset };
|
||||
case 'N':
|
||||
return { value: null, offset };
|
||||
case 'm':
|
||||
return readMidi(buffer, offset);
|
||||
default:
|
||||
throw new Error(`I don't understand the argument code ${tag}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an OSC message or bundle to a Buffer.
|
||||
*
|
||||
* This low-level function converts OSC messages and bundles into binary format
|
||||
* for transmission or storage. Useful for sending OSC over custom transports
|
||||
* (WebSocket, TCP, HTTP), storing to files, or implementing custom OSC routers.
|
||||
*
|
||||
* @param {Object} message - OSC message or bundle object with oscType property
|
||||
* @returns {Buffer} The encoded OSC data ready for transmission
|
||||
*
|
||||
* @example
|
||||
* // Encode a message
|
||||
* import { Message, encode } from 'node-osc';
|
||||
*
|
||||
* const message = new Message('/oscillator/frequency', 440);
|
||||
* const buffer = encode(message);
|
||||
* console.log('Encoded bytes:', buffer.length);
|
||||
*
|
||||
* @example
|
||||
* // Encode a bundle
|
||||
* import { Bundle, encode } from 'node-osc';
|
||||
*
|
||||
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
||||
* const buffer = encode(bundle);
|
||||
*
|
||||
* @example
|
||||
* // Send over WebSocket
|
||||
* const buffer = encode(message);
|
||||
* websocket.send(buffer);
|
||||
*/
|
||||
function encode(message) {
|
||||
if (message.oscType === 'bundle') {
|
||||
return encodeBundleToBuffer(message);
|
||||
} else {
|
||||
return encodeMessageToBuffer(message);
|
||||
}
|
||||
}
|
||||
|
||||
function encodeMessageToBuffer(message) {
|
||||
// OSC Message format:
|
||||
// Address pattern (padded string)
|
||||
// Type tag string (padded string starting with ,)
|
||||
// Arguments (encoded according to type tags)
|
||||
|
||||
const address = padString(message.address);
|
||||
const addressBuffer = node_buffer.Buffer.from(address);
|
||||
|
||||
const encodedArgs = message.args.map(encodeArgument);
|
||||
const typeTags = ',' + encodedArgs.map(arg => arg.tag).join('');
|
||||
const typeTagsBuffer = node_buffer.Buffer.from(padString(typeTags));
|
||||
|
||||
const argumentBuffers = encodedArgs.map(arg => arg.data);
|
||||
|
||||
return node_buffer.Buffer.concat([addressBuffer, typeTagsBuffer, ...argumentBuffers]);
|
||||
}
|
||||
|
||||
function encodeBundleToBuffer(bundle) {
|
||||
// OSC Bundle format:
|
||||
// "#bundle" (padded string)
|
||||
// Timetag (8 bytes)
|
||||
// Elements (each prefixed with size)
|
||||
|
||||
const bundleString = padString('#bundle');
|
||||
const bundleStringBuffer = node_buffer.Buffer.from(bundleString);
|
||||
|
||||
const timetagBuffer = writeTimeTag(bundle.timetag);
|
||||
|
||||
const elementBuffers = bundle.elements.map(element => {
|
||||
let elementBuffer;
|
||||
if (element.oscType === 'bundle') {
|
||||
elementBuffer = encodeBundleToBuffer(element);
|
||||
} else {
|
||||
elementBuffer = encodeMessageToBuffer(element);
|
||||
}
|
||||
const sizeBuffer = writeInt32(elementBuffer.length);
|
||||
return node_buffer.Buffer.concat([sizeBuffer, elementBuffer]);
|
||||
});
|
||||
|
||||
return node_buffer.Buffer.concat([bundleStringBuffer, timetagBuffer, ...elementBuffers]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Buffer containing OSC data into a message or bundle object.
|
||||
*
|
||||
* This low-level function parses binary OSC data back into JavaScript objects.
|
||||
* Useful for receiving OSC over custom transports, reading from files,
|
||||
* or implementing custom OSC routers.
|
||||
*
|
||||
* @param {Buffer} buffer - The Buffer containing OSC data
|
||||
* @returns {Object} The decoded OSC message or bundle. Messages have
|
||||
* {oscType: 'message', address: string, args: Array}, bundles have
|
||||
* {oscType: 'bundle', timetag: number, elements: Array}
|
||||
* @throws {Error} If the buffer contains malformed OSC data
|
||||
*
|
||||
* @example
|
||||
* // Decode received data
|
||||
* import { decode } from 'node-osc';
|
||||
*
|
||||
* const decoded = decode(buffer);
|
||||
* if (decoded.oscType === 'message') {
|
||||
* console.log('Address:', decoded.address);
|
||||
* console.log('Arguments:', decoded.args);
|
||||
* }
|
||||
*
|
||||
* @example
|
||||
* // Round-trip encode/decode
|
||||
* import { Message, encode, decode } from 'node-osc';
|
||||
*
|
||||
* const original = new Message('/test', 42, 'hello');
|
||||
* const buffer = encode(original);
|
||||
* const decoded = decode(buffer);
|
||||
* console.log(decoded.address); // '/test'
|
||||
*/
|
||||
function decode(buffer) {
|
||||
// Check if it's a bundle or message
|
||||
if (buffer.length >= 8 && buffer.subarray(0, 8).toString() === '#bundle\0') {
|
||||
return decodeBundleFromBuffer(buffer);
|
||||
} else {
|
||||
return decodeMessageFromBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeMessageFromBuffer(buffer) {
|
||||
let offset = 0;
|
||||
|
||||
// Read address pattern
|
||||
const addressResult = readString(buffer, offset);
|
||||
const address = addressResult.value;
|
||||
offset = addressResult.offset;
|
||||
|
||||
// Read type tag string
|
||||
const typeTagsResult = readString(buffer, offset);
|
||||
const typeTags = typeTagsResult.value;
|
||||
offset = typeTagsResult.offset;
|
||||
|
||||
if (!typeTags.startsWith(',')) {
|
||||
throw new Error('Malformed Packet');
|
||||
}
|
||||
|
||||
const tags = typeTags.slice(1); // Remove leading comma
|
||||
const args = [];
|
||||
|
||||
for (const tag of tags) {
|
||||
const argResult = decodeArgument(tag, buffer, offset);
|
||||
args.push({ value: argResult.value });
|
||||
offset = argResult.offset;
|
||||
}
|
||||
|
||||
return {
|
||||
oscType: 'message',
|
||||
address,
|
||||
args
|
||||
};
|
||||
}
|
||||
|
||||
function decodeBundleFromBuffer(buffer) {
|
||||
let offset = 8; // Skip "#bundle\0"
|
||||
|
||||
// Read timetag
|
||||
const timetagResult = readTimeTag(buffer, offset);
|
||||
const timetag = timetagResult.value;
|
||||
offset = timetagResult.offset;
|
||||
|
||||
const elements = [];
|
||||
|
||||
while (offset < buffer.length) {
|
||||
// Read element size
|
||||
const sizeResult = readInt32(buffer, offset);
|
||||
const size = sizeResult.value;
|
||||
offset = sizeResult.offset;
|
||||
if (size <= 0 || offset + size > buffer.length) {
|
||||
throw new Error('Malformed Packet');
|
||||
}
|
||||
|
||||
// Read element data
|
||||
const elementBuffer = buffer.subarray(offset, offset + size);
|
||||
const element = decode(elementBuffer);
|
||||
elements.push(element);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return {
|
||||
oscType: 'bundle',
|
||||
timetag,
|
||||
elements
|
||||
};
|
||||
}
|
||||
|
||||
exports.decode = decode;
|
||||
exports.encode = encode;
|
||||
424
backend/node_modules/node-osc/dist/test/lib/osc.js
generated
vendored
Normal file
424
backend/node_modules/node-osc/dist/test/lib/osc.js
generated
vendored
Normal file
@ -0,0 +1,424 @@
|
||||
'use strict';
|
||||
|
||||
var node_buffer = require('node:buffer');
|
||||
|
||||
// OSC 1.0 Protocol Implementation
|
||||
// Based on http://opensoundcontrol.org/spec-1_0
|
||||
|
||||
|
||||
function padString(str) {
|
||||
const nullTerminated = str + '\0';
|
||||
const byteLength = node_buffer.Buffer.byteLength(nullTerminated);
|
||||
const padding = (4 - (byteLength % 4)) % 4;
|
||||
return nullTerminated + '\0'.repeat(padding);
|
||||
}
|
||||
|
||||
function readString(buffer, offset) {
|
||||
let end = offset;
|
||||
while (end < buffer.length && buffer[end] !== 0) {
|
||||
end++;
|
||||
}
|
||||
if (end >= buffer.length) {
|
||||
throw new Error('Malformed Packet: Missing null terminator for string');
|
||||
}
|
||||
const str = buffer.subarray(offset, end).toString('utf8');
|
||||
// Find next 4-byte boundary
|
||||
const paddedLength = Math.ceil((end - offset + 1) / 4) * 4;
|
||||
return { value: str, offset: offset + paddedLength };
|
||||
}
|
||||
|
||||
function writeInt32(value) {
|
||||
const buffer = node_buffer.Buffer.alloc(4);
|
||||
buffer.writeInt32BE(value, 0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readInt32(buffer, offset) {
|
||||
if (offset + 4 > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for int32');
|
||||
}
|
||||
const value = buffer.readInt32BE(offset);
|
||||
return { value, offset: offset + 4 };
|
||||
}
|
||||
|
||||
function writeFloat32(value) {
|
||||
const buffer = node_buffer.Buffer.alloc(4);
|
||||
buffer.writeFloatBE(value, 0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readFloat32(buffer, offset) {
|
||||
if (offset + 4 > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for float32');
|
||||
}
|
||||
const value = buffer.readFloatBE(offset);
|
||||
return { value, offset: offset + 4 };
|
||||
}
|
||||
|
||||
function writeBlob(value) {
|
||||
const length = value.length;
|
||||
const lengthBuffer = writeInt32(length);
|
||||
const padding = 4 - (length % 4);
|
||||
const paddingBuffer = node_buffer.Buffer.alloc(padding === 4 ? 0 : padding);
|
||||
return node_buffer.Buffer.concat([lengthBuffer, value, paddingBuffer]);
|
||||
}
|
||||
|
||||
function readBlob(buffer, offset) {
|
||||
const lengthResult = readInt32(buffer, offset);
|
||||
const length = lengthResult.value;
|
||||
if (length < 0) {
|
||||
throw new Error('Malformed Packet: Invalid blob length');
|
||||
}
|
||||
if (lengthResult.offset + length > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for blob');
|
||||
}
|
||||
const data = buffer.subarray(lengthResult.offset, lengthResult.offset + length);
|
||||
const padding = 4 - (length % 4);
|
||||
const nextOffset = lengthResult.offset + length + (padding === 4 ? 0 : padding);
|
||||
if (nextOffset > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for blob padding');
|
||||
}
|
||||
return { value: data, offset: nextOffset };
|
||||
}
|
||||
|
||||
function writeTimeTag(value) {
|
||||
// For now, treat timetag as a double (8 bytes)
|
||||
// OSC timetag is 64-bit: 32-bit seconds since 1900, 32-bit fractional
|
||||
const buffer = node_buffer.Buffer.alloc(8);
|
||||
if (value === 0 || value === null || value === undefined) {
|
||||
// Immediate execution
|
||||
buffer.writeUInt32BE(0, 0);
|
||||
buffer.writeUInt32BE(1, 4);
|
||||
} else if (typeof value === 'number') {
|
||||
// Convert to OSC timetag format
|
||||
const seconds = Math.floor(value);
|
||||
const fraction = Math.floor((value - seconds) * 0x100000000);
|
||||
buffer.writeUInt32BE(seconds + 2208988800, 0); // Add epoch offset (1900 vs 1970)
|
||||
buffer.writeUInt32BE(fraction, 4);
|
||||
} else {
|
||||
// If not a number, write zeros (immediate execution)
|
||||
buffer.writeUInt32BE(0, 0);
|
||||
buffer.writeUInt32BE(1, 4);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readTimeTag(buffer, offset) {
|
||||
if (offset + 8 > buffer.length) {
|
||||
throw new Error('Malformed Packet: Not enough bytes for timetag');
|
||||
}
|
||||
const seconds = buffer.readUInt32BE(offset);
|
||||
const fraction = buffer.readUInt32BE(offset + 4);
|
||||
|
||||
let value;
|
||||
if (seconds === 0 && fraction === 1) {
|
||||
// Immediate execution
|
||||
value = 0;
|
||||
} else {
|
||||
// Convert from OSC epoch (1900) to Unix epoch (1970)
|
||||
const unixSeconds = seconds - 2208988800;
|
||||
const fractionalSeconds = fraction / 0x100000000;
|
||||
value = unixSeconds + fractionalSeconds;
|
||||
}
|
||||
|
||||
return { value, offset: offset + 8 };
|
||||
}
|
||||
|
||||
function writeMidi(value) {
|
||||
// MIDI message is 4 bytes: port id, status byte, data1, data2
|
||||
const buffer = node_buffer.Buffer.alloc(4);
|
||||
|
||||
if (node_buffer.Buffer.isBuffer(value)) {
|
||||
if (value.length !== 4) {
|
||||
throw new Error('MIDI message must be exactly 4 bytes');
|
||||
}
|
||||
value.copy(buffer);
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// Allow object format: { port: 0, status: 144, data1: 60, data2: 127 }
|
||||
buffer.writeUInt8(value.port || 0, 0);
|
||||
buffer.writeUInt8(value.status || 0, 1);
|
||||
buffer.writeUInt8(value.data1 || 0, 2);
|
||||
buffer.writeUInt8(value.data2 || 0, 3);
|
||||
} else {
|
||||
throw new Error('MIDI value must be a 4-byte Buffer or object with port, status, data1, data2 properties');
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function readMidi(buffer, offset) {
|
||||
if (offset + 4 > buffer.length) {
|
||||
throw new Error('Not enough bytes for MIDI message');
|
||||
}
|
||||
|
||||
const value = buffer.subarray(offset, offset + 4);
|
||||
return { value, offset: offset + 4 };
|
||||
}
|
||||
|
||||
function encodeArgument(arg) {
|
||||
if (typeof arg === 'object' && arg.type && arg.value !== undefined) {
|
||||
// Explicit type specification
|
||||
switch (arg.type) {
|
||||
case 'i':
|
||||
case 'integer':
|
||||
return { tag: 'i', data: writeInt32(arg.value) };
|
||||
case 'f':
|
||||
case 'float':
|
||||
return { tag: 'f', data: writeFloat32(arg.value) };
|
||||
case 's':
|
||||
case 'string':
|
||||
return { tag: 's', data: node_buffer.Buffer.from(padString(arg.value)) };
|
||||
case 'b':
|
||||
case 'blob':
|
||||
return { tag: 'b', data: writeBlob(arg.value) };
|
||||
case 'd':
|
||||
case 'double':
|
||||
// For doubles, use float for now (OSC 1.0 doesn't have double)
|
||||
return { tag: 'f', data: writeFloat32(arg.value) };
|
||||
case 'T':
|
||||
return { tag: 'T', data: node_buffer.Buffer.alloc(0) };
|
||||
case 'F':
|
||||
return { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
||||
case 'boolean':
|
||||
return arg.value ? { tag: 'T', data: node_buffer.Buffer.alloc(0) } : { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
||||
case 'm':
|
||||
case 'midi':
|
||||
return { tag: 'm', data: writeMidi(arg.value) };
|
||||
default:
|
||||
throw new Error(`Unknown argument type: ${arg.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Infer type from JavaScript type
|
||||
switch (typeof arg) {
|
||||
case 'number':
|
||||
if (Number.isInteger(arg)) {
|
||||
return { tag: 'i', data: writeInt32(arg) };
|
||||
} else {
|
||||
return { tag: 'f', data: writeFloat32(arg) };
|
||||
}
|
||||
case 'string':
|
||||
return { tag: 's', data: node_buffer.Buffer.from(padString(arg)) };
|
||||
case 'boolean':
|
||||
return arg ? { tag: 'T', data: node_buffer.Buffer.alloc(0) } : { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
||||
default:
|
||||
if (node_buffer.Buffer.isBuffer(arg)) {
|
||||
return { tag: 'b', data: writeBlob(arg) };
|
||||
}
|
||||
throw new Error(`Don't know how to encode argument: ${arg}`);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeArgument(tag, buffer, offset) {
|
||||
switch (tag) {
|
||||
case 'i':
|
||||
return readInt32(buffer, offset);
|
||||
case 'f':
|
||||
return readFloat32(buffer, offset);
|
||||
case 's':
|
||||
return readString(buffer, offset);
|
||||
case 'b':
|
||||
return readBlob(buffer, offset);
|
||||
case 'T':
|
||||
return { value: true, offset };
|
||||
case 'F':
|
||||
return { value: false, offset };
|
||||
case 'N':
|
||||
return { value: null, offset };
|
||||
case 'm':
|
||||
return readMidi(buffer, offset);
|
||||
default:
|
||||
throw new Error(`I don't understand the argument code ${tag}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an OSC message or bundle to a Buffer.
|
||||
*
|
||||
* This low-level function converts OSC messages and bundles into binary format
|
||||
* for transmission or storage. Useful for sending OSC over custom transports
|
||||
* (WebSocket, TCP, HTTP), storing to files, or implementing custom OSC routers.
|
||||
*
|
||||
* @param {Object} message - OSC message or bundle object with oscType property
|
||||
* @returns {Buffer} The encoded OSC data ready for transmission
|
||||
*
|
||||
* @example
|
||||
* // Encode a message
|
||||
* import { Message, encode } from 'node-osc';
|
||||
*
|
||||
* const message = new Message('/oscillator/frequency', 440);
|
||||
* const buffer = encode(message);
|
||||
* console.log('Encoded bytes:', buffer.length);
|
||||
*
|
||||
* @example
|
||||
* // Encode a bundle
|
||||
* import { Bundle, encode } from 'node-osc';
|
||||
*
|
||||
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
||||
* const buffer = encode(bundle);
|
||||
*
|
||||
* @example
|
||||
* // Send over WebSocket
|
||||
* const buffer = encode(message);
|
||||
* websocket.send(buffer);
|
||||
*/
|
||||
function encode(message) {
|
||||
if (message.oscType === 'bundle') {
|
||||
return encodeBundleToBuffer(message);
|
||||
} else {
|
||||
return encodeMessageToBuffer(message);
|
||||
}
|
||||
}
|
||||
|
||||
function encodeMessageToBuffer(message) {
|
||||
// OSC Message format:
|
||||
// Address pattern (padded string)
|
||||
// Type tag string (padded string starting with ,)
|
||||
// Arguments (encoded according to type tags)
|
||||
|
||||
const address = padString(message.address);
|
||||
const addressBuffer = node_buffer.Buffer.from(address);
|
||||
|
||||
const encodedArgs = message.args.map(encodeArgument);
|
||||
const typeTags = ',' + encodedArgs.map(arg => arg.tag).join('');
|
||||
const typeTagsBuffer = node_buffer.Buffer.from(padString(typeTags));
|
||||
|
||||
const argumentBuffers = encodedArgs.map(arg => arg.data);
|
||||
|
||||
return node_buffer.Buffer.concat([addressBuffer, typeTagsBuffer, ...argumentBuffers]);
|
||||
}
|
||||
|
||||
function encodeBundleToBuffer(bundle) {
|
||||
// OSC Bundle format:
|
||||
// "#bundle" (padded string)
|
||||
// Timetag (8 bytes)
|
||||
// Elements (each prefixed with size)
|
||||
|
||||
const bundleString = padString('#bundle');
|
||||
const bundleStringBuffer = node_buffer.Buffer.from(bundleString);
|
||||
|
||||
const timetagBuffer = writeTimeTag(bundle.timetag);
|
||||
|
||||
const elementBuffers = bundle.elements.map(element => {
|
||||
let elementBuffer;
|
||||
if (element.oscType === 'bundle') {
|
||||
elementBuffer = encodeBundleToBuffer(element);
|
||||
} else {
|
||||
elementBuffer = encodeMessageToBuffer(element);
|
||||
}
|
||||
const sizeBuffer = writeInt32(elementBuffer.length);
|
||||
return node_buffer.Buffer.concat([sizeBuffer, elementBuffer]);
|
||||
});
|
||||
|
||||
return node_buffer.Buffer.concat([bundleStringBuffer, timetagBuffer, ...elementBuffers]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Buffer containing OSC data into a message or bundle object.
|
||||
*
|
||||
* This low-level function parses binary OSC data back into JavaScript objects.
|
||||
* Useful for receiving OSC over custom transports, reading from files,
|
||||
* or implementing custom OSC routers.
|
||||
*
|
||||
* @param {Buffer} buffer - The Buffer containing OSC data
|
||||
* @returns {Object} The decoded OSC message or bundle. Messages have
|
||||
* {oscType: 'message', address: string, args: Array}, bundles have
|
||||
* {oscType: 'bundle', timetag: number, elements: Array}
|
||||
* @throws {Error} If the buffer contains malformed OSC data
|
||||
*
|
||||
* @example
|
||||
* // Decode received data
|
||||
* import { decode } from 'node-osc';
|
||||
*
|
||||
* const decoded = decode(buffer);
|
||||
* if (decoded.oscType === 'message') {
|
||||
* console.log('Address:', decoded.address);
|
||||
* console.log('Arguments:', decoded.args);
|
||||
* }
|
||||
*
|
||||
* @example
|
||||
* // Round-trip encode/decode
|
||||
* import { Message, encode, decode } from 'node-osc';
|
||||
*
|
||||
* const original = new Message('/test', 42, 'hello');
|
||||
* const buffer = encode(original);
|
||||
* const decoded = decode(buffer);
|
||||
* console.log(decoded.address); // '/test'
|
||||
*/
|
||||
function decode(buffer) {
|
||||
// Check if it's a bundle or message
|
||||
if (buffer.length >= 8 && buffer.subarray(0, 8).toString() === '#bundle\0') {
|
||||
return decodeBundleFromBuffer(buffer);
|
||||
} else {
|
||||
return decodeMessageFromBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeMessageFromBuffer(buffer) {
|
||||
let offset = 0;
|
||||
|
||||
// Read address pattern
|
||||
const addressResult = readString(buffer, offset);
|
||||
const address = addressResult.value;
|
||||
offset = addressResult.offset;
|
||||
|
||||
// Read type tag string
|
||||
const typeTagsResult = readString(buffer, offset);
|
||||
const typeTags = typeTagsResult.value;
|
||||
offset = typeTagsResult.offset;
|
||||
|
||||
if (!typeTags.startsWith(',')) {
|
||||
throw new Error('Malformed Packet');
|
||||
}
|
||||
|
||||
const tags = typeTags.slice(1); // Remove leading comma
|
||||
const args = [];
|
||||
|
||||
for (const tag of tags) {
|
||||
const argResult = decodeArgument(tag, buffer, offset);
|
||||
args.push({ value: argResult.value });
|
||||
offset = argResult.offset;
|
||||
}
|
||||
|
||||
return {
|
||||
oscType: 'message',
|
||||
address,
|
||||
args
|
||||
};
|
||||
}
|
||||
|
||||
function decodeBundleFromBuffer(buffer) {
|
||||
let offset = 8; // Skip "#bundle\0"
|
||||
|
||||
// Read timetag
|
||||
const timetagResult = readTimeTag(buffer, offset);
|
||||
const timetag = timetagResult.value;
|
||||
offset = timetagResult.offset;
|
||||
|
||||
const elements = [];
|
||||
|
||||
while (offset < buffer.length) {
|
||||
// Read element size
|
||||
const sizeResult = readInt32(buffer, offset);
|
||||
const size = sizeResult.value;
|
||||
offset = sizeResult.offset;
|
||||
if (size <= 0 || offset + size > buffer.length) {
|
||||
throw new Error('Malformed Packet');
|
||||
}
|
||||
|
||||
// Read element data
|
||||
const elementBuffer = buffer.subarray(offset, offset + size);
|
||||
const element = decode(elementBuffer);
|
||||
elements.push(element);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return {
|
||||
oscType: 'bundle',
|
||||
timetag,
|
||||
elements
|
||||
};
|
||||
}
|
||||
|
||||
exports.decode = decode;
|
||||
exports.encode = encode;
|
||||
90
backend/node_modules/node-osc/dist/test/test-bundle.js
generated
vendored
Normal file
90
backend/node_modules/node-osc/dist/test/test-bundle.js
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
tap.test('bundle: verbose bundle', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
t.teardown(() => {
|
||||
server.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
server.on('bundle', (bundle) => {
|
||||
t.same(bundle.elements[0], ['/one', 1]);
|
||||
t.same(bundle.elements[1], ['/two', 2]);
|
||||
});
|
||||
|
||||
client.send(new nodeOsc.Bundle(1, {
|
||||
address: '/one',
|
||||
args: [
|
||||
1
|
||||
]
|
||||
}, {
|
||||
address: '/two',
|
||||
args: [
|
||||
2
|
||||
]
|
||||
}));
|
||||
});
|
||||
|
||||
tap.test('bundle: array syntax', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
t.teardown(() => {
|
||||
server.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
server.on('bundle', (bundle) => {
|
||||
t.same(bundle.elements[0], ['/one', 1]);
|
||||
t.same(bundle.elements[1], ['/two', 2]);
|
||||
});
|
||||
|
||||
client.send(new nodeOsc.Bundle(
|
||||
['/one', 1],
|
||||
['/two', 2]
|
||||
));
|
||||
});
|
||||
|
||||
tap.test('bundle: nested bundle', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(4);
|
||||
|
||||
t.teardown(() => {
|
||||
server.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
const payload = new nodeOsc.Bundle(
|
||||
['/one', 1],
|
||||
['/two', 2],
|
||||
['/three', 3]
|
||||
);
|
||||
|
||||
payload.append(new nodeOsc.Bundle(10,
|
||||
['/four', 4]
|
||||
));
|
||||
|
||||
server.on('bundle', (bundle) => {
|
||||
t.same(bundle.elements[0], ['/one', 1]);
|
||||
t.same(bundle.elements[1], ['/two', 2]);
|
||||
t.same(bundle.elements[2], ['/three', 3]);
|
||||
t.same(bundle.elements[3].elements[0], ['/four', 4]);
|
||||
});
|
||||
|
||||
client.send(payload);
|
||||
});
|
||||
292
backend/node_modules/node-osc/dist/test/test-client.js
generated
vendored
Normal file
292
backend/node_modules/node-osc/dist/test/test-client.js
generated
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
tap.test('client: with array', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 0, 1, 'testing', true], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
client.send(['/test', 0, 1, 'testing', true], (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
client.close();
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: array is not mutated when sent', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(3);
|
||||
|
||||
const originalArray = ['/test', 0, 1, 'testing', true];
|
||||
const expectedArray = ['/test', 0, 1, 'testing', true];
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 0, 1, 'testing', true], 'We should receive expected payload');
|
||||
// Verify the original array was not mutated
|
||||
t.same(originalArray, expectedArray, 'Original array should not be mutated');
|
||||
});
|
||||
|
||||
client.send(originalArray, (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
client.close();
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: with string', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test'], `We should receive expected payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send('/test', (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
client.close();
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: with Message object', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 1, 2, 3, 'lol', false], `we received the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send({
|
||||
address: '/test',
|
||||
args: [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
'lol',
|
||||
false
|
||||
]
|
||||
}, (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
client.close();
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: with Bundle object', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 1, 2, 3, 'lol', false], `we received the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send({
|
||||
address: '/test',
|
||||
args: [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
'lol',
|
||||
false
|
||||
]
|
||||
}, (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
client.close();
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: failure', async (t) => {
|
||||
const client = new nodeOsc.Client('127.0.0.1', 9999);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
t.throws(() => {
|
||||
client.send(123, (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
});
|
||||
});
|
||||
client.close();
|
||||
client.send('/boom', (err) => {
|
||||
t.equal(err.code, 'ERR_SOCKET_DGRAM_NOT_RUNNING');
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: close with callback', async (t) => {
|
||||
const client = new nodeOsc.Client('127.0.0.1', 9999);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
client.close((err) => {
|
||||
t.error(err, 'close should not error');
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: send bundle with non-numeric timetag', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('bundle', (bundle) => {
|
||||
oscServer.close();
|
||||
t.equal(bundle.timetag, 0, 'should receive immediate execution timetag as 0');
|
||||
t.ok(bundle.elements.length > 0, 'should have elements');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Send bundle with non-numeric timetag (will be encoded as immediate execution)
|
||||
const bundle = {
|
||||
oscType: 'bundle',
|
||||
timetag: 'immediate', // Non-numeric, will trigger the else branch in writeTimeTag
|
||||
elements: [
|
||||
{
|
||||
oscType: 'message',
|
||||
address: '/test1',
|
||||
args: [{ type: 'i', value: 42 }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
client.send(bundle);
|
||||
});
|
||||
|
||||
tap.test('client: send bundle with null timetag', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('bundle', (bundle) => {
|
||||
oscServer.close();
|
||||
t.equal(bundle.timetag, 0, 'should receive immediate execution timetag as 0');
|
||||
t.ok(bundle.elements.length > 0, 'should have elements');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Send bundle with null timetag (will be encoded as immediate execution)
|
||||
const bundle = {
|
||||
oscType: 'bundle',
|
||||
timetag: null, // Null, will trigger the else branch in writeTimeTag
|
||||
elements: [
|
||||
{
|
||||
oscType: 'message',
|
||||
address: '/test2',
|
||||
args: [{ type: 's', value: 'hello' }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
client.send(bundle);
|
||||
});
|
||||
|
||||
tap.test('client: send message with float type arg', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.equal(msg[0], '/float-test', 'should receive address');
|
||||
t.ok(Math.abs(msg[1] - 9.876) < 0.001, 'should receive float value');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Send raw message with 'float' type to hit that case label
|
||||
client.send({
|
||||
oscType: 'message',
|
||||
address: '/float-test',
|
||||
args: [{ type: 'float', value: 9.876 }]
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: send message with blob type arg', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.equal(msg[0], '/blob-test', 'should receive address');
|
||||
t.ok(Buffer.isBuffer(msg[1]), 'should receive blob as buffer');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Send raw message with 'blob' type to hit that case label
|
||||
client.send({
|
||||
oscType: 'message',
|
||||
address: '/blob-test',
|
||||
args: [{ type: 'blob', value: Buffer.from([0xAA, 0xBB]) }]
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: send message with double type arg', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.equal(msg[0], '/double-test', 'should receive address');
|
||||
t.ok(Math.abs(msg[1] - 1.23456789) < 0.001, 'should receive double value as float');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Send raw message with 'double' type to hit that case label
|
||||
client.send({
|
||||
oscType: 'message',
|
||||
address: '/double-test',
|
||||
args: [{ type: 'double', value: 1.23456789 }]
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('client: send message with midi type arg', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.equal(msg[0], '/midi-test', 'should receive address');
|
||||
t.ok(Buffer.isBuffer(msg[1]), 'should receive MIDI as buffer');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Send raw message with 'midi' type to hit that case label
|
||||
client.send({
|
||||
oscType: 'message',
|
||||
address: '/midi-test',
|
||||
args: [{ type: 'midi', value: Buffer.from([0x00, 0x90, 0x40, 0x60]) }]
|
||||
});
|
||||
});
|
||||
144
backend/node_modules/node-osc/dist/test/test-decode.js
generated
vendored
Normal file
144
backend/node_modules/node-osc/dist/test/test-decode.js
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
'use strict';
|
||||
|
||||
var tap = require('tap');
|
||||
var decode = require('#decode');
|
||||
|
||||
tap.test('decode: valid', (t) => {
|
||||
const buf = Buffer.from('/test\0\0\0,s\0,testing\0');
|
||||
t.same(decode(buf), ['/test', 'testing'], 'should be empty array');
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: valid', (t) => {
|
||||
const buf = Buffer.from('/test\0\0\0,s\0,testing\0');
|
||||
t.same(decode(buf), ['/test', 'testing'], 'should be empty array');
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: malformed packet', (t) => {
|
||||
t.throws(() => {
|
||||
const buf = Buffer.from('/test\0\0');
|
||||
decode(buf);
|
||||
}, /Malformed Packet/);
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: invalid typetags', (t) => {
|
||||
t.throws(() => {
|
||||
const buf = Buffer.from('/test\0\0\0,R\0');
|
||||
decode(buf);
|
||||
}, /I don't understand the argument code R/);
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: malformed OSC structure', (t) => {
|
||||
// Try to create a scenario that might trigger the "else" case in decode
|
||||
// This tests an edge case where the buffer might be parsed but not create a valid OSC structure
|
||||
t.throws(() => {
|
||||
// Create a buffer that's too short to be valid
|
||||
const buf = Buffer.from('\0\0\0\0');
|
||||
decode(buf);
|
||||
}, /Malformed Packet/);
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: corrupted buffer', (t) => {
|
||||
// Test with a buffer that could potentially cause fromBuffer to return unexpected results
|
||||
t.throws(() => {
|
||||
// Create a malformed buffer that might not parse correctly
|
||||
const buf = Buffer.from('invalid');
|
||||
decode(buf);
|
||||
}, /(Malformed Packet|Cannot read|out of range)/);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// This test attempts to exercise edge cases in the decode function
|
||||
tap.test('decode: edge case with manually crafted invalid structure', (t) => {
|
||||
// Since the decode function has a defensive else clause, let's try to trigger it
|
||||
// by creating a buffer that might result in an unexpected object structure
|
||||
|
||||
// Try with an empty buffer
|
||||
t.throws(() => {
|
||||
const buf = Buffer.alloc(0);
|
||||
decode(buf);
|
||||
}, /(Malformed Packet|Cannot read|out of range)/);
|
||||
|
||||
// Try with a buffer containing only null bytes
|
||||
t.throws(() => {
|
||||
const buf = Buffer.alloc(16, 0);
|
||||
decode(buf);
|
||||
}, /(Malformed Packet|Cannot read|out of range)/);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: malformed structure with unexpected oscType', async (t) => {
|
||||
// Test the defensive else clause by providing a custom fromBuffer function
|
||||
// that returns an object with an invalid oscType
|
||||
|
||||
const mockFromBuffer = () => ({
|
||||
oscType: 'invalid',
|
||||
data: 'test'
|
||||
});
|
||||
|
||||
t.throws(() => {
|
||||
decode(Buffer.from('test'), mockFromBuffer);
|
||||
}, /Malformed Packet/, 'should throw for invalid oscType');
|
||||
|
||||
// Test with undefined oscType
|
||||
const mockFromBufferUndefined = () => ({
|
||||
data: 'test'
|
||||
// missing oscType property
|
||||
});
|
||||
|
||||
t.throws(() => {
|
||||
decode(Buffer.from('test'), mockFromBufferUndefined);
|
||||
}, /Malformed Packet/, 'should throw for undefined oscType');
|
||||
|
||||
// Test with null oscType
|
||||
const mockFromBufferNull = () => ({
|
||||
oscType: null,
|
||||
data: 'test'
|
||||
});
|
||||
|
||||
t.throws(() => {
|
||||
decode(Buffer.from('test'), mockFromBufferNull);
|
||||
}, /Malformed Packet/, 'should throw for null oscType');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: message without args defaults to empty array', (t) => {
|
||||
const mockFromBuffer = () => ({
|
||||
oscType: 'message',
|
||||
address: '/test'
|
||||
});
|
||||
|
||||
t.same(
|
||||
decode(Buffer.from('test'), mockFromBuffer),
|
||||
['/test'],
|
||||
'should default args to empty array'
|
||||
);
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('decode: bundle element must be message or bundle', (t) => {
|
||||
const mockFromBuffer = () => ({
|
||||
oscType: 'bundle',
|
||||
elements: [
|
||||
{
|
||||
oscType: 'message',
|
||||
address: '/ok',
|
||||
args: []
|
||||
},
|
||||
{
|
||||
oscType: 'nope'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
t.throws(() => {
|
||||
decode(Buffer.from('test'), mockFromBuffer);
|
||||
}, /Malformed Packet/, 'should throw for invalid bundle element');
|
||||
t.end();
|
||||
});
|
||||
58
backend/node_modules/node-osc/dist/test/test-e2e.js
generated
vendored
Normal file
58
backend/node_modules/node-osc/dist/test/test-e2e.js
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
function flaky() {
|
||||
return process.release.lts === 'Dubnium' && process.platform === 'win32';
|
||||
}
|
||||
|
||||
function skip(t) {
|
||||
t.skip(`flaky ~ ${t.name}`);
|
||||
t.end();
|
||||
}
|
||||
|
||||
tap.test('osc: argument message no callback', async (t) => {
|
||||
if (flaky()) return skip(t);
|
||||
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
t.same(msg, ['/test', 1, 2, 'testing'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
client.send('/test', 1, 2, 'testing');
|
||||
});
|
||||
|
||||
tap.test('osc: client with callback and message as arguments', async (t) => {
|
||||
if (flaky()) return skip(t);
|
||||
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
t.same(msg, ['/test', 1, 2, 'testing'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
client.send('/test', 1, 2, 'testing', (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
});
|
||||
});
|
||||
1304
backend/node_modules/node-osc/dist/test/test-encode-decode.js
generated
vendored
Normal file
1304
backend/node_modules/node-osc/dist/test/test-encode-decode.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
117
backend/node_modules/node-osc/dist/test/test-error-handling.js
generated
vendored
Normal file
117
backend/node_modules/node-osc/dist/test/test-error-handling.js
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
tap.test('server: socket error event is emitted', async (t) => {
|
||||
t.plan(1);
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
|
||||
oscServer.on('error', (err) => {
|
||||
t.ok(err, 'error event should be emitted');
|
||||
oscServer.close();
|
||||
});
|
||||
|
||||
// Simulate a socket error
|
||||
oscServer._sock.emit('error', new Error('test socket error'));
|
||||
});
|
||||
|
||||
tap.test('server: error listener can be added before listening', async (t) => {
|
||||
t.plan(2);
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
|
||||
oscServer.on('error', (err) => {
|
||||
t.ok(err, 'error event should be emitted');
|
||||
t.equal(err.message, 'socket test error', 'error message should match');
|
||||
});
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
});
|
||||
|
||||
// Simulate a socket error
|
||||
oscServer._sock.emit('error', new Error('socket test error'));
|
||||
});
|
||||
|
||||
tap.test('client: socket error event is emitted', (t) => {
|
||||
t.plan(1);
|
||||
const client = new nodeOsc.Client('127.0.0.1', 9999);
|
||||
|
||||
client.on('error', (err) => {
|
||||
t.ok(err, 'error event should be emitted');
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Simulate a socket error
|
||||
client._sock.emit('error', new Error('test client error'));
|
||||
});
|
||||
|
||||
tap.test('client: error listener can be added at construction', (t) => {
|
||||
t.plan(2);
|
||||
const client = new nodeOsc.Client('127.0.0.1', 9999);
|
||||
|
||||
client.on('error', (err) => {
|
||||
t.ok(err, 'error event should be emitted');
|
||||
t.equal(err.message, 'client socket error', 'error message should match');
|
||||
});
|
||||
|
||||
t.teardown(() => {
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Simulate a socket error
|
||||
client._sock.emit('error', new Error('client socket error'));
|
||||
});
|
||||
|
||||
tap.test('client: is an EventEmitter instance', (t) => {
|
||||
t.plan(1);
|
||||
const client = new nodeOsc.Client('127.0.0.1', 9999);
|
||||
|
||||
t.ok(typeof client.on === 'function', 'client should have EventEmitter methods');
|
||||
|
||||
client.close();
|
||||
});
|
||||
|
||||
tap.test('server: multiple error listeners can be attached', async (t) => {
|
||||
t.plan(2);
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
|
||||
oscServer.on('error', (err) => {
|
||||
t.ok(err, 'first listener should receive error');
|
||||
});
|
||||
|
||||
oscServer.on('error', (err) => {
|
||||
t.ok(err, 'second listener should receive error');
|
||||
});
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
});
|
||||
|
||||
// Simulate a socket error
|
||||
oscServer._sock.emit('error', new Error('multi listener test'));
|
||||
});
|
||||
|
||||
tap.test('client: multiple error listeners can be attached', (t) => {
|
||||
t.plan(2);
|
||||
const client = new nodeOsc.Client('127.0.0.1', 9999);
|
||||
|
||||
client.on('error', (err) => {
|
||||
t.ok(err, 'first listener should receive error');
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
t.ok(err, 'second listener should receive error');
|
||||
});
|
||||
|
||||
t.teardown(() => {
|
||||
client.close();
|
||||
});
|
||||
|
||||
// Simulate a socket error
|
||||
client._sock.emit('error', new Error('multi listener test'));
|
||||
});
|
||||
403
backend/node_modules/node-osc/dist/test/test-message.js
generated
vendored
Normal file
403
backend/node_modules/node-osc/dist/test/test-message.js
generated
vendored
Normal file
@ -0,0 +1,403 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
function round(num) {
|
||||
return Math.round(num * 100) / 100;
|
||||
}
|
||||
|
||||
tap.test('message: basic usage', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
m.append('testing');
|
||||
m.append(123);
|
||||
m.append([456, 789]);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = ['/address', 'testing', 123, 456, 789];
|
||||
t.same(msg, expected, `We reveived the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: multiple args', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address', 'testing', 123, true);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = ['/address', 'testing', 123, true];
|
||||
t.same(msg, expected, `We reveived the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: object', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
m.append({
|
||||
type: 'string',
|
||||
value: 'test'
|
||||
});
|
||||
m.append({
|
||||
type: 'double',
|
||||
value: 100
|
||||
});
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = ['/address', 'test', 100];
|
||||
t.same(msg, expected, `We reveived the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: float', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(2);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
m.append(3.14);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
3.14
|
||||
];
|
||||
t.equal(msg[0], expected[0], `We reveived the payload: ${msg}`);
|
||||
t.equal(round(msg[1]), expected[1], 'pie please');
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: alias messages', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(5);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
m.append({
|
||||
type: 'i',
|
||||
value: 123
|
||||
});
|
||||
m.append({
|
||||
type: 'f',
|
||||
value: 3.14
|
||||
});
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
123,
|
||||
3.14
|
||||
];
|
||||
t.equal(msg[0], expected[0], `We reveived the payload: ${msg}`);
|
||||
t.equal(msg[1], expected[1], 'easy as abc');
|
||||
t.ok(Number.isInteger(msg[1]), 'the first value is an int');
|
||||
t.equal(round(msg[2]), expected[2], 'pie please');
|
||||
t.ok(msg[2] % 1 !== 0, 'the second value is a float');
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: boolean', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
const m = new nodeOsc.Message('/address');
|
||||
m.append(true);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
true
|
||||
];
|
||||
t.same(msg, expected, `We reveived the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: blob', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
const buf = Buffer.from('test');
|
||||
m.append({
|
||||
type: 'blob',
|
||||
value: buf
|
||||
});
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
buf
|
||||
];
|
||||
t.same(msg, expected, `We reveived the payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: Buffer as blob', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
const buf = Buffer.from('test buffer data');
|
||||
// Directly append Buffer without wrapping in object
|
||||
m.append(buf);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
buf
|
||||
];
|
||||
t.same(msg, expected, `We received the buffer payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
// test('message: timetag', (t) => {
|
||||
// const oscServer = new osc.Server(3333, '127.0.0.1');
|
||||
// const client = new osc.Client('127.0.0.1', 3333);
|
||||
// const m = new osc.Message('/address');
|
||||
//
|
||||
// oscServer.on('message', (msg) => {
|
||||
// const expected = [
|
||||
// '/address'
|
||||
// ];
|
||||
// t.same(msg, expected, `We reveived the payload: ${msg}`);
|
||||
// oscServer.close();
|
||||
// t.end();
|
||||
// });
|
||||
//
|
||||
// client.send(m, () => {
|
||||
// client.close();
|
||||
// });
|
||||
// });
|
||||
|
||||
tap.test('message: Buffer with multiple arguments', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(6);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
const buf1 = Buffer.from('first');
|
||||
const buf2 = Buffer.from('second');
|
||||
|
||||
m.append('string');
|
||||
m.append(42);
|
||||
m.append(buf1);
|
||||
m.append(3.14);
|
||||
m.append(buf2);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
t.equal(msg[0], '/address', 'Address matches');
|
||||
t.equal(msg[1], 'string', 'String matches');
|
||||
t.equal(msg[2], 42, 'Integer matches');
|
||||
t.same(msg[3], buf1, 'First buffer matches');
|
||||
t.equal(round(msg[4]), 3.14, 'Float matches');
|
||||
t.same(msg[5], buf2, 'Second buffer matches');
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: Buffer in constructor', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const buf = Buffer.from('constructor buffer');
|
||||
const m = new nodeOsc.Message('/address', 'test', buf, 123);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
'test',
|
||||
buf,
|
||||
123
|
||||
];
|
||||
t.same(msg, expected, `We received the constructor buffer payload: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: Buffer in array', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
const buf1 = Buffer.from('array1');
|
||||
const buf2 = Buffer.from('array2');
|
||||
|
||||
m.append([buf1, 'string', buf2, 456]);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
buf1,
|
||||
'string',
|
||||
buf2,
|
||||
456
|
||||
];
|
||||
t.same(msg, expected, `We received the array with buffers: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: empty Buffer', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
const buf = Buffer.from('');
|
||||
|
||||
m.append(buf);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
const expected = [
|
||||
'/address',
|
||||
buf
|
||||
];
|
||||
t.same(msg, expected, `We received the empty buffer: ${msg}`);
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: large Buffer', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(4);
|
||||
t.teardown(async () => {
|
||||
await server.close();
|
||||
await client.close();
|
||||
});
|
||||
|
||||
const m = new nodeOsc.Message('/address');
|
||||
const buf = Buffer.alloc(1024, 'x');
|
||||
|
||||
m.append(buf);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
t.equal(msg[0], '/address', 'Address matches');
|
||||
t.ok(Buffer.isBuffer(msg[1]), 'Second element is a Buffer');
|
||||
t.equal(msg[1].length, 1024, 'Buffer size matches');
|
||||
t.same(msg[1], buf, 'Buffer content matches');
|
||||
});
|
||||
|
||||
client.send(m);
|
||||
});
|
||||
|
||||
tap.test('message: error', (t) => {
|
||||
const m = new nodeOsc.Message('/address');
|
||||
t.plan(2);
|
||||
t.throws(() => {
|
||||
m.append({
|
||||
lol: 'it broken'
|
||||
});
|
||||
}, /don't know how to encode object/);
|
||||
t.throws(() => {
|
||||
m.append(undefined);
|
||||
}, /don't know how to encode/);
|
||||
});
|
||||
1007
backend/node_modules/node-osc/dist/test/test-osc-internal.js
generated
vendored
Normal file
1007
backend/node_modules/node-osc/dist/test/test-osc-internal.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
314
backend/node_modules/node-osc/dist/test/test-promises.js
generated
vendored
Normal file
314
backend/node_modules/node-osc/dist/test/test-promises.js
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
tap.test('client: send with promise - array', async (t) => {
|
||||
const server = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(server, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', server.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
server.on('message', (msg) => {
|
||||
server.close();
|
||||
t.same(msg, ['/test', 0, 1, 'testing', true], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
await client.send(['/test', 0, 1, 'testing', true]);
|
||||
await client.close();
|
||||
});
|
||||
|
||||
tap.test('client: array is not mutated when sent with promise', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(2);
|
||||
|
||||
const originalArray = ['/test', 0, 1, 'testing', true];
|
||||
const expectedArray = ['/test', 0, 1, 'testing', true];
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 0, 1, 'testing', true], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
await client.send(originalArray);
|
||||
|
||||
// Verify the original array was not mutated
|
||||
t.same(originalArray, expectedArray, 'Original array should not be mutated');
|
||||
|
||||
await client.close();
|
||||
});
|
||||
|
||||
tap.test('client: send with promise - string', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
await client.send('/test');
|
||||
await client.close();
|
||||
});
|
||||
|
||||
tap.test('client: send with promise - message object', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 1, 2, 3, 'lol', false], 'we received the payload');
|
||||
});
|
||||
|
||||
await client.send({
|
||||
address: '/test',
|
||||
args: [1, 2, 3, 'lol', false]
|
||||
});
|
||||
await client.close();
|
||||
});
|
||||
|
||||
tap.test('client: send with promise - multiple args', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
oscServer.close();
|
||||
t.same(msg, ['/test', 1, 2, 'testing'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
await client.send('/test', 1, 2, 'testing');
|
||||
await client.close();
|
||||
});
|
||||
|
||||
tap.test('client: send promise rejection on closed socket', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
await client.close();
|
||||
await oscServer.close();
|
||||
|
||||
try {
|
||||
await client.send('/boom');
|
||||
t.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'ERR_SOCKET_DGRAM_NOT_RUNNING', 'Should reject with correct error code');
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('client: async/await usage', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
const messagePromise = node_events.once(oscServer, 'message');
|
||||
|
||||
await client.send('/async-test', 42, 'hello');
|
||||
const [receivedMessage] = await messagePromise;
|
||||
|
||||
t.same(receivedMessage, ['/async-test', 42, 'hello'], 'Message received via async/await');
|
||||
|
||||
await client.close();
|
||||
await oscServer.close();
|
||||
});
|
||||
|
||||
tap.test('server: close with promise', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
|
||||
t.plan(1);
|
||||
|
||||
await node_events.once(oscServer, 'listening');
|
||||
|
||||
await oscServer.close();
|
||||
t.pass('Server closed successfully with promise');
|
||||
});
|
||||
|
||||
tap.test('server: no callback still emits listening event', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
|
||||
t.plan(1);
|
||||
|
||||
await node_events.once(oscServer, 'listening');
|
||||
t.pass('listening event emitted');
|
||||
|
||||
await oscServer.close();
|
||||
});
|
||||
|
||||
tap.test('client and server: full async/await workflow', async (t) => {
|
||||
t.plan(3);
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
|
||||
// Wait for server to be ready
|
||||
await node_events.once(oscServer, 'listening');
|
||||
t.pass('Server started');
|
||||
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
t.pass('Client created');
|
||||
|
||||
// Set up message handler
|
||||
const messageReceived = node_events.once(oscServer, 'message');
|
||||
|
||||
// Send message and wait for it to be received
|
||||
await client.send('/workflow', 'test', 123);
|
||||
const [msg] = await messageReceived;
|
||||
t.same(msg, ['/workflow', 'test', 123], 'Message received correctly');
|
||||
|
||||
// Clean up
|
||||
await client.close();
|
||||
await oscServer.close();
|
||||
});
|
||||
|
||||
tap.test('client: multiple sends with promises', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
t.plan(3);
|
||||
|
||||
const messages = [];
|
||||
oscServer.on('message', (msg) => {
|
||||
messages.push(msg);
|
||||
});
|
||||
|
||||
await client.send('/msg1', 1);
|
||||
await client.send('/msg2', 2);
|
||||
await client.send('/msg3', 3);
|
||||
|
||||
// Give a little time for all messages to be received
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
t.equal(messages.length, 3, 'Received all three messages');
|
||||
t.same(messages[0], ['/msg1', 1], 'First message correct');
|
||||
t.same(messages[2], ['/msg3', 3], 'Last message correct');
|
||||
|
||||
await client.close();
|
||||
await oscServer.close();
|
||||
});
|
||||
|
||||
tap.test('client: close promise rejection on error', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', t.context.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
// Mock the socket's close method to simulate an error
|
||||
const originalClose = client._sock.close.bind(client._sock);
|
||||
|
||||
// Set up teardown to ensure socket is properly closed
|
||||
t.teardown(() => {
|
||||
// Restore original close method first
|
||||
client._sock.close = originalClose;
|
||||
// Then close the socket
|
||||
try {
|
||||
client._sock.close(() => {});
|
||||
} catch {
|
||||
// Socket might already be closed, that's ok
|
||||
}
|
||||
});
|
||||
|
||||
client._sock.close = function(cb) {
|
||||
// Simulate an error being passed to callback
|
||||
if (cb) {
|
||||
const err = new Error('Mock close error');
|
||||
err.code = 'MOCK_ERROR';
|
||||
setImmediate(() => cb(err));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
await oscServer.close();
|
||||
await client.close();
|
||||
t.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'MOCK_ERROR', 'Should reject with mock error');
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('server: close promise rejection on error', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
|
||||
t.plan(1);
|
||||
|
||||
await node_events.once(oscServer, 'listening');
|
||||
|
||||
// Mock the socket's close method to simulate an error
|
||||
const originalClose = oscServer._sock.close.bind(oscServer._sock);
|
||||
|
||||
// Set up teardown to ensure socket is properly closed
|
||||
t.teardown(() => {
|
||||
// Restore original close method first
|
||||
oscServer._sock.close = originalClose;
|
||||
// Then close the socket
|
||||
try {
|
||||
oscServer._sock.close(() => {});
|
||||
} catch {
|
||||
// Socket might already be closed, that's ok
|
||||
}
|
||||
});
|
||||
|
||||
oscServer._sock.close = function(cb) {
|
||||
// Simulate an error being passed to callback
|
||||
if (cb) {
|
||||
const err = new Error('Mock close error');
|
||||
err.code = 'MOCK_ERROR';
|
||||
setImmediate(() => cb(err));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
await oscServer.close();
|
||||
t.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'MOCK_ERROR', 'Should reject with mock error');
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('client: send promise rejection on send error', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(1);
|
||||
|
||||
// Mock the socket's send method to simulate an error
|
||||
const originalSend = client._sock.send;
|
||||
client._sock.send = function(msg, offset, length, port, address, callback) {
|
||||
// Simulate an error being passed to callback
|
||||
const err = new Error('Mock send error');
|
||||
err.code = 'MOCK_SEND_ERROR';
|
||||
if (callback) {
|
||||
setImmediate(() => callback(err));
|
||||
}
|
||||
};
|
||||
|
||||
t.teardown(async () => {
|
||||
client._sock.send = originalSend;
|
||||
await client.close();
|
||||
await oscServer.close();
|
||||
});
|
||||
|
||||
try {
|
||||
await client.send('/test', 'data');
|
||||
t.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'MOCK_SEND_ERROR', 'Should reject with mock send error');
|
||||
}
|
||||
});
|
||||
102
backend/node_modules/node-osc/dist/test/test-server.js
generated
vendored
Normal file
102
backend/node_modules/node-osc/dist/test/test-server.js
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
'use strict';
|
||||
|
||||
var node_events = require('node:events');
|
||||
var tap = require('tap');
|
||||
var nodeOsc = require('node-osc');
|
||||
|
||||
tap.test('server: create and close', async (t) => {
|
||||
t.plan(1);
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
oscServer.close((err) => {
|
||||
t.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('server: listen to message', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0);
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(3);
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
oscServer.on('/test', (msg) => {
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
client.send('/test', (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('server: no defined host', async (t) => {
|
||||
const oscServer = new nodeOsc.Server(0);
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.plan(3);
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
oscServer.on('/test', (msg) => {
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
client.send('/test', (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('server: callback as second arg', async (t) => {
|
||||
t.plan(4);
|
||||
const oscServer = new nodeOsc.Server(0, () => {
|
||||
t.ok('callback called');
|
||||
});
|
||||
await node_events.once(oscServer, 'listening');
|
||||
const client = new nodeOsc.Client('127.0.0.1', oscServer.port);
|
||||
|
||||
t.teardown(() => {
|
||||
oscServer.close();
|
||||
client.close();
|
||||
});
|
||||
|
||||
oscServer.on('message', (msg) => {
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
oscServer.on('/test', (msg) => {
|
||||
t.same(msg, ['/test'], 'We should receive expected payload');
|
||||
});
|
||||
|
||||
client.send('/test', (err) => {
|
||||
t.error(err, 'there should be no error');
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('server: bad message', async (t) => {
|
||||
t.plan(2);
|
||||
const oscServer = new nodeOsc.Server(0, '127.0.0.1');
|
||||
await node_events.once(oscServer, 'listening');
|
||||
t.throws(() => {
|
||||
oscServer._sock.emit('message', 'whoops');
|
||||
}, /can't decode incoming message:/);
|
||||
oscServer.close((err) => {
|
||||
t.error(err);
|
||||
});
|
||||
});
|
||||
42
backend/node_modules/node-osc/dist/test/test-types.js
generated
vendored
Normal file
42
backend/node_modules/node-osc/dist/test/test-types.js
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
var tap = require('tap');
|
||||
var node_child_process = require('node:child_process');
|
||||
var node_path = require('node:path');
|
||||
var node_url = require('node:url');
|
||||
|
||||
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
||||
const __dirname$1 = node_url.fileURLToPath(new URL('.', (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('test-types.js', document.baseURI).href))));
|
||||
|
||||
// Only run in ESM mode (not when transpiled to CJS in dist/)
|
||||
// Normalize path separators for cross-platform compatibility
|
||||
const normalizedPath = __dirname$1.replace(/\\/g, '/');
|
||||
const isESM = !normalizedPath.includes('/dist/');
|
||||
|
||||
tap.test('types: TypeScript compilation', (t) => {
|
||||
let tsconfigPath;
|
||||
const testRoot = node_path.resolve(__dirname$1, isESM ? '.': '../../test');
|
||||
if (isESM) {
|
||||
tsconfigPath = node_path.join(testRoot, 'fixtures', 'types', 'tsconfig-esm.test.json');
|
||||
}
|
||||
else {
|
||||
tsconfigPath = node_path.join(testRoot, 'fixtures', 'types', 'tsconfig-cjs.test.json');
|
||||
}
|
||||
|
||||
try {
|
||||
// Run TypeScript compiler
|
||||
const cmd = 'npx tsc --project "' + tsconfigPath + '"';
|
||||
node_child_process.execSync(cmd, {
|
||||
encoding: 'utf-8',
|
||||
stdio: 'pipe',
|
||||
cwd: node_path.join(testRoot, 'fixtures', 'types')
|
||||
});
|
||||
t.pass('TypeScript types compile successfully');
|
||||
} catch (error) {
|
||||
t.fail('TypeScript compilation failed: ' + error.message);
|
||||
if (error.stdout) console.log('STDOUT:', error.stdout);
|
||||
if (error.stderr) console.log('STDERR:', error.stderr);
|
||||
}
|
||||
|
||||
t.end();
|
||||
});
|
||||
Reference in New Issue
Block a user