diff --git a/.eslintrc.js b/.eslintrc.js index f352c73..705b7d5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,13 +1,12 @@ module.exports = { - env: { - node: true, - commonjs: true, - es2021: true, - }, - extends: ['airbnb', 'prettier'], - parserOptions: { - ecmaVersion: 'latest', - }, - ignorePatterns: ["**/node_modules", "**/dist"] - }; - \ No newline at end of file + env: { + node: true, + commonjs: true, + es2021: true, + }, + extends: ['airbnb', 'prettier'], + parserOptions: { + ecmaVersion: 'latest', + }, + ignorePatterns: ['**/node_modules', '**/dist'], +}; diff --git a/.github/workflows/publish-osc-npm.yml b/.github/workflows/publish-osc-npm.yml index 50250e1..e8356e5 100644 --- a/.github/workflows/publish-osc-npm.yml +++ b/.github/workflows/publish-osc-npm.yml @@ -1,7 +1,7 @@ name: Publish @jwetzell/osc to npmjs on: push: - tags: + tags: - 'osc/*' jobs: publish-lib: diff --git a/.github/workflows/run-osc-tests.yml b/.github/workflows/run-osc-tests.yml index 089ccfe..c05fb14 100644 --- a/.github/workflows/run-osc-tests.yml +++ b/.github/workflows/run-osc-tests.yml @@ -22,4 +22,4 @@ jobs: - name: Install Node.js dependencies run: npm ci --workspace @jwetzell/osc - - run: npm run test --workspace @jwetzell/osc \ No newline at end of file + - run: npm run test --workspace @jwetzell/osc diff --git a/packages/osc/src/bundle.ts b/packages/osc/src/bundle.ts index dc63450..d1fc671 100644 --- a/packages/osc/src/bundle.ts +++ b/packages/osc/src/bundle.ts @@ -1,89 +1,89 @@ -import { messageFromBuffer, messageToBuffer } from "./message"; -import { OSCBundle } from "./models"; -import { oscTypeConverterMap } from "./osc-types"; +import { messageFromBuffer, messageToBuffer } from './message'; +import { OSCBundle } from './models'; +import { oscTypeConverterMap } from './osc-types'; export function bundleFromBuffer(bytes: Buffer): OSCBundle | undefined { - if (bytes.length < 8) { - throw new Error('bundle has to be at least 20 bytes'); - } - - if (bytes.subarray(0, 7).toString('ascii') !== '#bundle') { - throw new Error('bundle must start with #bundle'); - } - - const [bundleHeader, bytesAfterHeader] = oscTypeConverterMap.s.fromBuffer(bytes); - let [timeTag, bytesAfterTimeTag] = oscTypeConverterMap.t.fromBuffer(bytesAfterHeader); - - if (!Array.isArray(timeTag)) { - throw new Error('problem getting bundle time tag'); - } - - const bundleContents = []; - - let endOfBundle = false; - - let [contentSize, remainingBytes] = oscTypeConverterMap.i.fromBuffer(bytesAfterTimeTag); - if (typeof contentSize === 'number') { - while (!endOfBundle) { - if (remainingBytes.length < contentSize) { - throw new Error('bundle does not contain enough data'); - } - - const bundleContentBytes = remainingBytes.subarray(0, contentSize); - - if (bundleContentBytes[0] === 35) { - // # character indicating contents is a bundle - const content = bundleFromBuffer(bundleContentBytes); - if (content) { - bundleContents.push(content); - } - } else if (bundleContentBytes[0] === 47) { - const content = messageFromBuffer(bundleContentBytes); - if (content) { - bundleContents.push(content); - } - } else { - throw new Error('bundle contents does not look like a OSC message or bundle'); - } - - remainingBytes = remainingBytes.subarray(contentSize); - if (remainingBytes.length === 0) { - endOfBundle = true; - } - } - } - - return { - timeTag, - contents: bundleContents, - }; + if (bytes.length < 8) { + throw new Error('bundle has to be at least 20 bytes'); } - - export function bundleToBuffer(bundle: OSCBundle): Buffer { - const headerBuffer = oscTypeConverterMap.s.toBuffer('#bundle'); - - if (headerBuffer === undefined) { - throw new Error('problem encoding buffer header'); - } - - const timeTagBuffer = oscTypeConverterMap.t.toBuffer(bundle.timeTag); - - if (timeTagBuffer === undefined) { - throw new Error('problem encoding buffer time tag'); - } - - const contentsBuffers: Buffer[] = []; - - bundle.contents.forEach((bundleContent) => { - if ('address' in bundleContent) { - const contentBuffer = messageToBuffer(bundleContent); - const contentSizeBuffer = oscTypeConverterMap.i.toBuffer(contentBuffer.length); - - if (contentBuffer && contentSizeBuffer) { - contentsBuffers.push(Buffer.concat([contentSizeBuffer, contentBuffer])); - } + + if (bytes.subarray(0, 7).toString('ascii') !== '#bundle') { + throw new Error('bundle must start with #bundle'); + } + + const [bundleHeader, bytesAfterHeader] = oscTypeConverterMap.s.fromBuffer(bytes); + let [timeTag, bytesAfterTimeTag] = oscTypeConverterMap.t.fromBuffer(bytesAfterHeader); + + if (!Array.isArray(timeTag)) { + throw new Error('problem getting bundle time tag'); + } + + const bundleContents = []; + + let endOfBundle = false; + + let [contentSize, remainingBytes] = oscTypeConverterMap.i.fromBuffer(bytesAfterTimeTag); + if (typeof contentSize === 'number') { + while (!endOfBundle) { + if (remainingBytes.length < contentSize) { + throw new Error('bundle does not contain enough data'); } - }); - - return Buffer.concat([headerBuffer, timeTagBuffer, ...contentsBuffers]); - } \ No newline at end of file + + const bundleContentBytes = remainingBytes.subarray(0, contentSize); + + if (bundleContentBytes[0] === 35) { + // # character indicating contents is a bundle + const content = bundleFromBuffer(bundleContentBytes); + if (content) { + bundleContents.push(content); + } + } else if (bundleContentBytes[0] === 47) { + const content = messageFromBuffer(bundleContentBytes); + if (content) { + bundleContents.push(content); + } + } else { + throw new Error('bundle contents does not look like a OSC message or bundle'); + } + + remainingBytes = remainingBytes.subarray(contentSize); + if (remainingBytes.length === 0) { + endOfBundle = true; + } + } + } + + return { + timeTag, + contents: bundleContents, + }; +} + +export function bundleToBuffer(bundle: OSCBundle): Buffer { + const headerBuffer = oscTypeConverterMap.s.toBuffer('#bundle'); + + if (headerBuffer === undefined) { + throw new Error('problem encoding buffer header'); + } + + const timeTagBuffer = oscTypeConverterMap.t.toBuffer(bundle.timeTag); + + if (timeTagBuffer === undefined) { + throw new Error('problem encoding buffer time tag'); + } + + const contentsBuffers: Buffer[] = []; + + bundle.contents.forEach((bundleContent) => { + if ('address' in bundleContent) { + const contentBuffer = messageToBuffer(bundleContent); + const contentSizeBuffer = oscTypeConverterMap.i.toBuffer(contentBuffer.length); + + if (contentBuffer && contentSizeBuffer) { + contentsBuffers.push(Buffer.concat([contentSizeBuffer, contentBuffer])); + } + } + }); + + return Buffer.concat([headerBuffer, timeTagBuffer, ...contentsBuffers]); +} diff --git a/packages/osc/src/message.ts b/packages/osc/src/message.ts index 6ef56e8..fe51eaf 100644 --- a/packages/osc/src/message.ts +++ b/packages/osc/src/message.ts @@ -1,77 +1,76 @@ -import { OSCMessage, OSCArg, OSCType } from "./models"; -import { oscTypeConverterMap } from "./osc-types"; +import { OSCMessage, OSCArg, OSCType } from './models'; +import { oscTypeConverterMap } from './osc-types'; function argsToBuffer(args: OSCArg[]) { - const argBuffers: Buffer[] = []; - - for (let index = 0; index < args.length; index += 1) { - const arg = args[index]; - const typeConverter = oscTypeConverterMap[arg.type]; - if (typeConverter === undefined) { - throw new TypeError('unknown type '.concat(arg.type)); - } - - const buffer = typeConverter.toBuffer(arg.value); - if (buffer !== undefined) { - argBuffers.push(buffer); - } + const argBuffers: Buffer[] = []; + + for (let index = 0; index < args.length; index += 1) { + const arg = args[index]; + const typeConverter = oscTypeConverterMap[arg.type]; + if (typeConverter === undefined) { + throw new TypeError('unknown type '.concat(arg.type)); } - return Buffer.concat(argBuffers); + + const buffer = typeConverter.toBuffer(arg.value); + if (buffer !== undefined) { + argBuffers.push(buffer); + } + } + return Buffer.concat(argBuffers); +} + +export function messageToBuffer(message: OSCMessage): Buffer { + const addressBuffer = oscTypeConverterMap.s.toBuffer(message.address); + if (addressBuffer === undefined) { + throw new Error('problem encoding address'); } - -export function messageToBuffer(message: OSCMessage): Buffer { - const addressBuffer = oscTypeConverterMap.s.toBuffer(message.address); - if (addressBuffer === undefined) { - throw new Error('problem encoding address'); - } - - const typeString = message.args.map((arg) => arg.type).join(''); - const typesBuffer = oscTypeConverterMap.s.toBuffer(`,${typeString}`); - if (typesBuffer === undefined) { - throw new Error('problem encoding types'); - } - const argsBuffer = argsToBuffer(message.args); - return Buffer.concat([addressBuffer, typesBuffer, argsBuffer]); + const typeString = message.args.map((arg) => arg.type).join(''); + const typesBuffer = oscTypeConverterMap.s.toBuffer(`,${typeString}`); + if (typesBuffer === undefined) { + throw new Error('problem encoding types'); } - - export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined { - if (bytes[0] !== 47) { - throw new Error('osc message must start with a /'); - } - - const oscArgs: OSCArg[] = []; - - const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes); - if (typeof address === 'string') { - let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress); - if (typeof typeString === 'string') { - if (!typeString.startsWith(',')) { - throw new Error('osc type string must start with a ,'); - } - let argsBuffer = bytesAfterType; - for (let index = 1; index < typeString.length; index++) { - const argType = typeString.charAt(index) as OSCType; - - const oscTypeConverter = oscTypeConverterMap[argType]; - if (oscTypeConverter === undefined) { - throw new Error('unknown OSC type'); - } - const [value, remainingBytes] = oscTypeConverter.fromBuffer(argsBuffer); - if (value !== undefined) { - const arg: OSCArg = { - type: argType, - value: value, - }; - oscArgs.push(arg); - } - argsBuffer = remainingBytes; - } - - return { - address, - args: oscArgs, - }; + const argsBuffer = argsToBuffer(message.args); + return Buffer.concat([addressBuffer, typesBuffer, argsBuffer]); +} + +export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined { + if (bytes[0] !== 47) { + throw new Error('osc message must start with a /'); + } + + const oscArgs: OSCArg[] = []; + + const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes); + if (typeof address === 'string') { + let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress); + if (typeof typeString === 'string') { + if (!typeString.startsWith(',')) { + throw new Error('osc type string must start with a ,'); } + let argsBuffer = bytesAfterType; + for (let index = 1; index < typeString.length; index++) { + const argType = typeString.charAt(index) as OSCType; + + const oscTypeConverter = oscTypeConverterMap[argType]; + if (oscTypeConverter === undefined) { + throw new Error('unknown OSC type'); + } + const [value, remainingBytes] = oscTypeConverter.fromBuffer(argsBuffer); + if (value !== undefined) { + const arg: OSCArg = { + type: argType, + value: value, + }; + oscArgs.push(arg); + } + argsBuffer = remainingBytes; + } + + return { + address, + args: oscArgs, + }; } - } \ No newline at end of file + } +}