UNPKG

mikronode-ng

Version:

Mikrotik API implemented in Node

693 lines (545 loc) 23.6 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Source: channel.js</title> <meta property="og:title" content=""/> <meta property="og:type" content="website"/> <meta property="og:image" content=""/> <meta property="og:url" content=""/> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <script src="scripts/jquery.min.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css"> <link type="text/css" rel="stylesheet" href="styles/jaguar.css"> <script> var config = {"monospaceLinks":true,"cleverLinks":true,"default":{"outputSourceFiles":true},"applicationName":"MikroNode","disqus":"","googleAnalytics":"","openGraph":{"title":"","type":"website","image":"","site_name":"","url":""},"meta":{"title":"","description":"","keyword":""},"linenums":false}; </script> </head> <body> <div id="wrap" class="clearfix"> <div class="navigation"> <h3 class="applicationName"><a href="index.html">MikroNode</a></h3> <div class="search"> <input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations"> </div> <ul class="list"> <li class="item" data-name="mikronode-ng"> <span class="title"> <a href="mikronode-ng.html">mikronode-ng</a> <span class="static">static</span> </span> <ul class="members itemMembers"> </ul> <ul class="typedefs itemMembers"> </ul> <ul class="methods itemMembers"> <span class="subtitle">Methods</span> <li data-name="mikronode-ng.getConnection"><a href="mikronode-ng.html#.getConnection">getConnection</a></li> <li data-name="mikronode-ng.parseItems"><a href="mikronode-ng.html#.parseItems">parseItems</a></li> </ul> <ul class="events itemMembers"> </ul> </li> <li class="item" data-name="mikronode-ng.Channel"> <span class="title"> <a href="mikronode-ng.Channel.html">mikronode-ng.Channel</a> </span> <ul class="members itemMembers"> <span class="subtitle">Members</span> <li data-name="mikronode-ng.Channel#clearEvents"><a href="mikronode-ng.Channel.html#clearEvents">clearEvents</a></li> <li data-name="mikronode-ng.Channel#closed"><a href="mikronode-ng.Channel.html#closed">closed</a></li> <li data-name="mikronode-ng.Channel#closeOnDone"><a href="mikronode-ng.Channel.html#closeOnDone">closeOnDone</a></li> <li data-name="mikronode-ng.Channel#closing"><a href="mikronode-ng.Channel.html#closing">closing</a></li> <li data-name="mikronode-ng.Channel#id"><a href="mikronode-ng.Channel.html#id">id</a></li> <li data-name="mikronode-ng.Channel#lastCommand"><a href="mikronode-ng.Channel.html#lastCommand">lastCommand</a></li> <li data-name="mikronode-ng.Channel#running"><a href="mikronode-ng.Channel.html#running">running</a></li> <li data-name="mikronode-ng.Channel#saveBuffer"><a href="mikronode-ng.Channel.html#saveBuffer">saveBuffer</a></li> </ul> <ul class="typedefs itemMembers"> <span class="subtitle">Typedefs</span> <li data-name="mikronode-ng.Channel.writeCallback"><a href="mikronode-ng.Channel.html#.writeCallback">writeCallback</a></li> </ul> <ul class="methods itemMembers"> <span class="subtitle">Methods</span> <li data-name="mikronode-ng.Channel#close"><a href="mikronode-ng.Channel.html#close">close</a></li> <li data-name="mikronode-ng.Channel#finalize"><a href="mikronode-ng.Channel.html#finalize">finalize</a></li> <li data-name="mikronode-ng.Channel#write"><a href="mikronode-ng.Channel.html#write">write</a></li> </ul> <ul class="events itemMembers"> <span class="subtitle">Events</span> <li data-name="mikronode-ng.Channel#event:close"><a href="mikronode-ng.Channel.html#event:event:close">event:close</a></li> <li data-name="mikronode-ng.Channel#event:done"><a href="mikronode-ng.Channel.html#event:event:done">event:done</a></li> <li data-name="mikronode-ng.Channel#event:error"><a href="mikronode-ng.Channel.html#event:event:error">event:error</a></li> <li data-name="mikronode-ng.Channel#event:timeout"><a href="mikronode-ng.Channel.html#event:event:timeout">event:timeout</a></li> <li data-name="mikronode-ng.Channel#event:trap"><a href="mikronode-ng.Channel.html#event:event:trap">event:trap</a></li> </ul> </li> <li class="item" data-name="mikronode-ng.Connection"> <span class="title"> <a href="mikronode-ng.Connection.html">mikronode-ng.Connection</a> </span> <ul class="members itemMembers"> <span class="subtitle">Members</span> <li data-name="mikronode-ng.Connection#channels"><a href="mikronode-ng.Connection.html#channels">channels</a></li> <li data-name="mikronode-ng.Connection#closeOnDone"><a href="mikronode-ng.Connection.html#closeOnDone">closeOnDone</a></li> <li data-name="mikronode-ng.Connection#host"><a href="mikronode-ng.Connection.html#host">host</a></li> <li data-name="mikronode-ng.Connection#password"><a href="mikronode-ng.Connection.html#password">password</a></li> <li data-name="mikronode-ng.Connection#port"><a href="mikronode-ng.Connection.html#port">port</a></li> <li data-name="mikronode-ng.Connection#status"><a href="mikronode-ng.Connection.html#status">status</a></li> <li data-name="mikronode-ng.Connection#timeout"><a href="mikronode-ng.Connection.html#timeout">timeout</a></li> <li data-name="mikronode-ng.Connection#tls"><a href="mikronode-ng.Connection.html#tls">tls</a></li> <li data-name="mikronode-ng.Connection#user"><a href="mikronode-ng.Connection.html#user">user</a></li> </ul> <ul class="typedefs itemMembers"> <span class="subtitle">Typedefs</span> <li data-name="mikronode-ng.Connection.connectCallback"><a href="mikronode-ng.Connection.html#.connectCallback">connectCallback</a></li> </ul> <ul class="methods itemMembers"> <span class="subtitle">Methods</span> <li data-name="mikronode-ng.Connection.parseItems"><a href="mikronode-ng.Connection.html#.parseItems">parseItems</a></li> <li data-name="mikronode-ng.Connection#closeChannel"><a href="mikronode-ng.Connection.html#closeChannel">closeChannel</a></li> <li data-name="mikronode-ng.Connection#connect"><a href="mikronode-ng.Connection.html#connect">connect</a></li> <li data-name="mikronode-ng.Connection#getChannel"><a href="mikronode-ng.Connection.html#getChannel">getChannel</a></li> <li data-name="mikronode-ng.Connection#getCommandPromise"><a href="mikronode-ng.Connection.html#getCommandPromise">getCommandPromise</a></li> <li data-name="mikronode-ng.Connection#getConnectPromise"><a href="mikronode-ng.Connection.html#getConnectPromise">getConnectPromise</a></li> <li data-name="mikronode-ng.Connection#openChannel"><a href="mikronode-ng.Connection.html#openChannel">openChannel</a></li> </ul> <ul class="events itemMembers"> <span class="subtitle">Events</span> <li data-name="mikronode-ng.Connection#event:close"><a href="mikronode-ng.Connection.html#event:event:close">event:close</a></li> <li data-name="mikronode-ng.Connection#event:error"><a href="mikronode-ng.Connection.html#event:event:error">event:error</a></li> <li data-name="mikronode-ng.Connection#event:timeout"><a href="mikronode-ng.Connection.html#event:event:timeout">event:timeout</a></li> <li data-name="mikronode-ng.Connection#event:trap"><a href="mikronode-ng.Connection.html#event:event:trap">event:trap</a></li> </ul> </li> <li class="item" data-name="mikronode-ng.Trap"> <span class="title"> <a href="mikronode-ng.Trap.html">mikronode-ng.Trap</a> </span> <ul class="members itemMembers"> <span class="subtitle">Members</span> <li data-name="mikronode-ng.Trap#channel"><a href="mikronode-ng.Trap.html#channel">channel</a></li> <li data-name="mikronode-ng.Trap#channelId"><a href="mikronode-ng.Trap.html#channelId">channelId</a></li> <li data-name="mikronode-ng.Trap#errors"><a href="mikronode-ng.Trap.html#errors">errors</a></li> </ul> <ul class="typedefs itemMembers"> </ul> <ul class="methods itemMembers"> </ul> <ul class="events itemMembers"> </ul> </li> <li class="item" data-name="mikronode-ng.TrapError"> <span class="title"> <a href="mikronode-ng.TrapError.html">mikronode-ng.TrapError</a> </span> <ul class="members itemMembers"> <span class="subtitle">Members</span> <li data-name="mikronode-ng.TrapError#category"><a href="mikronode-ng.TrapError.html#category">category</a></li> <li data-name="mikronode-ng.TrapError#message"><a href="mikronode-ng.TrapError.html#message">message</a></li> </ul> <ul class="typedefs itemMembers"> </ul> <ul class="methods itemMembers"> </ul> <ul class="events itemMembers"> </ul> </li> </ul> </div> <div class="main"> <h1 class="page-title" data-filename="channel.js.html">Source: channel.js</h1> <section> <article> <pre class="prettyprint source "><code>var events = require('events'); var crypto = require('crypto'); var util = require('util'); var dbg = require('debug'); var utils = require('./utils'); module.exports = (function() { var debugChannel = dbg('mikronode-ng:channel'); var debugChannelData = dbg('mikronode-ng:channel:data'); var _ = require('private-parts').createKey(); /** * writeCallback * @callback mikronode-ng.Channel.writeCallback * @param {Channel} */ /** * Emitted when a command has finished successfully. * @event mikronode-ng.Channel#event:done * @property {(string|string[])} data - The data returned by the channel * @property {Channel} channel - The channel originating the event Fatal event. */ /** * Emitted when a non-recoverable error has occurred on the socket. No further commands * can be processed on any channel. * @event mikronode-ng.Channel#event:error * @property {error} error - The error object * @property {Channel} channel - The channel originating the event */ /** * Emitted when a socket has been idle too long. * @event mikronode-ng.Channel#event:timeout * @property {string} message - 'Socket Timeout' * @property {boolean} socketStillOpen - If true, communications can continue * @property {Channel} channel - The channel originating the event */ /** * Emitted when the channel is closed either by an explicit call to * {@link mikronode-ng.Channel#close} or when the channel is closed automatically via * {@link mikronode-ng.Channel#closeOnDone} * @event mikronode-ng.Channel#event:close * @property {Channel} channel - The channel originating the event */ /** * Emitted when a command has failed. Subsequent commands may succeed. * @event mikronode-ng.Channel#event:trap * @property {mikronode-ng.Trap} trap - The trap object */ /** * Channel (should not be instantiated directly) * @exports mikronode-ng.Channel * @implements {EventEmitter} * @class * @param {number} id * @param {mikronode-ng.Connection} conn * @fires mikronode-ng.Channel#event:done * @fires mikronode-ng.Channel#event:trap * @fires mikronode-ng.Channel#event:error * @fires mikronode-ng.Channel#event:timeout * @fires {mikronode-ng.Channel#event:close} */ function Channel(id, conn) { debugChannel('Opening channel: ' + id); /** * Channel ID * @public * @readonly * @instance * @member {number} id * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'id', id, false, _); /** * Connection * @private * @readonly * @instance * @member {mikronode-ng.Connection} connection * @memberof mikronode-ng.Channel */ _(this).connection = conn; /** * @public * @readonly * @instance * @member {boolean} running * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'running', false, false, _); /** * @public * @readonly * @instance * @member {boolean} closing * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'closing', false, false, _); /** * @public * @readonly * @instance * @member {boolean} closed * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'closed', false, false, _); /** * Clear event listeners on done * @public * @instance * @member {boolean} clearEvents * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'clearEvents', false, true, _); /** * Save each line received in a buffer and pass the entire buffer to the done event. * Otherwise the done event will not get all the lines, only the last line. This is * handy when following trailing output from a listen command, where the data could * be endless. * @public * @instance * @member {boolean} saveBuffer * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'saveBuffer', true, true, _); /** * Close channel on done * @public * @instance * @member {boolean} closeOnDone * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'closeOnDone', false, true, _); /** * @public * @readonly * @instance * @member {string[]} lastCommand * @memberof mikronode-ng.Channel */ utils.createProperty(this, 'lastCommand', [], false, _, true); /** * @private * @instance * @member {mikronode-ng.Channel.writeCallback} writeCallback * @memberof mikronode-ng.Channel */ _(this).writeCallback = null; /** * @private * @instance * @member {array} packet * @memberof mikronode-ng.Channel */ _(this).packet = []; /** * @private * @instance * @member {array} commands * @memberof mikronode-ng.Channel */ _(this).commands = []; /** * @private * @instance * @member {array} buffer * @memberof mikronode-ng.Channel */ _(this).buffer = []; /* We want connection errors to propogate down to * the channel so they can be caught by a channel promise */ var _this = this; /* A 'error' event is thrown by Socket * and are non-recoverable so we force close the channel. */ _(this).errorListener = utils.makeListener(this.errorListener, this); conn.once('error', _(this).errorListener); /* A 'timeout' event is thrown by Socket * but they are recoverable. If Connection has closed * the Socket, we'll close the channel. Otherwise, just * notify receivers and let them decide what to do. */ _(this).timeoutListener = utils.makeListener(this.timeoutListener, this); conn.on('timeout', _(this).timeoutListener); } util.inherits(Channel, events.EventEmitter); Channel.prototype.errorListener = function errorListener(err) { debugChannel('Channel %s caught Connection Error: %o', _(this).id, _(this).connection); this.emit('error', err, this); this.close(true); }; Channel.prototype.timeoutListener = function timeoutListener(message, socketStillOpen) { debugChannel('Channel %s caught Timeout', _(this).id); this.emit('timeout', message, socketStillOpen, this); if (!socketStillOpen) { this.close(true); } }; /** * Writes data to the channel * @param {(string|string[])} data - Can be a single string with the command and * optional parameters separated by '\n' or an array of strings with the * command in the first position and the parameters in the rest. * @param {(object|string[])} [parameters] - If the first parameter is a command * string, this object will be treated as the parameters for the command. * &lt;p> * It can be an array or strings... * * &lt;pre> * ['name=value','name=value'...] * &lt;/pre> * * or an Object... * * &lt;pre> * {'name': 'value', 'name': 'value'...} * &lt;/pre> * * @param {mikronode-ng.Channel.writeCallback} [writeCallback] - This will be called * just before write actually writes the data to the connection. */ Channel.prototype.write = function write(d, parameters, writeCallback) { if (_(this).closing) { return; } if (d) { if (typeof (d) === 'string') { d = d.split("\n"); } if (typeof parameters !== 'function') { if (Array.isArray(parameters)) { Array.prototype.push.apply(d, parameters); } else if (parameters instanceof Object) { Object.keys(parameters).forEach(function(k) { d.push(k + '=' + parameters[k]); }); } } else if (writeCallback === undefined) { writeCallback = parameters; } if (Array.isArray(d) &amp;&amp; d.length) { _(this).buffer = _(this).buffer.concat(d); } else { return; } } else { debugChannel('Channel %s write: empty arg.', _(this).id); } if (_(this).running) { _(this).lastCommand = _(this).buffer; if (debugChannelData.enabled) { debugChannelData('Channel %s running: pushing command %o', _(this).id, _(this).lastCommand); } else { debugChannel('Channel %s running: pushing command', _(this).id); } _(this).commands.push([ _(this).buffer, writeCallback ]); _(this).buffer = []; } else { _(this).lastCommand = _(this).buffer; var b = _(this).buffer; _(this).running = true; _(this).saveBuffer = true; _(this).buffer = []; b.push('.tag=' + _(this).id); if (writeCallback) { writeCallback(this); } if (debugChannelData.enabled) { debugChannelData('Channel %s idle: writing %o', _(this).id, _(this).lastCommand); } else { debugChannel('Channel %s idle: writing', _(this).id); } _(this).connection._write(b); // Send command. } }; /** * Called when connection gets 'done' * @private * @param {(string|string[])} data */ Channel.prototype._done = function _done(data, trap) { if (trap) { debugChannel('Channel %s trap: %o', _(this).id, trap); this.emit('trap', trap, this); } else { var p = _(this).packet; _(this).packet = []; if (!p.length) { p = [ data ]; } else if (p[p.length - 1] !== data) { p.push(data); } if (debugChannelData.enabled) { debugChannelData('Channel %s done: %o', _(this).id, p); } else { debugChannel('Channel %s done', _(this).id); } this.emit('done', p, this); } if (_(this).clearEvents) { this.removeAllListeners('done'); this.removeAllListeners('data'); this.removeAllListeners('read'); } _(this).running = false; if (_(this).commands.length) { var c = _(this).commands.shift(); var cl = _(this).closing; _(this).closing = false; debugChannel('Channel %s more commands', _(this).id); this.write(c[0], {}, c[1]); _(this).closing = cl; } else if (_(this).closing || _(this).closeOnDone) { this.close(); } }; /** * Called when connection gets 'data' * @private * @param {(string|string[])} data */ Channel.prototype._data = function _data(data) { if (debugChannelData.enabled) { debugChannelData('Channel %s data: %o', _(this).id, data); } else { debugChannel('Channel %s data', _(this).id); } if (_(this).saveBuffer) { _(this).packet.push(data); } this.emit('data', [ data ], this); this.emit('read', [ data ], this); }; /** * Closes the channel This will close the connection if * {@link mikronode-ng.Connection#closeOnDone} was set and this was the last channel to * close. * @public * @param {boolean} force - Force close even of there are other commands pending. * Otherwise mark the channel as 'closing' which will prevent new commands * from being started but will let queued ones finish. */ Channel.prototype.close = function close(force) { // Close _(this) channel. _(this).closing = true; if (_(this).closed || (!force &amp;&amp; (_(this).commands.length || _(this).running))) { debugChannel('Channel %s closing deferred', _(this).id); return; } debugChannel('Channel %s closing. Forced: %s', _(this).id, force ? 'true' : 'false'); if (_(this).running) { try { debugChannel('Channel %s sending cancel', _(this).id); _(this).connection._write([ '/cancel', '=tag=' + _(this).id ]); } catch (err) { debugChannel('Error sending /cancel', err.stack); } } _(this).connection.removeListener('error', _(this).errorListener); _(this).connection.removeListener('timeout', _(this).timeoutListener); debugChannel('Channel %s closed', _(this).id); _(this).closed = true; this.emit('close', this); this.removeAllListeners(); }; /** * Calls {@link mikronode-ng.Channel#close}(false) * @public */ Channel.prototype.finalize = function finalize() { debugChannel('Channel %s finalize', _(this).id); if (!_(this).closing) { this.close(); } }; return Channel; })(); </code></pre> </article> </section> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Wed Jul 06 2016 06:45:18 GMT-0600 (MDT) </footer> </div> </div> <script>prettyPrint();</script> <script src="scripts/linenumber.js"></script> <script src="scripts/main.js"></script> </body> </html>