onvif
Version:
Client to ONVIF NVT devices Profile S: cameras
200 lines (170 loc) • 6.56 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: discovery.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.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/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: discovery.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @namespace discovery
* @description Discovery module
* @author Andrew D.Laptev <a.d.laptev@gmail.com>
* @licence MIT
*/
const
Cam = require('./cam').Cam
, events = require('events')
, guid = require('./utils').guid
, linerase = require('./utils').linerase
, parseSOAPString = require('./utils').parseSOAPString
, url = require('url')
;
/**
* Discovery singleton
* @type {Object}
* @class
*/
var Discovery = Object.create(new events.EventEmitter());
/**
* @callback Discovery~ProbeCallback
* @property {?Error} error
* @property {Array<Cam|object>} found devices
*/
/**
* Discover NVT devices in the subnetwork
* @param {object} [options]
* @param {number} [options.timeout=5000] timeout in milliseconds for discovery responses
* @param {boolean} [options.resolve=true] set to `false` if you want omit creating of Cam objects
* @param {string} [options.messageId=GUID] WS-Discovery message id
* @param {Discovery~ProbeCallback} [callback] timeout callback
* @fires Discovery#device
* @fires Discovery#error
* @example
* var onvif = require('onvif');
* onvif.Discovery.on('device', function(cam){
* // function would be called as soon as NVT responses
* cam.username = <USERNAME>;
* cam.password = <PASSWORD>;
* cam.connect(console.log);
* })
* onvif.Discovery.probe();
* @example
* var onvif = require('onvif');
* onvif.Discovery.probe(function(err, cams) {
* // function would be called only after timeout (5 sec by default)
* if (err) { throw err; }
* cams.forEach(function(cam) {
* cam.username = <USERNAME>;
* cam.password = <PASSWORD>;
* cam.connect(console.log);
* });
* });
*/
Discovery.probe = function(options, callback) {
if (callback === undefined) {
if (typeof options === 'function') {
callback = options;
options = {};
} else {
options = options || {};
}
}
callback = callback || function() {};
var cams = {}
, errors = []
, messageID = 'urn:uuid:' + (options.messageId || guid())
, request = new Buffer(
'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:dn="http://www.onvif.org/ver10/network/wsdl">' +
'<Header>' +
'<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">' + messageID + '</wsa:MessageID>' +
'<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>' +
'<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>' +
'</Header>' +
'<Body>' +
'<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
'<Types>dn:NetworkVideoTransmitter</Types>' +
'<Scopes />' +
'</Probe>' +
'</Body>' +
'</Envelope>'
)
, socket = require('dgram').createSocket('udp4');
socket.on('error', function(err) {
Discovery.emit('error', err);
callback(err);
});
const listener = function(msg, rinfo) {
parseSOAPString(msg.toString(), function(err, data, xml) {
// TODO check for matching RelatesTo field and messageId
if (err || !data[0].probeMatches) {
errors.push(err || new Error('Wrong SOAP message from ' + rinfo.address + ':' + rinfo.port, xml));
/**
* Indicates error response from device.
* @event Discovery#error
* @type {string}
*/
Discovery.emit('error', 'Wrong SOAP message from ' + rinfo.address + ':' + rinfo.port, xml);
} else {
data = linerase(data);
// Possible to get multiple matches for the same camera
// when your computer has more than one network adapter in the same subnet
var camAddr = data.probeMatches.probeMatch.endpointReference.address;
if (!cams[camAddr]) {
var cam;
if (options.resolve !== false) {
var camUri = url.parse(data.probeMatches.probeMatch.XAddrs);
cam = new Cam({
hostname: camUri.hostname
, port: camUri.port
, path: camUri.path
});
} else {
cam = data;
}
cams[camAddr] = cam;
/**
* Indicates discovered device.
* @event Discovery#device
* @type {Cam|object}
*/
Discovery.emit('device', cam, rinfo, xml);
}
}
});
};
socket.on('message', listener);
socket.send(request, 0, request.length, 3702, '239.255.255.250');
setTimeout(function() {
socket.removeListener('message', listener);
socket.close();
callback(errors.length ? errors : null, Object.keys(cams).map(function(addr) { return cams[addr]; }));
}.bind(this), options.timeout || 5000);
};
module.exports = {
Discovery: Discovery
};</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Cam_.html">Cam</a></li><li><a href="Discovery_.html">Discovery</a></li></ul><h3>Events</h3><ul><li><a href="Cam_.html#event:event">event</a></li><li><a href="Cam_.html#event:rawResponse">rawResponse</a></li><li><a href="Discovery_.html#event:device">device</a></li><li><a href="Discovery_.html#event:error">error</a></li></ul><h3>Namespaces</h3><ul><li><a href="cam.html">cam</a></li><li><a href="discovery.html">discovery</a></li><li><a href="utils.html">utils</a></li></ul><h3>Global</h3><ul><li><a href="global.html#guid">guid</a></li><li><a href="global.html#linerase">linerase</a></li><li><a href="global.html#parseSOAPString">parseSOAPString</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Mon Jun 20 2016 15:42:17 GMT+0300 (MSK)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>