mikronode-ng
Version:
Mikrotik API implemented in Node
693 lines (545 loc) • 23.6 kB
HTML
<!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.
* <p>
* It can be an array or strings...
*
* <pre>
* ['name=value','name=value'...]
* </pre>
*
* or an Object...
*
* <pre>
* {'name': 'value', 'name': 'value'...}
* </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) && 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 && (_(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>