import net from 'net'; import * as _ from 'lodash'; const Promise = require('bluebird'); const log = require('debug')(__filename); const pipeName = '\\\\.\\pipe\\sp_remote_control'; const tracker = log.extend('trace'); tracker.log = (data, ...args) => { console.error('Function %s was called', data, ...args); }; class Soundpad { /** * @constructor * @param {object} connectionSettings - Settings of connecting Soundpad */ constructor(connectionSettings) { tracker('constructor'); this.connected = false; this.pipe = false; this.intervalTimeout = false; this.writing = false; connectionSettings = _.defaults(connectionSettings, { autoReconnect: true, pollingInterval: 1000, reconnectInterval: 1000, timeout: 1000 }); this.autoReconnect = connectionSettings.autoReconnect; this.connectionTimeout = connectionSettings.timeout; this.pollingInterval = connectionSettings.pollingInterval; this.reconnectInterval = connectionSettings.reconnectInterval; this.timeout = connectionSettings.timeout; } /** * Connects to Soundpad * @returns {Promise} Resolves the Soundpad instance when connected Soundpad successfully */ connect() { tracker('connect'); return new Promise((resolve, reject) => { if (this.connected) { reject(new Error('Soundpad already connected')); } const socket = net.createConnection({ path: pipeName, timeout: this.timeout }, () => { socket.removeAllListeners(); this.pipe = socket; this.connected = true; this.intervalTimeout = setInterval(this.poll, this.pollingInterval); resolve(this); }); socket.on('error', () => { if (this.autoReconnect) { Promise.delay(this.reconnectInterval).then(() => { this.connect().then(() => { return this; }); }); } else { reject(new Error('Soundpad could not be connected')); } }); }); } /** * Disconnects Soundpad * @returns {Promise} Resolves the Soundpad instance when disconnected Soundpad successfully. */ disconnect() { tracker('disconnect'); return new Promise((resolve, reject) => { if (this.connected) { clearInterval(this.intervalTimeout); this.pipe.end(); this.pipe = false; resolve(this); } else { reject(new Error('Soundpad is not connected or not a socket')); } }); } /** * Poll Soundpad * @returns {Promise} Resolves the Soundpad instance when Soundpad respond */ poll() { tracker('poll'); return new Promise((resolve, reject) => { this.send('IsAlive()').then(() => { resolve(this); }, error => { reject(error); }); }); } /** * Send `data` to Soundpad * @param {string|Buffer|Uint8Array} data - Data which will be sent. * @param {boolean} hasResponse - Wait until Soundpad respond? * @returns {Promise} Resolves response if `hasResponse` is `true`, * or resolves the Soundpad instance when the data is sent */ send(data, hasResponse = false) { tracker('send'); return new Promise((resolve, reject) => { if (this.writing) { reject(new Error('Cannot send data while other data is being sent')); } if (this.connected) { this.writing = true; if (typeof data === 'string') { data = Buffer.from(data); } if (hasResponse) { this.pipe.on('data', data => { this.pipe.removeAllListeners('data'); this.writing = false; resolve(data); }); } this.pipe.write(data, 'utf8', () => { if (!hasResponse) { this.writing = false; resolve(this); } }); if (this.writing) { reject(new Error('Could not be sent to Soundpad')); } } else { reject(new Error('Soundpad is not connected or not a socket')); } }); } } module.exports = Soundpad; module.exports.pipeName = pipeName;