Source: index.js

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;