diff --git a/lib/jamserver/constants.js b/lib/jamserver/constants.js index 93ab1e70..affa3ec7 100644 --- a/lib/jamserver/constants.js +++ b/lib/jamserver/constants.js @@ -45,13 +45,14 @@ module.exports = Object.freeze({ retryInterval: 2000, // 2 seconds longRetryInterval: 60000, // 1 minute localBrokerUrl: 'http://localhost:1883', - brokerUrl: 'tcp://jamscript.madhacker.biz:1883' + brokerUrl: 'http://localhost:1884' }, mdns: { - retries: 5, - retryInterval: 2000, // 2 seconds - longRetryInterval: 60000 // 1 minute + retryInterval: 2000, + heartBeatPort: 5454, + heartBeatMulticastAddress: '239.0.0.251', + heartBeatTTL: 1000 }, localStorage: { diff --git a/lib/jamserver/jamlib.js b/lib/jamserver/jamlib.js index c1bf7da6..ef89530f 100644 --- a/lib/jamserver/jamlib.js +++ b/lib/jamserver/jamlib.js @@ -6,7 +6,7 @@ // Load the global modules const mqtt = require('mqtt'), - os = require('os'), + os = require('os'), globals = require('./constants').globals; // Do command line processing... @@ -26,11 +26,11 @@ var machType = getMachineType(cmdopts); deviceParams.setItem('machType', machType); var reggie = new Registrar(cmdopts.app, machType, deviceParams.getItem('deviceId'), - cmdopts.port, {long: cmdopts.long, lat: cmdopts.lat}, { protocols: { mqtt: false, mdns: true, localStorage: false } }); + cmdopts.port, { protocols: { mqtt: true, mdns: true } }); var jamsys = require('./jamsys'); jamsys.init(reggie, machType, cmdopts.tags, cmdopts.iflow, cmdopts.oflow, deviceParams.getItem('deviceId'), - cmdopts.link, cmdopts.long, cmdopts.lat); + cmdopts.link, cmdopts.long, cmdopts.lat); jamsys.setMQTT(getMachineAddr(), cmdopts.port); @@ -39,60 +39,60 @@ jnode.init(reggie, machType); module.exports = new function() { - this.registerFuncs = registerFuncs; - this.run = run; + this.registerFuncs = registerFuncs; + this.run = run; } function run(callback) { - // Check the presence of the MQTT server. - // If not, report an error and quit + // Check the presence of the MQTT server. + // If not, report an error and quit - checkMQTTServer(function(present) { - if (!present) { - console.log("ERROR! Cannot connect to MQTT server. Exiting."); - process.exit(1); - } + checkMQTTServer(function(present) { + if (!present) { + console.log("ERROR! Cannot connect to MQTT server. Exiting."); + process.exit(1); + } if (machType === globals.NodeType.CLOUD) { reggie.registerAndDiscover(); - jnode.startService(); - jnode.startRunner(); - } else { - jnode.doRegister(); - jnode.startService(); - jnode.startRunner(); + jnode.startService(); + jnode.startRunner(); + } else { + jnode.doRegister(); + jnode.startService(); + jnode.startRunner(); - } + } - if (callback !== undefined) - callback(); - }); + if (callback !== undefined) + callback(); + }); } function registerFuncs(machbox) { - // Register all callbacks in the machbox. - // These are functions registered by the application - fkeys = Object.keys(machbox.functions); - for (i in fkeys) { - tkey = fkeys[i]; - jnode.registerCallback(tkey, machbox.functions[tkey], machbox.signatures[tkey]); - } + // Register all callbacks in the machbox. + // These are functions registered by the application + fkeys = Object.keys(machbox.functions); + for (i in fkeys) { + tkey = fkeys[i]; + jnode.registerCallback(tkey, machbox.functions[tkey], machbox.signatures[tkey]); + } } // Check whether the MQTT server is up and running.. function checkMQTTServer(callback) { - var tserv = mqtt.connect("mqtt://localhost:" + cmdopts.port ); - tserv.on('connect', function() { - tserv.end(); - callback(true); - }); - tserv.on('offline', function() { + var tserv = mqtt.connect("mqtt://localhost:" + cmdopts.port ); + tserv.on('connect', function() { + tserv.end(); + callback(true); + }); + tserv.on('offline', function() { tserv.end(); - callback(false); - }); + callback(false); + }); } diff --git a/lib/jamserver/jamsys.js b/lib/jamserver/jamsys.js index e97b87f1..77f4283a 100644 --- a/lib/jamserver/jamsys.js +++ b/lib/jamserver/jamsys.js @@ -96,7 +96,7 @@ module.exports = new function() { this.setupAdvertisement(aname); } - reggie.addAttributes(attr); + reggie.setAttributes(attr); } // Advertise aname off diff --git a/lib/jdiscovery/README.md b/lib/jdiscovery/README.md index 34eefd15..39f639ca 100644 --- a/lib/jdiscovery/README.md +++ b/lib/jdiscovery/README.md @@ -1,149 +1,183 @@ -# JAMScript Registration and Discovery - -## To Run -If on Ubuntu, or other debianesque systems, you'll need to install `libavahi-compat-libdnssd-dev` for the mdns module to work: -`sudo apt install libavahi-compat-libdnssd-dev` -You'll also need to link the mdns module, regardless of whether you're on a debianesque system: -- macOS: `cd mdns && npm link` -- Ubuntu: `cd mdns && sudo npm link --unsafe-perm` (because Ubuntu sucks) -If you want to use MQTT, start an MQTT broker: `mosquitto` - -### To run app.js -Try the following: -- `npm start device` - starts a device node -- `npm start device iPhone 1234567` - starts a device with attribute `iPhone` and phone number `1234567` -- `npm start device Android 1234567` - starts a device with attribute `Android` and phone number `1234567` -- `npm start fog` - starts a fog node -- `npm start cloud` - starts a cloud node -See `app.js` to figure out who discovers whom :) - -### If the mdns module stops working... -You should update it! Do the following: -- Run `npm pack mdns` to download the latest mdns source -- Unzip the downloaded source -- Replace the contents of the `mdns` folder in this directory with the contents of the unzipped source -- Open up `mdns/lib/service_type.js` and comment out the sections of the code that limit the length of the advertisement's name. Currently (mdns version 2.3.4), the code blocks that do this are: -``` - if (str.length > 15) { - throw new Error('type ' + str + ' has more than 15 characters'); - } -``` -``` - if (str.length > 16) { // 16 is correct because we have a leading underscore - throw new Error('type ' + _uu(str) + ' has more than 15 characters'); - } -``` -- Follow the steps in the `To Run` section above to make sure the module is properly linked +# JDISCOVERY: A Discovery Service for JAMScript -## Registrar -The `Registrar` is the object you'll be interfacing with. It is responsible for finding other nodes running the same application as this one, and making this node visible so that other nodes may find it too. You create a Registrar as follows: -``` - var reggie = new Registrar(app, machType, id, port, config); -``` -where `app` is the name of the application, `machType` (machine type) is one of 'device', 'fog', or 'cloud', `id` is the id of the node, `port` is the port it is running on, and `config` is an optional parameter with the following options: -- `protocols`: An object in which you specify what protocols you want to use. If this option is not present, all protocols will be used. e.g. To use just mDNS, you might pass -``` - { - protocols: { - mqtt: false, - mdns: true, - localStorage: false - } - } -``` -Alternatively -``` - { - protocols: { - mdns: true - } - } +JAMScript nodes discover each other using jdiscovery and its attribute system. Below, you will find a quick start guide as well as a description of its external and developer APIs. + +## Quick Setup and Demo + +### Dependencies +The following are automatically installed by the JAMScript setup scripts. +- `node.js` & `npm` +- `mosquitto` - MQTT Broker +- npm packages: `bonjour, mqtt` + +### Demo ``` -will suffice. -- `eliminateDuplicates`: Set to `true` if you want the `Registrar` to automatically eliminate duplicate discoveries, so that only one event will be returned to the app per discovery. Set this to `false` if you want to be notified separately if/when a discovery is made by each of local storage, mDNS, and MQTT. The default is `true`. +/* Source in apps/demo.js */ -Now, before we get into how to use our new Registrar object, we'll need to understand what **attributes** are. +const Registrar = require('../jregistrar-head.js'), + globals = require('../../jamserver/constants').globals, + events = require('events'); -## Attributes -The system revolves around attributes. An attribute is some aspect of a node with an associated value (or not - an attribute need not have a value). Nodes have attributes that are discoverable by other nodes. If you can follow that, then the rest should be easy - that's really all there is to it. But, to solidify the idea, here are a couple of examples: -- `thermostat` - You might give this attribute to a device that is a thermostat. The value of this attribute could be the temperature measured by the device. -- `dimmable` - Maybe you have some smart light bulbs that can be dimmed. If so, perhaps you'd want to give them this attribute. The associated value could be the percentage of full brightness that the bulb is currently set to. -- `cellPhone` - Perhaps you want a fog node to discover all nearby devices that are cell phones, for whatever reason. You could give such devices this attribute. The value of the attribute could be null if you don't need to know anything other than the fact that the device is a cell phone. Remember: you don't need to have a value associated with an attribute. +const id = process.argv[2], + type = process.argv[3], + port = process.argv[4], + app = 'tester'; -## Discovering attributes -This module is all about registration and discovery, so obviously we'll want to discover some attributes of the nodes out there. But what is out there to begin with? +console.log('_______________________________________________'); +console.log(' id: ' + id + ' type: ' + type + ' port: ' + port); +console.log('-----------------------------------------------'); +console.log(); -### Built-in attributes/discoveries -By default, each device, fog, and cloud on the network has only a single attribute: *status*. The *status* attribute is used to discover which nodes are online and which are offline. If a node is online, then its status attribute will have a value of form: -``` - { - ip: ip_addr_of_node, - port: port_of_node - } -``` -In other words, the status attribute gives you the information you need to connect to a node. If, however, the node is offline, then the value of the status attribute will be 'offline'. +// Construct registrar and start it +const reggie = new Registrar(app, type, id, port, + { protocols: { mqtt: true, mdns: true } }); +// ... if the mqtt discovery option is enabled, you need to have a broker +// ... running at the address specified in JAMScript-beta/lib/jamserver/constants.js +// ... at constants.mqtt.brokerUrl -In addition to giving each node the status attribute, the system is configured such that devices discover fog statuses and fogs discover cloud statuses, i.e. devices will be made aware of when fogs go online or offline, and fogs will be made aware of when clouds go online or offline. But how will you, as the programmer, be informed of these status updates? Status updates, and, in fact, all attribute discoveries, are emitted to the application by the Registrar. To wrap up our discussion of built-in attributes, we'll take a look at the built-in events the Registrar object emits: `fog-up`, `fog-down`, `cloud-up`, and `cloud-down`. An example is usually helpful. +reggie.registerAndDiscover(); -``` - var reggie = new Registrar(app, machType, id, port); +// Setup default discoveries +if (type === 'device') { - // devices will receive these events by default - reggie.on('fog-up', function(id, connInfo, protocol) { - console.log('Fog ' + id + ' is online, with ip ' + connInfo.ip + ' and port ' + connInfo.port); + reggie.on('fog-up', function(fogId, connInfo) { + console.log('FOG UP: id: ' + fogId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); }); - - reggie.on('fog-down', function(id, protocol) { - console.log('Fog ' + id + ' has gone offline'); + reggie.on('fog-down', function(fogId) { + console.log('FOG DOWN: id: ' + fogId); }); +} else if (type === 'fog') { - // fogs will receive these events by default - reggie.on('cloud-up', function(id, connInfo, protocol) { - console.log('Cloud ' + id + ' is online, with ip ' + connInfo.ip + ' and port ' + connInfo.port); + reggie.on('cloud-up', function(cloudId, connInfo) { + console.log('CLOUD UP: id: ' + cloudId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); }); - - reggie.on('cloud-down', function(id, protocol) { - console.log('Cloud ' + id + ' has gone offline'); + reggie.on('cloud-down', function(cloudId) { + console.log('CLOUD DOWN: id: ' + cloudId); }); +} + +// Setup custom attributes/discoveries +if (type === 'device') { + const ticker = setInterval( + /** + * XXX N.B. XXX + * The call must be bound to this scope + * using either a lambda expression, + * or, a call to bind() + * It will NOT work otherwise! + */ + (o) => { reggie.setAttributes(o); }, + 5000, + { secret : () => Math.random().toString(16) } + ); + setTimeout( + () => { + clearInterval(ticker); + reggie.removeAttributes(['secret']); + reggie.quit(); + }, + 22000 + ); +} else if (type === 'fog') { + + reggie.on('new-secret', function(id, secret) { + console.log('NEW-SECRET: id: ' + id + ' secret: ' + secret); + }); + reggie.on('no-more-secret', function(id) { + console.log('NO-MORE-SECRET: id: ' + id); + }); + reggie.discoverAttributes({ + device: { + secret: { + onAdd : 'new-secret', + onRemove : 'no-more-secret' + } + } + }); +} +``` - // clouds will not receive any such events (by default) +Open two terminals to the jdiscovery directory and run the following commands (one in each). +- `node apps/demo.js node-0 device 42420` +- `node apps/demo.js node-1 fog 42421` - // kick-start registration and discovery - reggie.registerAndDiscover(); +## API + +### Import and Constructor +``` +const Registrar = require('jdiscovery'); +const reggie = new Registrar(app, type, id, port, config); +``` +- `app`: Application name +- `type`: Node type ('device', 'fog', 'cloud') +- `id`: Node identifier (must be unique w.r.t. application name) +- `port`: Port number where the application can be reached +- `config`: Object with property `protocols` for regirstrar setup (as is for flexibility) +``` + const config = + { + protocols: { + mqtt: false, + mdns: true + } + } ``` -### Custom discoveries -We see that devices discover fogs statuses and fogs discover clouds statuses by default, but what if we're a cloud node and we want to discover fogs? No problem, we can use the `discoverAttributes` API as follows: +### reggie.registerAndDiscover(); +Kick-starts registration (announcing of attributes) and discovery. **This method must be called for the registrar to start functioning; it is best to call it right after calling the constructor.** See the demo code above for an example. -``` - var reggie = new Registrar(app, machType, id, port); +### reggie.setAttributes(attrs); +Sets the specified attributes to the node. Calling this method multiple times updates the attribute value being shared with the network. - reggie.discoverAttributes({ - fog: { - status: { - online: 'fog-up', - offline: 'fog-down' - } - } - }); +`attrs` is an object of `` pairs. The `attr` is the name of the attribute and is limited to valid JavaScript object keys. The attribute `value` can be any basic data type, `null`, a JavaScript object, or a function returning one of the previous. Note that functions should be wrapped in a lambda expression as in the example below to avoid binding issues with `this`. - // now this node (a cloud) will receive fog-up and fog-down events - reggie.on('fog-up', function(id, connInfo, protocol) { - console.log('Fog ' + id + ' is online, with ip ' + connInfo.ip + ' and port ' + connInfo.port); +Both attribute names and values **should be kept brief**. The Registrar uses MQTT and mDNS under the hood, which are both lightweight messaging protocols. You may run into some trouble if you try to send too much information! **Remember: This module is should be used for basic discovery only. If nodes need to exchange larger chunks of information, then a separate connection should be made**. +``` + // Setting an attribute once + reggie.setAttributes({ + thermostat: 20 }); + // If you want to keep the rest of the network up to date on your temperature, you can simply set an interval + // ... update the temperature every five seconds + setInterval( + /** + * XXX N.B. XXX + * The call must be bound to this scope + * using either a lambda expression, + * or, a call to bind() + * It will NOT work otherwise! + */ + (o) => { reggie.setAttributes(o); }, + 5000, + { thermostat: () => _getThermostatTemp() } + ); +``` - reggie.on('fog-down', function(id, protocol) { - console.log('Fog ' + id + ' has gone offline'); - }); +### reggie.removeAttributes(attrs); +Stop sharing the given attrs with the network. - reggie.registerAndDiscover(); -``` +`attrs` is an `Array` of `String`s (**not** just a `String`). -By this point, you're probably sick of the status attribute. Surely there are other things you'll want to discover too, for example devices that are thermostats! (exciting, right?) You're in luck! You can discover them as follows: +### reggie.discoverAttributes(dattrs); +Causes the node to begin discovering the given attributes of other nodes. +`dattrs` is an object with one or more of the following keys: +- `all`: attributes of **all** other nodes that the node should discover +- `device`: attributes of devices that the node should discover +- `fog`: attributes of fogs that the node should discover +- `cloud`: attributes of clouds that the node should discover ``` - // ... + { + all: {attr: event, ...}, // discover these attributes for all nodes + device: {attr: event, ...}, // discover these attributes just for devices + fog: {attr: event, ...}, // discover these attributes just for fogs + cloud: {attr: event, ...} // discover these attributes just for clouds + } +``` +**OR** As a shortcut for _all_, one can simply pass an object of pairs. +The value of each of these keys should be an object of `` pairs, where `attr` is the name of an attribute to be discovered, and `event` is an object with keys 'onAdd' & 'onRemove' mapped to event names which will be emitted by the Registrar on discovery (`onAdd`) or on loss (`onRemove`). +``` reggie.discoverAttributes({ device: { thermostat: { @@ -152,114 +186,34 @@ By this point, you're probably sick of the status attribute. Surely there are ot } } }); - + // register interest in these events reggie.on('i-found-a-thermostat', function(id, value, protocol) { console.log('Node ' + id + ' is apparently a thermostat with temperature ' + value); }); - reggie.on('this-node-is-no-longer-a-thermostat', function(id, protocol) { console.log('Node ' + id + ' is apparently no longer a thermostat'); }); - - // ... -``` - -Notice the parameters to the functions called upon a discovery. When a discovery is made, the following arguments are available: -- `nodeId`: the ID of the node for which the discovery was made -- `attributeValue`: the value of the attribute discovered -- `protocol`: the protocol which made the discovery - - The protocol will be one of the values defined in `../jamserver/constants.js#globals.Protocol` -When an attribute is removed from a node, or the node goes down (status becomes offline), then there are just two parameters to the function: -- `nodeId`: the ID of the node which removed the attribute, or went down -- `protocol`: the protocol which made the discovery - -Now back to attributes. If status is the only attribute that any node has by default, then how can we give nodes other attributes? This is done by announcing attributes. - -## Announcing attributes -In order to give a node an attribute, you use the `addAttributes` API. For example, to add the thermostat attribute, you could use: - -``` - // ... - - reggie.addAttributes({ - thermostat: 20 - }); - - // ... ``` - -Or, if you want to wait to provide the temperature until the exact moment that the Registrar announces the attribute on the network, you can provide a function that returns the temperature: - +The only exception to this is when discovering the `status` attribute, in which case `event` must be an object specifying two events: one to be emitted when the remote node comes up (with `online`) and another to be emitted when it goes down (with `offline`). ``` - // ... - - reggie.addAttributes({ - thermostat: function() { - return theTemperature; + reggie.discoverAttributes({ + fog: { + status: { + online: 'fog-up', + offline: 'fog-down' + } } }); - - // ... -``` - -Lastly, if you want to keep the rest of the network up to date on your temperature, you can simply set an interval: - -``` - // ... - - // update the temperature every five seconds - setInterval(reggie.addAttributes, 5000, { thermostat: theTemperature }); - - // ... -``` - -## API - -### reggie.addAttributes(attrs) -Adds the specified attributes to the node. - -`attrs` is an object of `` pairs. The `attributeName` is limited to valid JavaScript object keys. The attribute value can be any basic data type, `null`, a JavaScript object, an array, or a function that returns a basic data type, `null`, or a JavaScript object or array. - -If a function is passed, then the function will be executed to retrieve the value of the attribute just before the Registrar announces the attribute on the network. If you need to pass parameters to the function, you can use bind: -``` - var x = 10; - var y = 12; - - reggie.addAttributes({ - someAttribute: function(a, b) { - return a + b; - }.bind(null, x, y) + // register interest in these events + reggie.on('fog-up', function(id, connInfo, protocol) { + console.log('Fog ' + id + ' is online, with ip ' + connInfo.ip + ' and port ' + connInfo.port); + }); + reggie.on('fog-down', function(id, protocol) { + console.log('Fog ' + id + ' has gone offline'); }); ``` -Both the attribute name and the attribute value **should be kept brief**. The Registrar uses MQTT and mDNS under the hood, which are both lightweight messaging protocols. You may run into some trouble if you try to send too much information! **Remember: This module is should be used for basic discovery only. If nodes need to exchange larger chunks of information, then a separate connection should be made**. - -#### Reserved attributes -As a general rule, you can add any attributes that you'd like. However, the following names are reserved by the system, and cannot be reused: -- `status` -- `lastCheckIn` -- `createdAt` -- `updatedAt` - -### reggie.removeAttributes(attrs) -Removes the specified attributes from the node. - -`attrs` can be a `String` or an `Array` of `String`s. - -### reggie.discoverAttributes(dattrs) -Causes the node to begin discovering the given attributes of other nodes. - -`dattrs` is an object with one or more of the following keys: -- `all`: attributes of **all** other nodes that the node should discover -- `device`: attributes of devices that the node should discover -- `fog`: attributes of fogs that the node should discover -- `cloud`: attributes of clouds that the node should discover - -The value of each of these keys should be an object of `` pairs, where `attributeName` is the name of an attribute to be discovered, and `eventName` is the name of the event to have the Registrar emit when it makes a discovery. The only exception to this is when discovering the `status` attribute, in which case `eventName` must be an object specifying two events: one to be emitted when the remote node comes up (with key `online`) and another to be emitted when it goes down (with key `offline`), e.g. `{ online: 'aNodeWentUp', offline: 'ohNoItWentDown' }`. - -If you wish to just pass attributes to be discovered on all other nodes, regardless of device, fog, or cloud, then `dattrs` can simply be an object of `` pairs. - -### reggie.stopDiscoveringAttributes(dattrs) +### reggie.stopDiscoveringAttributes(dattrs); Tells the Registrar to stop discovering the given attributes of other nodes. `dattrs` is an object with one or more of the following keys: @@ -268,197 +222,49 @@ Tells the Registrar to stop discovering the given attributes of other nodes. - `fog`: an `Array` of attributes of fogs that the node should stop discovering - `cloud`: an `Array` of attributes of clouds that the node should stop discovering -Alternatively, if you want to stop discovering attributes on all other nodes, regardless of type, `dattrs` cam simply be an `Array` of the attribute names. - -### reggie.registerAndDiscover([options]) -Kick-starts registration (announcing of attributes) and discovery. - -`options` is an optional way to specify attributes of the node and those it should discover, rather than using `reggie.addAttributes` and `reggie.discoverAttributes`. It is an object that accepts the following `` pairs: -- `attrsToAdd`: an object of the same form as that accepted by `reggie.addAttributes` -- `attrsToDiscover`: an object of the same form as that accepted by `reggie.discoverAttributes` - -## Other events -In addition to `fog-up`, `fog-down`, `cloud-up`, and `cloud-down` events, the Regisrar also emits an `error` event. However, currently this event is only emitted if `MQTT` denies you from discovering certain attributes due to a permissions issue, which would be weird (at least in the current state of JAMScript) and should be flagged. The idea is that this `error` event can be extended to represent other issues that should be noted by you, the programmer. +Alternatively, if you want to stop discovering attributes on all nodes, regardless of type, `dattrs` cam simply be an `Array` of the attribute names. +### reggie.getDiscoveryTable(handler); +Gives access to the discovery table (which is, essentially, a map of the current locally known network state). A call to getDiscoveryTable(...) does **NOT** return a copy of the discovery table. It is through the `handler` callback that the received discovery table can be processed. An example discovery table can be found below. ``` - reggie.on('error', function(err) { - switch(err.name) { - case 'permissions_err': - console.log(err.message); - console.log('The following MQTT subscriptions were denied: ' + err.value); - break; - default: - console.log('unknown error'); - break; - } - }); +const dt = +{ + node_id : { + 'attrs' : { + 'status' : { + 'seqval' : seqval, + 'data' : data + }, + other_attr : { + 'seqval' : seqval, + 'data' : data + } + } + 'network' : 'LAN' || 'WAN', + 'other_useful_info' : ... + }, + other_node_id : { + ... + } +} ``` -## Example -Finally, an example, putting everything together, and assuming that the type of the node (device, fog, or cloud) is indeterminate until runtime: +### reggie.quit(); +Perform a clean exit for the current node on the network. This will lead to jdiscovery telling other nodes that the node going down is not because of a mobility-oriented disconnection. -**app.js** -``` - var Registrar = require('./jregistrar'), - errLog = require('../jerrlog'), - globals = require('../constants').globals, - events = require('events'), - Random = require('random-js'); - - var random = new Random(Random.engines.mt19937().autoSeed()); - - var machType = process.argv[2], - phoneType = process.argv[3], - phoneNumber = process.argv[4], - app = 'keithTest', - port = 1337, - id = random.uuid4(); - - // don't forget to initialize the logger! - errLog.init(app, false); - - console.log('_______________________________________________'); - console.log(machType + ' id: ' + id); - console.log('-----------------------------------------------'); - console.log(); - - var reggie = new Registrar(app, machType, id, port); - - //------------------------------------------------------------------------------ - // Default discoveries - //------------------------------------------------------------------------------ - - if (machType === 'device') { - reggie.on('fog-up', function(fogId, connInfo) { - console.log('FOG UP: id: ' + fogId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); - }); - - reggie.on('fog-down', function(fogId) { - console.log('FOG DOWN: id: ' + fogId); - }); - } else if (machType === 'fog') { - reggie.on('cloud-up', function(cloudId, connInfo) { - console.log('CLOUD UP: id: ' + cloudId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); - - }); - - reggie.on('cloud-down', function(cloudId) { - console.log('CLOUD DOWN: id: ' + cloudId); - }); - } +## Developer Notes - // on rare occasions, you might get an error - reggie.on('error', function(err) { - switch(err.name) { - case 'permissions_err': - console.log(err.message); - console.log('Subscriptions: ' + err.value); - break; - default: - console.log('unknown error'); - break; - } - }); +### Registry Policies - //------------------------------------------------------------------------------ - // Custom attributes/discoveries - //------------------------------------------------------------------------------ - - if (machType === 'device') { - // we'll have devices announce if they are phones (iphone or android) - // we'll say all devices are thermostats too...I know it doesn't make sense but it's just meant - // to be demonstrative :P - if (phoneType === 'iPhone') { - reggie.addAttributes({ - iPhone: phoneNumber - }); - } else if (phoneType === 'Android') { - reggie.addAttributes({ - android: 'psych, get an iPhone!' - }); - - // in 10 seconds, turn this android into an iphone - setTimeout(function() { - reggie.removeAttributes('android'); - reggie.addAttributes({ - iPhone: phoneNumber - }); - }, 5000); - } - reggie.addAttributes({ - thermostat: function() { - // returns some random number, which we'll treat as the temperature - return 'Temperature: ' + Math.random() * 100; - } - }); - } else if (machType === 'fog') { - // since we'll have clouds discover fogs, we don't need fogs to discover clouds - reggie.stopDiscoveringAttributes({ - cloud: ['status'] - }); - - reggie.discoverAttributes({ - device: { - thermostat: { - onAdd: 'thermo-added', - onRemove: 'thermo-removed' - } - } - }); - - reggie.on('thermo-added', function(id, temp) { - console.log('DEVICE ' + id + ' is a thermostat with temperature ' + temp); - }); - - reggie.on('thermo-removed', function(id, temp) { - console.log('DEVICE ' + id + ' is no longer a thermostat'); - }); - } else { - // maybe clouds want to discover fogs, and iphone devices - reggie.discoverAttributes({ - device: { - iPhone: { - onAdd: 'iPhone-added', - onRemove: 'iPhone-removed' - }, - android: { - onAdd: 'android-added', - onRemove: 'android-removed' - } - }, - fog: { - status: { - online: 'fog-up', - offline: 'fog-down' - } - } - }); - - reggie.on('fog-up', function(fogId, connInfo) { - console.log('FOG UP: id: ' + fogId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); - }); - - reggie.on('fog-down', function(fogId) { - console.log('FOG DOWN: id: ' + fogId); - }); - - reggie.on('iPhone-added', function(deviceId, phoneNumber) { - console.log('DEVICE ' + deviceId + ' is an iPhone with number ' + phoneNumber); - }); +#### MQTT - reggie.on('iPhone-removed', function(deviceId) { - console.log('DEVICE ' + deviceId + ' is no longer an iPhone'); - }); +Connections between a client and a broker always use the following configuration: +- `cleanSession : true` +- `lastWill : { data : 'offline' }` +Furthermore, all messages are sent with `retain : true` which leads to broker keeping all the most recent messages on all topics to reflect the current network state at any time. +It may be noted that having `cleanSession : true` also requires a node to resubscribe to its topics of interest after any temporary disconnection. +Regarding the last will of a node, it will be published to all nodes interested in the status attribute of the publisher in the case where the connection between the publisher and the broker is interrupted. - reggie.on('android-added', function(deviceId, phoneNumber) { - console.log('DEVICE ' + deviceId + ' is an Android with number: ' + phoneNumber); - }); +#### MDNS - reggie.on('android-removed', function(deviceId) { - console.log('DEVICE ' + deviceId + ' is no longer an Android'); - }); - } - - reggie.registerAndDiscover(); - -``` +Nodes and services are discovered using the standard MDNS service discovery methodology. For node and service downs, however, we rely on a new reserved service coming up, which all nodes are configured to listen to by default. This `(app)-(type)-attrrem` service holds a list of services going down in its text record. For crash and mobility-oriented connection detection, a simple heartbeat mechanism is used. Do note that for the heartbeat mechanism to function properly, port `5454`must be free on all hosts and multicast address `239.0.0.251` should be unused by other applications on the LAN. diff --git a/lib/jdiscovery/apps/demo.js b/lib/jdiscovery/apps/demo.js new file mode 100644 index 00000000..3b892572 --- /dev/null +++ b/lib/jdiscovery/apps/demo.js @@ -0,0 +1,81 @@ +const Registrar = require('../jregistrar-head.js'), + globals = require('../../jamserver/constants').globals, + events = require('events'); + +const id = process.argv[2], + type = process.argv[3], + port = process.argv[4], + app = 'tester'; + +console.log('_______________________________________________'); +console.log(' id: ' + id + ' type: ' + type + ' port: ' + port); +console.log('-----------------------------------------------'); +console.log(); + +// Construct registrar and start it +const reggie = new Registrar(app, type, id, port, + { protocols: { mqtt: true, mdns: true } }); +// ... if the mqtt discovery option is enabled, you need to have a broker +// ... running at the address specified in JAMScript-beta/lib/jamserver/constants.js +// ... at constants.mqtt.brokerUrl + +reggie.registerAndDiscover(); + +// Setup default discoveries +if (type === 'device') { + + reggie.on('fog-up', function(fogId, connInfo) { + console.log('FOG UP: id: ' + fogId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); + }); + reggie.on('fog-down', function(fogId) { + console.log('FOG DOWN: id: ' + fogId); + }); +} else if (type === 'fog') { + + reggie.on('cloud-up', function(cloudId, connInfo) { + console.log('CLOUD UP: id: ' + cloudId + ', ip: ' + connInfo.ip + ', port: ' + connInfo.port); + }); + reggie.on('cloud-down', function(cloudId) { + console.log('CLOUD DOWN: id: ' + cloudId); + }); +} + +// Setup custom attributes/discoveries +if (type === 'device') { + const ticker = setInterval( + /** + * XXX N.B. XXX + * The call must be bound to this scope + * using either a lambda expression, + * or, a call to bind() + * It will NOT work otherwise! + */ + (o) => { reggie.setAttributes(o); }, + 5000, + { secret : () => Math.random().toString(16) } + ); + setTimeout( + () => { + clearInterval(ticker); + reggie.removeAttributes(['secret']); + reggie.quit(); + }, + 22000 + ); +} else if (type === 'fog') { + + reggie.on('new-secret', function(id, secret) { + console.log('NEW-SECRET: id: ' + id + ' secret: ' + secret); + }); + reggie.on('no-more-secret', function(id) { + console.log('NO-MORE-SECRET: id: ' + id); + }); + reggie.discoverAttributes({ + device: { + secret: { + onAdd : 'new-secret', + onRemove : 'no-more-secret' + } + } + }); +} diff --git a/lib/jdiscovery/jregistrar-abdomen.js b/lib/jdiscovery/jregistrar-abdomen.js new file mode 100644 index 00000000..9d9c5463 --- /dev/null +++ b/lib/jdiscovery/jregistrar-abdomen.js @@ -0,0 +1,23 @@ +const RegistrarTail = require('./jregistrar-tail.js'); + +[,, app, type, id, port, config] = process.argv; +this.registrarTail = new RegistrarTail(app, type, id, port, JSON.parse(config)); + +this.registrarTail.on('appNotifLess', (event, id, protocol) => { + process.send({ appNotifLess: {event: event, id: id, protocol: protocol }}); +}); +this.registrarTail.on('appNotifMore', (event, id, data, protocol) => { + process.send({ appNotifMore: {event: event, id: id, data: data, protocol: protocol }}); +}); +this.registrarTail.on('discoveryTable', (dt) => { + process.send({ discoveryTable: dt }); +}); + +process.on('message', (m) => { + // DEBUG + // console.log('DEBUG: jregistrar-abdomen received call: ', m); + + for(f in m) + if(m.hasOwnProperty(f)) + this.registrarTail[f](m[f]); +}); diff --git a/lib/jdiscovery/jregistrar-head.js b/lib/jdiscovery/jregistrar-head.js new file mode 100644 index 00000000..46637efb --- /dev/null +++ b/lib/jdiscovery/jregistrar-head.js @@ -0,0 +1,81 @@ +const EventEmitter = require('events'), + cp = require('child_process'); + +function RegistrarHead(app, type, id, port, config) { + + this.registrarAbdomen = cp.fork( + __dirname + '/jregistrar-abdomen.js', + [app, type, id, port, JSON.stringify(config)] + ); + let self = this; + this.registrarAbdomen.on('message', (m) => { + let e; + if(m.hasOwnProperty('appNotifLess')) { + e = m['appNotifLess']; + self.emit(e.event, e.id, e.protocol); + } else if(m.hasOwnProperty('appNotifMore')) { + e = m['appNotifMore']; + self.emit(e.event, e.id, e.data, e.protocol); + } else if(m.hasOwnProperty('discoveryTable')) { + if((typeof self.discoveryTableHandler) === 'function') + self.discoveryTableHandler(JSON.parse(m['discoveryTable'])); + } + }); +} + +/* Registrar inherits from EventEmitter */ +RegistrarHead.prototype = Object.create(EventEmitter.prototype); +RegistrarHead.prototype.constructor = RegistrarHead; + +/** + * REGISTRAR INTERFACE METHODS + * __JDISCOVERY_EXTERNAL_API__ + */ + +RegistrarHead.prototype.registerAndDiscover = function(options) { + this.registrarAbdomen.send({ registerAndDiscover : ((options)?(options):null) }); +} + +RegistrarHead.prototype.setAttributes = function(attrs) { + // N.B. Gotta clone attrs to avoid some crazy JS shit... + // Evaluate attr function to get value + // ... right before sending over to other process + let clone = {}; + for(const key in attrs) { + if(attrs.hasOwnProperty(key)) { + if(typeof attrs[key] === 'function') { + clone[key] = attrs[key](); + } else { + clone[key] = attrs[key]; + } + } + } + this.registrarAbdomen.send({ setAttributes : clone }); +} +RegistrarHead.prototype.removeAttributes = function(attrs) { + this.registrarAbdomen.send({ removeAttributes : attrs }); +} + +RegistrarHead.prototype.discoverAttributes = function(dattrs) { + this.registrarAbdomen.send({ discoverAttributes : dattrs }); +} +RegistrarHead.prototype.stopDiscoveringAttributes = function(dattrs) { + this.registrarAbdomen.send({ stopDiscoveringAttributes : dattrs }); +} + +RegistrarHead.prototype.quit = function() { + this.registrarAbdomen.send({ quit : null }); + setTimeout( + (s) => { this.registrarAbdomen.kill(s); }, + 3000, + 'SIGTERM' + ); +} + +RegistrarHead.prototype.getDiscoveryTable = function(handler) { + this.discoveryTableHandler = handler; + this.registrarAbdomen.send({ getDiscoveryTable : null }); +} + +/* exports */ +module.exports = RegistrarHead; diff --git a/lib/jdiscovery/jregistrar-tail.js b/lib/jdiscovery/jregistrar-tail.js new file mode 100644 index 00000000..f4bee5ef --- /dev/null +++ b/lib/jdiscovery/jregistrar-tail.js @@ -0,0 +1,393 @@ +const EventEmitter = require('events'), + globals = require('../jamserver/constants').globals, + constants = require('../jamserver/constants'), + MQTTRegistry = require('./mqttregistry'), + MDNSRegistry = require('./mdnsregistry'), + os = require('os'); + +/** + * Registrar Class + * This class is the interface between the application + * and the MQTT, mDNS registries + */ + +function RegistrarTail(app, type, id, port, config) { + // the name of the application + this.app = app; + // the type of the machine the registar is running on (device, fog, or cloud) + this.type = type; + // the id of the machine + this.id = id; + // the port the program is running on + if (typeof port === 'string') { + port = parseInt(port); + } + if (!(typeof port === 'number')) { + throw new Error('port is not a number'); + } + this.port = port; + + /** + * DISCOVERY TABLE (dt) + * Notes: + * --> We don't keep an entry for our own node + * + * And an example... + * { + * node_id : { + * 'attrs' : { + * 'status' : { + * 'seqval' : seqval, + * 'data' : data + * }, + * other_attr : { + * 'seqval' : seqval, + * 'data' : data + * } + * } + * 'network' : 'LAN' || 'WAN', + * 'other_useful_info' : ... + * }, + * other_node_id : { + * ... + * } + * } + */ + this.dt = {}; + this.seqval = 0; + + /** + * config-specific set-up + */ + var noProtocols = true; + + this.mqttRegistry = null; + if (!config || !config.protocols || config.protocols.mqtt) { + // QoS |1| for MQTT: Message delivery is __AT_LEAST_ONCE__ + var subQos = 1, + pubQos = 1; + this.mqttRegistry = new MQTTRegistry(app, type, id, port, subQos, pubQos); + noProtocols = false; + } + this.mdnsRegistry = null; + if (!config || !config.protocols || config.protocols.mdns) { + this.mdnsRegistry = new MDNSRegistry(app, type, id, port); + noProtocols = false; + } + if (noProtocols) { + throw new Error('a Registrar must use at least one protocol'); + } + + // whether or not this registrar has been started + this.started = false; +} + +/* Registrar inherits from EventEmitter */ +RegistrarTail.prototype = Object.create(EventEmitter.prototype); +RegistrarTail.prototype.constructor = RegistrarTail; + +/** + * REGISTRAR INTERFACE METHODS + * __JDISCOVERY_EXTERNAL_API__ + */ + +/** + * Register a node on the network, and discover other nodes. + * `options` is an optional parameter + * `options` include: + * attrsToSet: key/value pair as in this.setAttributes + * attrsToDiscover: as in this.discoverAttributes + */ +RegistrarTail.prototype.registerAndDiscover = function() { + + if (this.started) + return; + + /** + * Set up default attributes, which are the same for devices, fogs, and clouds. + * The only default attribute is 'status'. + */ + this.setAttributes( + { + status: { + port: this.port, + ip: this._getIPv4Address() + } + }); + + /** + * Prep the default discoveries to be made by a node: + * devices discover (fogs, clouds) and fogs discover clouds. + */ + if (this.type === globals.NodeType.DEVICE) { + // default discoveries: + // devices discover fogs, clouds + this.discoverAttributes({ + fog: { + status: { + online: 'fog-up', + offline: 'fog-down' + } + }, + cloud: { + status: { + online: 'cloud-up', + offline: 'cloud-down' + } + } + }); + } else if (this.type === globals.NodeType.FOG) { + // default discoveries: + // fogs discover clouds + this.discoverAttributes({ + cloud: { + status: { + online: 'cloud-up', + offline: 'cloud-down' + } + } + }); + } else { + // If this node is a cloud, then it discovers nothing by default! + } + + /** + * Set propagatable events + */ + [this.mqttRegistry, this.mdnsRegistry].filter(x => x).map(x => + { + let self = this; + x.on('error', function(info) { + self.emit('error', info); + }); + x.on('discovery', function(attr, event, id, data, seqval) { + self._respondToDiscoveryEvent.call(self, attr, event, id, data, seqval, x.protocol); + }); + + x.on('attr-removed', function(attr, event, id, seqval) { + self._respondToRemovalEvent.call(self, attr, event, id, seqval, x.protocol); + }); + }); + + [this.mqttRegistry, this.mdnsRegistry].map( + x => {if(x) x.registerAndDiscover();} + ); + this.started = true; +} + +/** + * Add custom, discoverable attributes to this node + * attrs is an object of key value pairs + */ +RegistrarTail.prototype.setAttributes = function(attrs) { + this._modifyAttributes("setAttributes", attrs, this._getSeqVal()); +} +RegistrarTail.prototype.removeAttributes = function(attrs) { + this._modifyAttributes("removeAttributes", attrs, this._getSeqVal()); +} +RegistrarTail.prototype._modifyAttributes = function(fun, attrs, seqval) { + if (attrs instanceof Array) { + attrs = attrs.reduce((acc, p) => { acc[p] = null; return acc; }, {}); + } + [this.mqttRegistry, this.mdnsRegistry].map( + x => {if(x) x[fun](attrs, seqval);} + ); +} + +/** + * Specify attributes to be discovered. + * dattrs can have one of the following forms: + * (a) + * { + * all: {attr: event, ...}, // discover these attributes for all nodes + * device: {attr: event, ...}, // discover these attributes just for devices + * fog: {attr: event, ...}, // discover these attributes just for fogs + * cloud: {attr: event, ...} // discover these attributes just for clouds + * } + * (b) As a shortcut for _all_, one can simply pass an object of pairs + * + * For the status attribute, the format is: + * status: { + * online: 'fog-up', + * offline: 'fog-down' + * } + * Whereas for custom attributes, the format is: + * is_a_phone: { + * onAdd: 'phone-found' + * onRemove: 'phone-lost' + * } + */ +RegistrarTail.prototype.discoverAttributes = function(dattrs) { + dattrs = this._formatDattributes(dattrs); + this._modifyDattributes("discoverAttributes", dattrs); +} +RegistrarTail.prototype.stopDiscoveringAttributes = function(dattrs) { + dattrs = this._formatDattributes(dattrs); + this._modifyDattributes("stopDiscoveringAttributes", dattrs); +} +/** + * Marshall dattrs to the following format (expected by the registries) + * { 'device' : {...}, 'fog' : {...}, 'cloud' : {...} } + */ +RegistrarTail.prototype._formatDattributes = function(dattrs) { + // array mashalling + if (dattrs instanceof Array) { + dattrs = dattrs.reduce((acc, p) => { acc[p] = null; return acc; }, {}); + } else { + ['device', 'fog', 'cloud'].filter(x => dattrs[x] instanceof Array).map( + x => { + dattrs[x] = dattrs[x].reduce((acc, p) => { acc[p] = null; return acc; }, {}); + } + ); + } + if (!(dattrs.all || dattrs.device || dattrs.fog || dattrs.cloud)) + dattrs = { 'all' : dattrs }; + ['device', 'fog', 'cloud'].map( + x => { + if(!dattrs[x]) dattrs[x] = {}; + // add all attrs in 'all' to each machine type + if(dattrs.all) + Object.assign(dattrs[x], dattrs.all); + } + ) + if(dattrs.all) + delete dattrs.all; + return dattrs; +} +RegistrarTail.prototype._modifyDattributes = function(fun, dattrs) { + [this.mqttRegistry, this.mdnsRegistry].map( + x => {if(x) x[fun](dattrs);} + ); +} +/** + * Exit from network cleanly + */ +RegistrarTail.prototype.quit = function() { + let seqval = this._getSeqVal(); + [this.mqttRegistry, this.mdnsRegistry].filter(x => x).map( + (x) => { + x.quit(seqval); + } + ); +} +/** + * Respond to discovery table pull request + */ +RegistrarTail.prototype.getDiscoveryTable = function() { + this.emit('discoveryTable', JSON.stringify(this.dt)); +} + +/** + * _PRIVATE HELPERS + */ +/** + * Upon receipt of a discovery event, pass it onto the rest of the application if it is not a duplicate + */ +RegistrarTail.prototype._respondToDiscoveryEvent = function(attr, event, id, data, seqval, protocol) { + + // DUBUGGING: Print shit + // console.log("DEBUG: Registrar._respondToDiscoveryEvent: ", event, id, data, seqval, protocol); + + // Update discovery table + if (!this.dt.hasOwnProperty(id)) { + this.dt[id] = {}; + this.dt[id]['attrs'] = {}; + // nodes are assumed to be on WAN by default + this.dt[id]['network'] = 'WAN'; + } + // maintain info about where the node is: 'LAN' or 'WAN' + if (protocol === constants.globals.Protocol.MDNS) { + this.dt[id]['network'] = 'LAN'; + } + if (!this.dt[id]['attrs'].hasOwnProperty(attr)) + this.dt[id]['attrs'][attr] = {}; + + // Because node offline events end up here instead of in _respondToRemovalEvent, we need to check the attribute + // and value in order to know what arguments to pass along with the event. + // WARNING: XXX __SEQVAL_BYPASS__ XXX + // It should be noted that is a potential network race condition whereby it would be + // possible to have status updates arriving to subscribers in the wrong order. + // This could potentially be solved by subscribing to status topics with QoS 2 + // The above proposed solution is : NOT IMPLEMENTED due to how unlikely this is to happen. + if (attr === 'status' && data === 'offline') { + + // ignore this if it has already been detected + if(this.dt[id]['attrs']['status']['data'] == 'offline') + return; + + // o.w. + this.dt[id]['attrs']['status']['data'] = 'offline'; + // Set seqvals for all attributes of node to -1 in case the node crashed + // ... this means any attr update will be accepted when the node does so + for(var key in this.dt[id]['attrs']) + if(this.dt[id]['attrs'].hasOwnProperty(key)) + this.dt[id]['attrs'][key]['seqval'] = -1; + this.emit('appNotifLess', event, id, protocol); + return; + } + + // Insert data/seqval pair if not already received + if ( !this.dt[id]['attrs'][attr].hasOwnProperty('seqval') + || this.dt[id]['attrs'][attr]['seqval'] < seqval + || ( (this.dt[id]['attrs'][attr]['seqval'] > (Number.MAX_SAFE_INTEGER/2)) + && (seqval < (Number.MAX_SAFE_INTEGER/1024)))) + { + this.dt[id]['attrs'][attr]['data'] = data; + this.dt[id]['attrs'][attr]['seqval'] = seqval; + + this.emit('appNotifMore', event, id, data, protocol); + } else { + return; + } +} + +/** + * Upon receipt of an attribute removal event, pass it onto the rest of the application + */ +RegistrarTail.prototype._respondToRemovalEvent = function(attr, event, id, seqval, protocol) { + + // DUBUGGING: Print shit + // console.log("DEBUG: Registar._respondToRemovalEvent: ", event, id, seqval, protocol); + + // check dt first + if ( !this.dt.hasOwnProperty(id) + || !this.dt[id]['attrs'].hasOwnProperty(attr)) + return; + + if ( !this.dt[id]['attrs'][attr].hasOwnProperty('seqval') + || this.dt[id]['attrs'][attr]['seqval'] < seqval + || ( (this.dt[id]['attrs'][attr]['seqval'] > (Number.MAX_SAFE_INTEGER/2)) + && (seqval < (Number.MAX_SAFE_INTEGER/1024)))) + { + delete this.dt[id]['attrs'][attr]; + this.emit('appNotifLess', event, id, protocol); + } +} + +/** + * returns next seq number for event ordering + */ +RegistrarTail.prototype._getSeqVal = function() { + if (this.seqval == Number.MAX_SAFE_INTEGER) { + this.seqval = 0; + } + return this.seqval++; +} + +/** + * returns the IPv4 address of the node + */ +RegistrarTail.prototype._getIPv4Address = function() { + var niaddrs = os.networkInterfaces(); + for (var ni in niaddrs) { + nielm = niaddrs[ni]; + for (n in nielm) { + if (nielm[n].family === 'IPv4' && nielm[n].internal === false) + return nielm[n].address + } + } + return globals.localhost; +} + +/* exports */ +module.exports = RegistrarTail; diff --git a/lib/jdiscovery/jregistrar.js b/lib/jdiscovery/jregistrar.js deleted file mode 100644 index 18e4b1af..00000000 --- a/lib/jdiscovery/jregistrar.js +++ /dev/null @@ -1,616 +0,0 @@ -var EventEmitter = require('events'), - globals = require('../jamserver/constants').globals, - constants = require('../jamserver/constants'), - MQTTRegistry = require('./mqttregistry'), - MDNSRegistry = require('./mdnsregistry'), - LocalRegistry = require('./localregistry'), - os = require('os'); - -//============================================================================== -// Helpers -//============================================================================== - -/** - * returns the IPv4 address of the node - */ -function getIPv4Address() { - var niaddrs = os.networkInterfaces(); - for (var ni in niaddrs) { - nielm = niaddrs[ni]; - for (n in nielm) { - if (nielm[n].family === 'IPv4' && nielm[n].internal === false) - return nielm[n].address - } - } - return globals.localhost; -} - -//============================================================================== -// Registrar Class -// This class is the interface between the application and the MQTT, mDNS, and -// local storage registries -//============================================================================== - -function Registrar(app, machType, id, port, loc, config) { - // the name of the application - this.app = app; - // the type of the machine the registar is running on (device, fog, or cloud) - this.machType = machType; - // the id of the machine - this.id = id; - // the port the program is running on - if (typeof port === 'string') { - port = parseInt(port); - } - if (!(typeof port === 'number')) { - throw new Error('port is not a number'); - } - this.port = port; - this.loc = loc; - - /* - * Store discoveries so that we can easily check for duplicates. - * discoveries is an object which maps from an attribute name, e.g. 'status' to - * a map of pairs. e.g. if discoveries looks like: - * { - * status: { - * a: 123, - * b: 456 - * } - * } - * then we know that the last message received from node 'a' regarding the - * 'attribute' status had ID 123. - */ - this.discoveries = {}; - - /** - * Reserved attributes. - * These are attribute names that cannot be used by third parties. - */ - this.reservedAttrs = ['status', 'lastCheckIn', 'createdAt', 'updatedAt']; - - // whether or not this registrar has been started - this.started = false; - - /** - * config-specific set-up - */ - - var noProtocols = true; - - if (!config || !config.protocols || config.protocols.mqtt) { - var subQos = this.machType == globals.NodeType.DEVICE ? 0 : 1; - var pubQos = this.machType == globals.NodeType.DEVICE ? 0 : 1; - this.mqttRegistry = new MQTTRegistry(app, machType, id, port, subQos, pubQos); - noProtocols = false; - } - - if (!config || !config.protocols || config.protocols.mdns) { - this.mdnsRegistry = new MDNSRegistry(app, machType, id, port); - noProtocols = false; - } - - if (!config || !config.protocols || config.protocols.localStorage) { - this.localRegistry = new LocalRegistry(app, machType, id, port); - noProtocols = false; - } - - if (noProtocols) { - throw new Error('a Registrar must use at least one protocol'); - } - - if (config && config.hasOwnProperty('eliminateDuplicates')) { - this.eliminateDuplicates = config.eliminateDuplicates; - } else { - // by default, eliminate duplicates - this.eliminateDuplicates = false; - } - - /** - * Set up default attributes, which are the same for devices, fogs, and clouds. - * The only default attribute is 'status'. - */ - this.addAttributes({ - status: function() { - return { - port: port, - ip: getIPv4Address(), - loc: loc - }; - } - }, true); - - /** - * Prep the default discoveries to be made by a node: - * devices discover fogs and fogs discover clouds. - */ - if (this.machType === globals.NodeType.DEVICE) { - // default discoveries: - // devices discover fogs - this.discoverAttributes({ - fog: { - status: { - online: 'fog-up', - offline: 'fog-down' - // if the status value is `offline`, then we emit fog-down, else we emit fog-up - } - }, - cloud: { - status: { - online: 'cloud-up', - offline: 'cloud-down' - } - } - }); - } else if (this.machType === globals.NodeType.FOG) { - // default discoveries: - // fogs discover clouds - this.discoverAttributes({ - cloud: { - status: { - online: 'cloud-up', - offline: 'cloud-down' - } - } - }); - } else { - // If this node is a cloud, then it discovers nothing by default! - } - - // listen for events from the Registries - var self = this; - - if (this.mqttRegistry) { - this.mqttRegistry.on('sub-error', function(dattrs) { - setTimeout(self.mqttRegistry.subscribe, constants.mqtt.longRetryInterval, self.mqttRegistry, dattrs); - }); - - this.mqttRegistry.on('subs-denied', function(dattrs) { - var err = new Error('MQTT subscriptions denied'); - err.name = 'permissions_err'; - err.value = dattrs; - self.emit('error', err); - }); - - this.mqttRegistry.on('unsub-error', function(dattrs) { - setTimeout(self.mqttRegistry.unsubscribe, constants.mqtt.longRetryInterval, self.mqttRegistry, dattrs); - }); - - this.mqttRegistry.on('pub-error', function(attr, value) { - setTimeout(self.mqttRegistry.publish, constants.mqtt.longRetryInterval, self.mqttRegistry, attr, value); - }); - - this.mqttRegistry.on('unpub-error', function(attr) { - setTimeout(self.mqttRegistry.unpublish, constants.mqtt.longRetryInterval, self.mqttRegistry, attr); - }); - - this.mqttRegistry.on('discovery', function(attr, event, nodeId, value, dedupeId) { - self._respondToDiscoveryEvent(self, attr, event, nodeId, value, dedupeId, constants.globals.Protocol.MQTT); - }); - - this.mqttRegistry.on('attr-removed', function(attr, event, nodeId) { - self._respondToAttrRemovalEvent(self, attr, event, nodeId, constants.globals.Protocol.MQTT); - }); - } - - if (this.mdnsRegistry) { - this.mdnsRegistry.on('ad-error', function(attr, adName, txtRecord) { - // an ad failed - try again after some time - setTimeout(self.mdnsRegistry._createAdvertisementWithRetries, constants.mdns.longRetryInterval, self.mdnsRegistry, attr, adName, txtRecord, 0); - }); - - this.mdnsRegistry.on('browser-error', function(attr, machType, events) { - // a browser failed - try again after some time - if (attr === 'status') { - setTimeout(self.mdnsRegistry._browseForStatus, constants.mdns.longRetryInterval, self.mdnsRegistry, machType, events); - } else { - setTimeout(self.mdnsRegistry._browse, constants.mdns.longRetryInterval, self.mdnsRegistry, attr, machType, events); - } - }); - - this.mdnsRegistry.on('discovery', function(attr, event, nodeId, value, dedupeId) { - self._respondToDiscoveryEvent(self, attr, event, nodeId, value, dedupeId, constants.globals.Protocol.MDNS); - }); - - this.mdnsRegistry.on('attr-removed', function(attr, event, nodeId) { - self._respondToAttrRemovalEvent(self, attr, event, nodeId, constants.globals.Protocol.MDNS); - }); - } - - if (this.localRegistry) { - this.localRegistry.on('discovery', function(attr, event, nodeId, value, dedupeId) { - self._respondToDiscoveryEvent(self, attr, event, nodeId, value, dedupeId, constants.globals.Protocol.LOCALSTORAGE); - }); - - this.localRegistry.on('attr-removed', function(attr, event, nodeId) { - self._respondToAttrRemovalEvent(self, attr, event, nodeId, constants.globals.Protocol.LOCALSTORAGE); - }); - } -} - -/* Registrar inherits from EventEmitter */ -Registrar.prototype = Object.create(EventEmitter.prototype); -Registrar.prototype.constructor = Registrar; - -//============================================================================== -// API -//============================================================================== - -/** - * Register a node on the network, and discover other nodes. - * `options` is an optional parameter - * `options` include: - * attrsToAdd: key/value pair as in this.addAttributes - * attrsToDiscover: as in this.discoverAttributes - */ -Registrar.prototype.registerAndDiscover = function(options) { - if (options) { - if (typeof options !== 'object') { - throw new Error('options must be an object - see the docs'); - } - - if (options.attrsToAdd) { - this.addAttributes(options.attrsToAdd); - } - - if (options.attrsToDiscover) { - this.discoverAttributes(options.attrsToDiscover); - } - } - - if (!this.started) { - if (this.mqttRegistry) { - this.mqttRegistry.registerAndDiscover(); - } - if (this.mdnsRegistry) { - this.mdnsRegistry.registerAndDiscover(); - } - if (this.localRegistry) { - this.localRegistry.registerAndDiscover(); - } - this.started = true; - } -} - -/** - * Upon receipt of an attribute removal event, pass it onto the rest of the application if it - * is something we don't already know - */ -Registrar.prototype._respondToAttrRemovalEvent = function(self, attr, event, nodeId, protocol) { - if (self.eliminateDuplicates && (!self.discoveries.hasOwnProperty(attr) || !self.discoveries[attr].hasOwnProperty(nodeId))) { - return; - } - delete self.discoveries[attr][nodeId]; - self.emit(event, nodeId, protocol); -} - -//============================================================================== -// Add and discover attributes -//============================================================================== - -/** - * Add custom, discoverable attributes to this node - * attrs is an object of key value pairs - */ -Registrar.prototype.addAttributes = function(attrs, override) { - // error handling - if (!override) { - this._checkFormOfAttrsToAdd(attrs); - } - // use the time corresponding to the publication of these attributes as the message ID - const dedupeId = Date.now(); - // add the attributes on each protocol - if (this.mqttRegistry) { - this.mqttRegistry.addAttributes(attrs, dedupeId); - } - if (this.mdnsRegistry) { - this.mdnsRegistry.addAttributes(attrs, dedupeId); - } - if (this.localRegistry) { - this.localRegistry.addAttributes(attrs, dedupeId); - } -} - -Registrar.prototype.removeAttributes = function(attrs) { - // error handling - attrs = this._reformatAttrsToRemove(attrs); - // remove the attributes on each protocol - if (this.mqttRegistry) { - this.mqttRegistry.removeAttributes(attrs); - } - if (this.mdnsRegistry) { - this.mdnsRegistry.removeAttributes(attrs); - } - if (this.localRegistry) { - this.localRegistry.removeAttributes(attrs); - } -} - -/** - * Specify attributes to be discovered. - * dattrs can have one of the following forms: - * (a) - * { - * all: {attr: event}, // discover these attributes for all nodes - * device: {attr: event}, // discover these attributes just for devices - * fog: {attr: event}, // discover these attributes just for fogs - * cloud: {attr: event} // discover these attributes just for clouds - * } - * (b) As a shortcut for all, one can simply pass an object of pairs - */ -Registrar.prototype.discoverAttributes = function(dattrs) { - dattrs = this._checkAndReformatAttrsToDiscover(dattrs); - if (this.mqttRegistry) { - this.mqttRegistry.discoverAttributes(dattrs); - } - if (this.mdnsRegistry) { - this.mdnsRegistry.discoverAttributes(dattrs); - } - if (this.localRegistry) { - this.localRegistry.discoverAttributes(dattrs); - } -} - -Registrar.prototype.stopDiscoveringAttributes = function(dattrs) { - dattrs = this._checkAndReformatAttrsToStopDiscovering(dattrs); - if (this.mqttRegistry) { - this.mqttRegistry.stopDiscoveringAttributes(dattrs); - } - if (this.mdnsRegistry) { - this.mdnsRegistry.stopDiscoveringAttributes(dattrs); - } - if (this.localRegistry) { - this.localRegistry.stopDiscoveringAttributes(dattrs); - } -} - -//============================================================================== -// Helpers -//============================================================================== - -/** - * Checks the format of a set of attributes to discover, and reformats them into the form accepted - * by the three registries - */ -Registrar.prototype._checkAndReformatAttrsToDiscover = function(attrs) { - // error handling - if (typeof attrs !== 'object') { - throw new Error('you must specify the attributes you want discovered as an object - see the docs'); - } - // check that the attrs parameter is properly formed - var formedAttrs; - if (attrs.all === undefined && - attrs.device === undefined && - attrs.fog === undefined && - attrs.cloud === undefined) { - this._checkFormOfAttrsToDiscover(attrs); - formedAttrs = { - device: {}, - fog: {}, - cloud: {} - }; - for (var key in attrs) { - formedAttrs.device[key] = attrs[key]; - formedAttrs.fog[key] = attrs[key]; - formedAttrs.cloud[key] = attrs[key]; - } - } else { - this._checkFormOfAttrsToDiscover(attrs.all); - this._checkFormOfAttrsToDiscover(attrs.device); - this._checkFormOfAttrsToDiscover(attrs.fog); - this._checkFormOfAttrsToDiscover(attrs.cloud); - for (var key in attrs.all) { - attrs.device[key] = attrs.all[key]; - attrs.fog[key] = attrs.all[key]; - attrs.cloud[key] = attrs.all[key]; - } - formedAttrs = attrs; - } - return formedAttrs; -} - -Registrar.prototype._checkAndReformatAttrsToStopDiscovering = function(dattrs) { - // error handling - if (!(dattrs instanceof Object) && !(dattrs instanceof Array)) { - throw new Error('you must specify the attributes to stop discovering in an object or array - see the docs'); - } - - // check that the attrs parameter is properly formed - var formedDattrs; - if (dattrs instanceof Array) { - formedDattrs = { - device: [], - fog: [], - cloud: [] - }; - for (var i = 0; i < dattrs.length; i++) { - if (typeof dattrs[i] != 'string') { - throw new Error('the attribute \'' + dattrs[i] + '\' is not a string'); - } - formedDattrs.device.push(dattrs[i]); - formedAttrs.fog.push(dattrs[i]); - formedAttrs.cloud.push(dattrs[i]); - } - } else { - if (dattrs.all) { - this._checkArrayOfStrings(dattrs.all); - } - if (dattrs.device) { - this._checkArrayOfStrings(dattrs.device); - } - if (dattrs.fog) { - this._checkArrayOfStrings(dattrs.fog); - } - if (dattrs.cloud) { - this._checkArrayOfStrings(dattrs.cloud); - } - if (dattrs.all) { - for (var i = 0; i < dattrs.all.length; i++) { - dattrs.device.push(dattrs.all[i]); - dattrs.fog.push(dattrs.all[i]); - dattrs.cloud.push(dattrs.all[i]); - } - } - formedDattrs = dattrs; - } - return formedDattrs; -} - -Registrar.prototype._checkArrayOfStrings = function(arr) { - if (!(arr instanceof Array)) { - throw new Error('attributes to stop discovering must be passed as an array of strings'); - } - - for (var i = 0; i < arr.length; i++) { - if (typeof arr[i] != 'string') { - throw new Error('the attribute \'' + arr[i] + '\' is not a string'); - } - } -} - -/** - * A helper for Registrar.prototype.discoverAttributes; - * ensures that attrs is an object of pairs - */ -Registrar.prototype._checkFormOfAttrsToDiscover = function(attrs) { - for (var key in attrs) { - if (key == 'status') { - // ensure that online and offline events are specified - if (!attrs.status instanceof Object) { - throw new Error('discovery of the status attribute requires \'online\' and \'offline\' event names, passed in an object - see the docs'); - } - - // online - if (!attrs.status.hasOwnProperty('online')) { - throw new Error('\'online\' event required for discovery of status attribute'); - } else { - if (typeof attrs.status.online != 'string') { - throw new Error('the event name \'' + attrs.status.online + '\' must be a string'); - } - } - - // offline - if (!attrs.status.hasOwnProperty('offline')) { - throw new Error('\'offline\' event required for discovery of status attribute'); - } else { - if (typeof attrs.status.offline != 'string') { - throw new Error('the event name \'' + attrs.status.offline + '\' must be a string'); - } - } - } else { - // ensure that onAdd and onRemove events are specified - if (!attrs[key] instanceof Object) { - throw new Error('discovery of an attribute requires \'onAdd\' and \'onRemove\' event names, passed in an object - see the docs'); - } - - // onAdd - if (!attrs[key].hasOwnProperty('onAdd')) { - throw new Error('\'onAdd\' event required for discovery of an attribute'); - } else { - if (typeof attrs[key].onAdd != 'string') { - throw new Error('the event name \'' + attrs[key].onAdd + '\' must be a string'); - } - } - - // onRemove - if (!attrs[key].hasOwnProperty('onRemove')) { - throw new Error('\'onRemove\' event required for discovery of an attribute'); - } else { - if (typeof attrs[key].onRemove != 'string') { - throw new Error('the event name \'' + attrs[key].onRemove + '\' must be a string'); - } - } - } - } -} - -Registrar.prototype._checkFormOfAttrsToAdd = function(attrs) { - if (typeof attrs !== 'object') { - throw new Error('attrs must be an object'); - } - for (var i = 0; i < this.reservedAttrs.length; i++) { - if (attrs[this.reservedAttrs[i]] !== undefined) { - throw new Error('the attribute \'' + this.reservedAttrs[i] + '\' is reserved'); - } - } - for (var attr in attrs) { - if (attrs[attr] === '') { - throw new Error('the attribute ' + attr + ' has an empty string as its value - this is not permitted'); - } - } -} - -Registrar.prototype._reformatAttrsToRemove = function(attrs) { - if (typeof attrs == 'string') { - attrs = [attrs]; - } else if (!(attrs instanceof Array)) { - throw new Error('attrs must be a string or an array of strings'); - } - - for (var i = 0; i < attrs.length; i++) { - if (typeof attrs[i] != 'string') { - throw new Error('attrs must be a string or an array of strings'); - } else if (attrs[i] == 'status') { - throw new Error('the \'status\' attribute cannot be removed'); - } - } - - return attrs; -} - -/** - * Upon receipt of a discovery event, pass it onto the rest of the application if it is not a duplicate - */ -Registrar.prototype._respondToDiscoveryEvent = function(self, attr, event, nodeId, value, dedupeId, protocol) { - - console.log("---------------------------------- ", event, nodeId, value); - - if (self.eliminateDuplicates && self._isDuplicate(self, attr, nodeId, dedupeId)) { - return; - } - self._updateDiscoveries(self, attr, nodeId, dedupeId); - - // Because node offline events end up here instead of in _respondToAttrRemovalEvent, we need to check the attribute - // and value in order to know what arguments to pass along with the event. - if (attr === 'status' && value === 'offline') { - self.emit(event, nodeId, protocol); - return; - } - self.emit(event, nodeId, value, protocol); -} - -/** - * Returns true if a discovery is a duplicate and false otherwise. - * attr - the attrubute for which a discovery was made - * nodeId - the ID of the node for which the discovery was made - * dedupeId - an ID that tells us if this message is a duplicate or not - */ -Registrar.prototype._isDuplicate = function(self, attr, nodeId, dedupeId) { - if (!self.discoveries.hasOwnProperty(attr)) { - return false; - } - - if (!self.discoveries[attr].hasOwnProperty(nodeId)) { - return false; - } - - // Compare the dedupe ID of the last message with that of the current message - // Because the dedupe IDs are timestamps, we say that a message is a duplicate - // if its ID is less than or equal to the last received. - if (dedupeId === 0 && self.discoveries[attr][nodeId] !== 0) { - // The one exception is that a dedupeId of zero is used for node down events, - // so we need to account for this special case. - return false; - } - return dedupeId <= self.discoveries[attr][nodeId]; -} - -Registrar.prototype._updateDiscoveries = function(self, attr, nodeId, dedupeId) { - if (!self.discoveries.hasOwnProperty(attr)) { - self.discoveries[attr] = {}; - } - self.discoveries[attr][nodeId] = dedupeId; -} - -/* exports */ -module.exports = Registrar; diff --git a/lib/jdiscovery/localregistry.js b/lib/jdiscovery/localregistry.js deleted file mode 100644 index 8c5fec71..00000000 --- a/lib/jdiscovery/localregistry.js +++ /dev/null @@ -1,411 +0,0 @@ -//============================================================================== -// Registers a node locally (using local storage) -//============================================================================== - -var LocalStorage = require('node-localstorage').LocalStorage, - lockFile = require('lockfile'), - constants = require('../jamserver/constants'), - logger = require('../jamserver/jerrlog'), - Registry = require('./registry'), - os = require('os'); - -/* create an mDNS advertisement on the local network */ - -function LocalRegistry(app, machType, id, port) { - Registry.call(this, app, machType, id, port); - this.localStorage = null; - this.binName = this._getBinName(); - // put the 'app' as a hidden directory in user's home - this.appDir = os.homedir() + '/.' + app; - // the timestamp when we last scanned local storage for other nodes; - // set to zero to catch nodes that started before this node - this.lastScanAt = 0; - this.currentOfflineMachs = {}; - - /** - * Attributes to write to local storage the next time we check in. A map from - * attribute name to { payload: attribute_value, dedupeId: deduplication_id } - * objects. - */ - this.attrsToAdd = {}; - // attributes to remove from local storage the next time we check in - this.attrsToRemove = []; - // attributes to discover the next time we scan - this.attrsToDiscover = { - device: {}, - fog: {}, - cloud: {} - }; - - // the previous devices, fogs, and clouds we found in local storage - this.prevMachs = {}; - - // whether or not scanning and checkins have been started - this.started = false; -} - -/* LocalRegistry inherits from Registry */ -LocalRegistry.prototype = Object.create(Registry.prototype); -LocalRegistry.prototype.constructor = LocalRegistry; - -/** - * API for local storage registration/discovery - */ -LocalRegistry.prototype.registerAndDiscover = function() { - if (!this.started) { - // initialize the local storage - var self = this; - this._initLocalStorage(this, function() { - self.started = true; - self._kickStartCheckIns(self); - self._kickStartScanning(self); - }); - } -} - -LocalRegistry.prototype._initLocalStorage = function(self, cb) { - lockFile.lock(constants.localStorage.initLock, { stale: constants.localStorage.stale }, function (err) { - if (err) { - // failed to acquire lock, which means someone else already has it; wait until the node with the lock - // has finished initializing local storage - grabbedLock = false; - var tempLs; - while (true) { - tempLs = new LocalStorage(self.appDir); - if (tempLs.getItem('initialized')) { - self.localStorage = tempLs; - break; - } - } - self.emit('ls-initialized'); - cb(); - return; - } - - // we've grabbed the lock - self.localStorage = new LocalStorage(self.appDir); - if (!self.localStorage.getItem('initialized')) { - // we need to perform the initialization - for (var i = 0; i < constants.localStorage.numBins; i++) { - self.localStorage.setItem('devices_' + i, '{}'); - self.localStorage.setItem('fogs_' + i, '{}'); - self.localStorage.setItem('clouds_' + i, '{}'); - } - self.localStorage.setItem('initialized', 'true'); - } - lockFile.unlockSync(constants.localStorage.initLock); - self.emit('ls-initialized'); - cb(); - }); -} - -/** - * Register a node on local storage by having it write itself into local storage (fogs and clouds only) - */ -LocalRegistry.prototype._kickStartCheckIns = function(self) { - // create an object to be written to local storage - var now = Date.now(); - var data = { - lastCheckIn: now, - createdAt: now - }; - - // add attrs - for (var attr in self.attrsToAdd) { - if (self.attrsToAdd[attr].payload instanceof Function) { - data[attr] = { - payload: self.attrsToAdd[attr].payload(), - id: self.attrsToAdd[attr].dedupeId, - updatedAt: now - }; - } else { - data[attr] = { - payload: self.attrsToAdd[attr].payload, - id: self.attrsToAdd[attr].dedupeId, - updatedAt: now - }; - } - } - // reset attrsToAdd - self.attrsToAdd = {}; - - self._addNodeToLocalStorage(self, data, 1, function() { - // check in every so often to indicate that we're still here - setInterval(self._checkIn, constants.localStorage.checkInInterval, self, 1); - }); -} - -/** - * Kick-start scanning - */ -LocalRegistry.prototype._kickStartScanning = function(self) { - self._scan(self); - setInterval(self._scan, constants.localStorage.scanInterval, self); -} - -/** - * Adds a node's information to local storage - */ -LocalRegistry.prototype._addNodeToLocalStorage = function(self, data, attemptNumber, cb) { - if (self.binName !== undefined) { - lockFile.lock(self.binName, { stale: constants.localStorage.stale }, function (err) { - if (err) { - setTimeout(self._addNodeToLocalStorage, self._getWaitTime(attemptNumber), self, data, attemptNumber + 1, cb); - return; - } - var nodes = JSON.parse(self.localStorage.getItem(self.binName)); - nodes[self.id] = data; - self.localStorage.setItem(self.binName, JSON.stringify(nodes)); - lockFile.unlockSync(self.binName); - cb(); - }); - } -} - -/** - * Update lastCheckIn field - * Also, at this time, we update the attributes of the node - */ -LocalRegistry.prototype._checkIn = function(self, attemptNumber) { - lockFile.lock(self.binName, { stale: constants.localStorage.stale }, function (err) { - if (err) { - setTimeout(self._checkIn, self._getWaitTime(attemptNumber), self, attemptNumber + 1); - return; - } - var now = Date.now(); - var nodes = JSON.parse(self.localStorage.getItem(self.binName)); - // update lastCheckIn field - nodes[self.id].lastCheckIn = now; - // update attributes - // remove any that need removing - for (var i = 0; i < self.attrsToRemove.length; i++) { - delete nodes[self.id][self.attrsToRemove[i]]; - } - // reset attrsToRemove - self.attrsToRemove = []; - // add any that need adding - for (var attr in self.attrsToAdd) { - if (self.attrsToAdd[attr].payload instanceof Function) { - nodes[self.id][attr] = { - payload: self.attrsToAdd[attr].payload(), - id: self.attrsToAdd[attr].dedupeId, - updatedAt: now - }; - } else { - nodes[self.id][attr] = { - payload: self.attrsToAdd[attr].payload, - id: self.attrsToAdd[attr].dedupeId, - updatedAt: now - }; - } - delete self.attrsToAdd[attr]; - } - self.localStorage.setItem(self.binName, JSON.stringify(nodes)); - lockFile.unlockSync(self.binName); - }); -} - -/** - * Scans local storage for other nodes - */ -LocalRegistry.prototype._scan = function(self) { - var binName; - var baseName; - var currMachs = {}; - var machs; - - if (Object.keys(self.attrsToDiscover.device).length !== 0) { - baseName = 'devices_'; - for (var i = 0; i < constants.localStorage.numBins; i++) { - binName = baseName + i; - machs = JSON.parse(self.localStorage.getItem(binName)); - self._makeDiscoveries(self, machs, self.attrsToDiscover.device); - self._detectRemovedAttrs(self, machs, self.attrsToDiscover.device); - for (var key in machs) { - currMachs[key] = machs[key]; - } - } - } - - if (Object.keys(self.attrsToDiscover.fog).length !== 0) { - baseName = 'fogs_'; - for (var i = 0; i < constants.localStorage.numBins; i++) { - binName = baseName + i; - machs = JSON.parse(self.localStorage.getItem(binName)); - self._makeDiscoveries(self, machs, self.attrsToDiscover.fog); - self._detectRemovedAttrs(self, machs, self.attrsToDiscover.fog); - for (var key in machs) { - currMachs[key] = machs[key]; - } - } - } - - if (Object.keys(self.attrsToDiscover.cloud).length !== 0) { - baseName = 'clouds_'; - for (var i = 0; i < constants.localStorage.numBins; i++) { - binName = baseName + i; - machs = JSON.parse(self.localStorage.getItem(binName)); - self._makeDiscoveries(self, machs, self.attrsToDiscover.cloud); - self._detectRemovedAttrs(self, machs, self.attrsToDiscover.cloud); - for (var key in machs) { - currMachs[key] = machs[key]; - } - } - } - - self.prevMachs = currMachs; - - // update when we last scanned - self.lastScanAt = Date.now(); -} - -LocalRegistry.prototype._makeDiscoveries = function(self, machs, dattrs) { - // only the machs that are newly online are of interest to us, unless we are interested in node status, - // in which case newly offline nodes are also of interest - var now = Date.now(); - for (var machId in machs) { - for (var attr in dattrs) { - if (attr === 'status') { - // check if the node has gone offline - if ((now - machs[machId].lastCheckIn) > 2 * constants.localStorage.checkInInterval) { - // if we haven't already noted that the machine is offline... - if (!self.currentOfflineMachs[machId]) { - self.currentOfflineMachs[machId] = true; - // pass a dedupeId of zero for node down events - self.emit('discovery', 'status', dattrs[attr].offline, machId, 'offline', 0); - } - } else if (machs[machId].createdAt > self.lastScanAt) { - // the node is newly online (or was online before the current node went online) - self.emit('discovery', 'status', dattrs[attr].online, machId, machs[machId].status.payload, machs[machId].status.id); - // in case we currently have this node recorded as offline - delete self.currentOfflineMachs[machId]; - } - } else { - if (machs[machId].hasOwnProperty(attr) && machs[machId][attr].updatedAt > self.lastScanAt) { - self.emit('discovery', attr, dattrs[attr].onAdd, machId, machs[machId][attr].payload, machs[machId][attr].id); - } - } - } - } -} - -LocalRegistry.prototype._detectRemovedAttrs = function(self, machs, dattrs) { - // for each attribute to discover, see if it was there the last time we scanned local storage but is gone now - for (var machId in machs) { - for (var attr in dattrs) { - if (self.prevMachs[machId] && self.prevMachs[machId][attr] && !machs[machId][attr]) { - self.emit('attr-removed', attr, dattrs[attr].onRemove, machId); - } - } - } -} - -//============================================================================== -// Add and discover attributes -//============================================================================== - -/** - * Add custom, discoverable attributes on the node - */ -LocalRegistry.prototype.addAttributes = function(attrs, dedupeId) { - for (var attr in attrs) { - delete this.attrsToRemove[attr]; - this.attrsToAdd[attr] = { payload: attrs[attr], dedupeId: dedupeId }; - } -} - -/** - * Removes attrs, a list of attribute keys, from this node - */ -LocalRegistry.prototype.removeAttributes = function(attrs) { - for (var i = 0; i < attrs.length; i++) { - delete this.attrsToAdd[attrs[i]]; - } - if (this.started) { - this.attrsToRemove = this.attrsToRemove.concat(attrs); - } -} - -/** - * Discover other nodes with the given attributes - * This function need only store the attributes on the node. The LocalRegistry will - * look for other nodes with these attributes the next time it scans local storage. - */ -LocalRegistry.prototype.discoverAttributes = function(dattrs) { - for (var key in dattrs.device) { - this.attrsToDiscover.device[key] = dattrs.device[key]; - } - - for (var key in dattrs.fog) { - this.attrsToDiscover.fog[key] = dattrs.fog[key]; - } - - for (var key in dattrs.cloud) { - this.attrsToDiscover.cloud[key] = dattrs.cloud[key]; - } -} - -/** - * Stops discovering the specified attributes - */ -LocalRegistry.prototype.stopDiscoveringAttributes = function(dattrs) { - if (dattrs.device) { - for (var i = 0; i < dattrs.device.length; i++) { - delete this.attrsToDiscover.device[dattrs.device[i]]; - } - } - - if (dattrs.fog) { - for (var i = 0; i < dattrs.fog.length; i++) { - delete this.attrsToDiscover.fog[dattrs.fog[i]]; - } - } - - if (dattrs.cloud) { - for (var i = 0; i < dattrs.cloud.length; i++) { - delete this.attrsToDiscover.cloud[dattrs.cloud[i]]; - } - } -} - -//============================================================================== -// Helpers -//============================================================================== - -LocalRegistry.prototype._getBinName = function() { - var binNumber = this._hash(this.id); - if (this.machType === constants.globals.NodeType.FOG) { - return 'fogs_' + binNumber; - } else if (this.machType === constants.globals.NodeType.CLOUD) { - return 'clouds_' + binNumber; - } else { - return 'devices_' + binNumber; - } -} - -/** - * Hash a uuid into an integer in the range 0 to constants.localStorage.numBins-1 - */ -LocalRegistry.prototype._hash = function(uuid) { - var hash = 0, i, chr; - if (uuid.length === 0) return hash; - for (i = 0; i < uuid.length; i++) { - chr = uuid.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; - hash |= 0; // convert to a 32 bit integer - } - if (hash < 0) { - hash += 1; - hash *= -1; - } - return hash % constants.localStorage.numBins; -} - -/** - * Helper for computing wait time - */ -LocalRegistry.prototype._getWaitTime = function(attemptNumber) { - return Math.ceil(Math.random() * Math.pow(2, attemptNumber)); -} - -module.exports = LocalRegistry; diff --git a/lib/jdiscovery/mdns/CHANGES b/lib/jdiscovery/mdns/CHANGES deleted file mode 100644 index 6e564cdc..00000000 --- a/lib/jdiscovery/mdns/CHANGES +++ /dev/null @@ -1,102 +0,0 @@ -CHANGES - -Version 2.2.3 to 2.2.4 - - - changed Readme from textile to markdown, since npmjs.org doesn't render textfile well (ronkorving) - -Version 2.2.2 to 2.2.3 - - - errors that could be thrown asynchronously are now emitted as "error" (achingbrain) - -Version 2.2.1 to 2.2.2 - - - node-mdns now uses NAN for compatibility across a wide range of Node.js versions (incl 0.11) (donpark) - -Version 2.2.0 to 2.2.1 - - - changed uncatchable error into "error" event on the browser (marcooliveira) - -Version 2.1.4 to 2.2.0 - - - moved the repository back from Wizcorp/node_mdns to agnat/node_mdns - -Version 2.1.3 to 2.1.4 - - - added service to errors from the resolver (bjornstar) - -Version 2.1.2 to 2.1.3 - - - applied the fix from 2.1.0 to remaining parts of the code base (achingbrain) - -Version 2.1.1 to 2.1.2 - - - fixed an exception that was thrown when a service went down along with its network interface (achingbrain) - -Version 2.1.0 to 2.1.1 - - - fixed the interfaceIndex patch by mrose17 as it was breaking on Node 0.8 (ronkorving) - -Version 2.0.0-dev to 2.1.0 - - - errno was broken in Node v0.10 (mrose17) - - allow interfaceIndex to be "really big" (mrose17) - -Version 1.1.0 to 2.0.0-dev - - - empty version release (agnat) - -Version 1.0.0 to 1.1.0 - - - better handling of network interfaces - - error handling: exceptions/errors contain the numeric error code now - -Version 0.0.7 to 1.0.0 - - - replaced IOWatcher with a libuv based SocketWatcher (Tony Ealden) - - fixed an API typo: filterAdresses -> filterAddresses (major version bumped) - - first release that actually works on windows - -Version 0.0.6 to 0.0.7 - - - Bugfix: convert NULL strings to undefined values in callbacks - -Version 0.0.5 to 0.0.6 - - - use node-gyp in gyp based builds - - prepared a windows port - -Version 0.0.4 to 0.0.5 - - - Publish and receive TXT records - - - Build universal binaries on Mac OS - This helps to work around a architecture mismatch between gyp-build nodes - and waf-build addons. - - - Added experimental gyp-based build - - - Continuous integration and coverage testing. - - - Fixed FreeBSD build - -Version 0.0.3 to 0.0.4 - - - New service type objects: - The strings have been replaced with a small ServiceType object. Also, older - versions used TCP as the default protocol. The protocol is now mandatory. - However, the new syntax is much more flexible. See user guide at - http://agnat.github.com/node_mdns/user_guide.html#service_types. - - - The 'info' object is now called 'service' - - - The info.regtype property is now called service.type - - - The info.serviceName property is now called service.name - - - Callback signature changed: - flags is now a property of the service object (service.flags) - - - possibly more - - -vim: spell spelllang=en_us : diff --git a/lib/jdiscovery/mdns/LICENSE b/lib/jdiscovery/mdns/LICENSE deleted file mode 100644 index 50dea472..00000000 --- a/lib/jdiscovery/mdns/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2010 David Siegel - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - diff --git a/lib/jdiscovery/mdns/Makefile b/lib/jdiscovery/mdns/Makefile deleted file mode 100644 index a204aaed..00000000 --- a/lib/jdiscovery/mdns/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -BUILDTYPE ?= Release - -GCOV_OUT = build/reports/coverage/cpp -NCOV_OUT = build/reports/coverage - -TEST_OPTIONS= - -ifdef PULSE_BUILD_NUMBER - TEST_OPTIONS= --ascii --verbose -endif - -all: bindings - -bindings: - $(MAKE) -C build BUILDTYPE=$(BUILDTYPE) - -test: bindings - node --expose_gc utils/testrun $(TEST_OPTIONS) - -coverage: - $(MAKE) coverage_run BUILDTYPE=Coverage - -coverage_build: - $(MAKE) -C build BUILDTYPE=Coverage - -jscoverage: - jscoverage -v --no-highlight lib/ build/Coverage/lib - -coverage_run: coverage_build jscoverage - lcov -d build/$(BUILDTYPE)/obj.target/dns_sd_bindings/src --zerocounters - mkdir -p $(GCOV_OUT)/html; - NCOV_OUT=$(NCOV_OUT) node --expose_gc utils/testrun $(TEST_OPTIONS) - lcov --base-directory build \ - --directory build/$(BUILDTYPE)/obj.target/dns_sd_bindings/src \ - --output-file $(GCOV_OUT)/testrun_all.info \ - --capture - utils/ncov - lcov --output-file $(GCOV_OUT)/testrun.info \ - --extract \ - $(GCOV_OUT)/testrun_all.info "$(abspath .)/*" \ - | tee $(GCOV_OUT)/lcov.log - genhtml --output-directory $(GCOV_OUT)/html \ - --demangle-cpp \ - $(GCOV_OUT)/testrun.info - tail -n 3 $(GCOV_OUT)/lcov.log | utils/coverage > $(GCOV_OUT)/coverage.properties - -doc: - utils/docpack - -website: - echo TODO - -.PHONY: test citest coverage coverage_build coverage_run bindings jscoverage doc website - diff --git a/lib/jdiscovery/mdns/README.md b/lib/jdiscovery/mdns/README.md deleted file mode 100644 index 8b1833fa..00000000 --- a/lib/jdiscovery/mdns/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# mdns -- node.js Service Discovery - -* Package: mdns -* Description: multicast DNS service discovery -* Installation: `npm install mdns` (see below) -* Documentation: [mdns user guide](http://agnat.github.com/node_mdns/user_guide.html) -* License: [MIT](http://github.com/agnat/node_mdns/blob/master/LICENSE) -* Donations: [![Flattr this git repository](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=agnat&url=https://github.com/agnat/node_mdns&title=node_mdns&tags=github&category=software) - -mdns adds multicast DNS service discovery, also known as zeroconf or bonjour to Node.js. It provides an object based interface to announce and browse services on the local network. - -## Synopsis - -```js -// import the module -var mdns = require('mdns'); - -// advertise a http server on port 4321 -var ad = mdns.createAdvertisement(mdns.tcp('http'), 4321); -ad.start(); - -// watch all http servers -var browser = mdns.createBrowser(mdns.tcp('http')); -browser.on('serviceUp', function(service) { - console.log("service up: ", service); -}); -browser.on('serviceDown', function(service) { - console.log("service down: ", service); -}); -browser.start(); - -// discover all available service types -var all_the_types = mdns.browseThemAll(); // all_the_types is just another browser... -``` - -## Installation - -On Linux and other systems using the avahi daemon the avahi dns_sd compat library and its header files are required. On debianesque systems the package name is `libavahi-compat-libdnssd-dev`. On other platforms Apple's [mDNSResponder](http://opensource.apple.com/tarballs/mDNSResponder/) is recommended. Care should be taken not to install more than one mDNS stack on a system. - -On Windows you are going to need Apples "Bonjour SDK for Windows". You can download it either from Apple (registration required) or various unofficial sources. Take your pick. After installing the SDK restart your computer and make sure the `BONJOUR_SDK_HOME` environment variable is set. You'll also need a compiler. Microsoft Visual Studio Express will do. On Windows node >=0.7.9 is required. - -mdns is available as a npm package: - -```sh -npm install mdns -``` - -If you want to play with the latest source code, here is a more manual approach: - -```sh -git clone http://github.com/agnat/node_mdns -cd node_mdns -npm link && npm test -``` - -In case you want to run or even publish your package using the development version of mdns you may set the version field to a tarball URL: - -```json -{ "name": "discomvobulator" -, "version": "0.0.1" -, "description": "covers all your discomvobulation needs" -, "dependencies": - { "mdns": "https://github.com/agnat/node_mdns/tarball/master" - } -} -``` - -## Documentation - -See the [user guide](http://agnat.github.com/node_mdns/user_guide.html). - -## Contributors - -In random order: - -* Orlando Vazquez ([orlandov](https://github.com/orlandov)) -* Ryan Dahl ([ry](https://github.com/ry)) -* Dominic Tarr ([dominictarr](https://github.com/dominictarr)) -* Emil Stenqvist ([emilisto](https://github.com/emilisto)) -* Toby Ealden ([TobyEalden](https://github.com/TobyEalden)) -* Ron Korving ([ronkorving](https://github.com/ronkorving)) -* Don Park ([donpark](https://github.com/donpark)) -* Cong Liu ([ghostoy](https://github.com/ghostoy)) -* Tian Zhang ([KhaosT](https://github.com/KhaosT)) - -Your name is missing on the list? Shame on me. Please open an issue. - -## Bugs and Contributions - -If you find a bug, please report it using the [issue tracker](http://github.com/agnat/node_mdns/issues). diff --git a/lib/jdiscovery/mdns/binding.gyp b/lib/jdiscovery/mdns/binding.gyp deleted file mode 100644 index 92dcea16..00000000 --- a/lib/jdiscovery/mdns/binding.gyp +++ /dev/null @@ -1,79 +0,0 @@ -{ 'targets': [ - { 'target_name': 'dns_sd_bindings' - , 'sources': [ 'src/dns_sd.cpp' - , 'src/dns_service_browse.cpp' - , 'src/dns_service_enumerate_domains.cpp' - , 'src/dns_service_get_addr_info.cpp' - , 'src/dns_service_process_result.cpp' - , 'src/dns_service_ref.cpp' - , 'src/dns_service_ref_deallocate.cpp' - , 'src/dns_service_ref_sock_fd.cpp' - , 'src/dns_service_register.cpp' - , 'src/dns_service_resolve.cpp' - , 'src/dns_service_update_record.cpp' - , 'src/mdns_utils.cpp' - , 'src/network_interface.cpp' - , 'src/socket_watcher.cpp' - , 'src/txt_record_ref.cpp' - , 'src/txt_record_create.cpp' - , 'src/txt_record_deallocate.cpp' - , 'src/txt_record_set_value.cpp' - , 'src/txt_record_get_length.cpp' - , 'src/txt_record_buffer_to_object.cpp' - ] - , 'conditions': [ - [ 'OS!="mac" and OS!="win"', { - 'libraries': [ '-ldns_sd' ] - }] - , [ 'OS=="mac"', { - 'defines': [ 'HAVE_DNSSERVICEGETADDRINFO' ] - }] - , ['OS=="freebsd"', { - 'include_dirs': [ '/usr/local/include' ] - , 'libraries': [ '-L/usr/local/lib' ] - }] - , ['OS=="win"', { - 'variables': { - 'BONJOUR_SDK_DIR': '$(BONJOUR_SDK_HOME)', # Preventing path resolution problems by saving the env var in variable first - 'PLATFORM': '$(Platform)' # Set the platform - } - , 'include_dirs': [ '<(BONJOUR_SDK_DIR)/Include' ] - , 'defines': [ 'HAVE_DNSSERVICEGETADDRINFO' ] - , 'libraries': [ '-l<(BONJOUR_SDK_DIR)/Lib/<(PLATFORM)/dnssd.lib' - , '-lws2_32.lib' - , '-liphlpapi.lib' - ] - }] - ] - , "include_dirs": [ " 0x7e || c === 0x3d) { - throw new Error("key must be all printable ascii characters exluding '='"); - } - } -} diff --git a/lib/jdiscovery/mdns/lib/avahi.js b/lib/jdiscovery/mdns/lib/avahi.js deleted file mode 100644 index fb1b6955..00000000 --- a/lib/jdiscovery/mdns/lib/avahi.js +++ /dev/null @@ -1,32 +0,0 @@ -var dns_sd = require('./dns_sd'); - -function supportsInterfaceIndexLocalOnly() { - try { - var sr = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = dns_sd.kDNSServiceInterfaceIndexLocalOnly - , name = null - , type = '_http._tcp' - , domain = null - , host = null - , port = 4321 - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister( sr, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - } catch (ex) { - if (ex.errorCode === dns_sd.kDNSServiceErr_Unsupported) { - if (sr && sr.initialized) { - dns_sd.DNSServiceRefDeallocate(sr); - } - return false; - } - console.warn('Unexpected result while probing for avahi:', ex); - } - dns_sd.DNSServiceRefDeallocate(sr); - return true; -} - -module.exports = ! supportsInterfaceIndexLocalOnly(); diff --git a/lib/jdiscovery/mdns/lib/browser.js b/lib/jdiscovery/mdns/lib/browser.js deleted file mode 100644 index 02b60440..00000000 --- a/lib/jdiscovery/mdns/lib/browser.js +++ /dev/null @@ -1,128 +0,0 @@ -var dns_sd = require('./dns_sd') - , nif = require('./network_interface') - , util = require('util') - , rst = require('./resolver_sequence_tasks') - , st = require('./service_type') - , MDNSService = require('./mdns_service').MDNSService - ; - -var Browser = exports.Browser = function Browser(serviceType, options) { - MDNSService.call(this); - var self = this; - - options = options || {}; - var flags = options.flags || 0 - , ifaceIdx = nif.interfaceIndex(options) - , domain = options.domain || null - , context = options.context || null - , requested_type = st.makeServiceType( serviceType ); - ; - - var interfaceNames = []; - - function on_service_changed(sdRef, flags, ifaceIdx, errorCode, serviceName, - serviceType, replyDomain, context) - { - function on_resolver_done(error, service) { - if (error) { - self.emit('error', error, service); - } else { - self.emit('serviceChanged', service, context); - self.emit('serviceUp', service, context); - } - } - if (errorCode == dns_sd.kDNSServiceErr_NoError) { - if (requested_type.isWildcard()) { - serviceType = serviceName + '.' + serviceType.split('.').shift(); - serviceName = null; - } - - var type; - - try { - type = st.makeServiceType(serviceType); - } catch(e) { - self.emit('error', e); - return; - } - - var service = { - interfaceIndex: ifaceIdx - , type: type - , replyDomain: replyDomain - , flags: flags - }; - if (serviceName) service.name = serviceName; - - if (dns_sd.kDNSServiceInterfaceIndexLocalOnly === ifaceIdx) { - service.networkInterface = nif.loopbackName(); - } else if (typeof dns_sd.if_indextoname !== 'undefined' && ifaceIdx > 0) { - try { - service.networkInterface = dns_sd.if_indextoname(ifaceIdx); - - interfaceNames[ifaceIdx] = service.networkInterface; - } catch(e) { - if(typeof interfaceNames[ifaceIdx] !== "undefined") { - service.networkInterface = interfaceNames[ifaceIdx]; - } else { - self.emit('error', e); - } - } - } - - if (flags & dns_sd.kDNSServiceFlagsAdd) { - resolve(service, - options.resolverSequence || Browser.defaultResolverSequence, - on_resolver_done); - } else { - self.emit('serviceChanged', service, context); - self.emit('serviceDown', service, context); - } - } else { - self.emit('error', dns_sd.buildException(errorCode)); - } - } - - dns_sd.DNSServiceBrowse(self.serviceRef, flags, ifaceIdx, '' + requested_type, - domain, on_service_changed, context); -} -util.inherits(Browser, MDNSService); - -var resolve = exports.resolve = function resolve(service, sequence, callback) { - var step = 0; - if ( ! callback) { - callback = sequence; - sequence = Browser.defaultResolverSequence; - } - - function next(error) { - if (error) { - callback(error, service); - return; - } - if (sequence.length === step) { - callback(undefined, service); - return; - } - sequence[step++](service, next); - } - - next(); -} - -Browser.create = function create(serviceType, options) { - return new Browser(serviceType, options); -} - -Browser.defaultResolverSequence = [ - rst.DNSServiceResolve() -, 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo() -, rst.makeAddressesUnique() -]; - -exports.browseThemAll = function browseThemAll(options) { - options = options || {} - options.resolverSequence = options.resolverSequence || []; - return Browser.create(st.ServiceType.wildcard, options); -} - diff --git a/lib/jdiscovery/mdns/lib/dns_sd.js b/lib/jdiscovery/mdns/lib/dns_sd.js deleted file mode 100644 index 5668b04f..00000000 --- a/lib/jdiscovery/mdns/lib/dns_sd.js +++ /dev/null @@ -1,37 +0,0 @@ -var path = require('path'); -var major, minor, patch; - -if (process.version.match(/^v(\d+)\.(\d+)\.(\d+).*$/)) { - major = parseInt(RegExp.$1); - minor = parseInt(RegExp.$2); - patch = parseInt(RegExp.$3); -} - -var default_dir = major === 0 && minor <= 4 ? 'default' : 'Release' - , buildtype = process.env.BUILDTYPE || default_dir - ; - -//console.log(major, minor, patch, default_dir, buildtype); - -function product(type) { - if (type === 'Coverage') { - return path.join('..', 'dns_sd_bindings') - } - return path.join('..', 'build', type, 'dns_sd_bindings') -} - -try { - module.exports = require(product(buildtype)); -} catch (ex) { - if (! ex.code) { - if (/not find/.test(ex)) { - ex.code = 'MODULE_NOT_FOUND'; - } - } - if (ex.code === 'MODULE_NOT_FOUND') { - module.exports = require(product(default_dir)); - console.warn('dns_sd: failed to load requested ', buildtype, 'build. using', default_dir, 'instead.'); - } else { - throw ex; - } -} diff --git a/lib/jdiscovery/mdns/lib/io_watcher.js b/lib/jdiscovery/mdns/lib/io_watcher.js deleted file mode 100644 index 5153003c..00000000 --- a/lib/jdiscovery/mdns/lib/io_watcher.js +++ /dev/null @@ -1,3 +0,0 @@ -var dns_sd = require('./dns_sd'); -exports.IOWatcher = typeof dns_sd.SocketWatcher !== 'undefined' ? - dns_sd.SocketWatcher : process.binding('io_watcher').IOWatcher; diff --git a/lib/jdiscovery/mdns/lib/mdns.js b/lib/jdiscovery/mdns/lib/mdns.js deleted file mode 100644 index a695774d..00000000 --- a/lib/jdiscovery/mdns/lib/mdns.js +++ /dev/null @@ -1,32 +0,0 @@ -var dns_sd = require('./dns_sd') - , ad = require('./advertisement') - , browser = require('./browser') - , st = require('./service_type') - , nif = require('./network_interface') - ; - -exports.dns_sd = dns_sd; - -exports.Advertisement = ad.Advertisement; -exports.createAdvertisement = ad.Advertisement.create; - -exports.Browser = browser.Browser; -exports.createBrowser = browser.Browser.create; -exports.browseThemAll = browser.browseThemAll; -exports.resolve = browser.resolve; - -exports.MDNSService = require('./mdns_service').MDNSService; - -exports.ServiceType = st.ServiceType; -exports.makeServiceType = st.makeServiceType; -exports.tcp = st.protocolHelper('tcp'); -exports.udp = st.protocolHelper('udp'); - -exports.loopbackInterface = nif.loopbackInterface; - -exports.dns_sd.exportConstants(exports); - -exports.rst = require('./resolver_sequence_tasks'); - -exports.isAvahi = require('./avahi.js'); - diff --git a/lib/jdiscovery/mdns/lib/mdns_service.js b/lib/jdiscovery/mdns/lib/mdns_service.js deleted file mode 100644 index c6f6dccc..00000000 --- a/lib/jdiscovery/mdns/lib/mdns_service.js +++ /dev/null @@ -1,44 +0,0 @@ -var dns_sd = require('./dns_sd') - , util = require('util') - , events = require('events') - , IOWatcher = require('./io_watcher').IOWatcher; - ; - -function MDNSService() { - events.EventEmitter.call(this); - var self = this; - - self._watcherStarted = false; - self.serviceRef = new dns_sd.DNSServiceRef(); - self.watcher = new IOWatcher(); - self.watcher.host = self; // TODO: Find out what this is for ... - self.watcher.callback = function() { - if (self._watcherStarted) { - try { - dns_sd.DNSServiceProcessResult.call(self, self.serviceRef); - } catch (error) { - self.emit("error", error); - } - } - }; -} -util.inherits(MDNSService, events.EventEmitter); -exports.MDNSService = MDNSService; - -MDNSService.prototype.start = function start() { - if (this._watcherStarted) { - throw new Error("mdns service already started"); - } - this.watcher.set(this.serviceRef.fd, true, false); - this.watcher.start(); - this._watcherStarted = true; -} - -MDNSService.prototype.stop = function stop() { - if (this._watcherStarted) { - this.watcher.stop(); - dns_sd.DNSServiceRefDeallocate(this.serviceRef); - this.serviceRef = null; - this._watcherStarted = false; - } -} diff --git a/lib/jdiscovery/mdns/lib/network_interface.js b/lib/jdiscovery/mdns/lib/network_interface.js deleted file mode 100644 index 7c6800ff..00000000 --- a/lib/jdiscovery/mdns/lib/network_interface.js +++ /dev/null @@ -1,86 +0,0 @@ -var net = require('net') - , os = require('os') - , dns_sd = require('./dns_sd') - , interfaceIndexDeprecatedWarningPrinted = false - ; - -var have_if_nametoindex = typeof dns_sd.if_nametoindex !== 'undefined'; - -exports.interfaceIndex = function interfaceIndex(options) { - var networkInterface - , index = 0; - if (typeof options.interfaceIndex !== 'undefined') { - if( ! interfaceIndexDeprecatedWarningPrinted) { - console.warn("WARNING: 'interfaceIndex' is deprecated and will be " + - "removed. Please use 'networkInterface' instead and see the " + - "documentation on why it's cool."); - interfaceIndexDeprecatedWarningPrinted = true; - } - networkInterface = options.interfaceIndex; - } else { - networkInterface = options.networkInterface; - } - if (typeof networkInterface !== 'undefined') { - if (net.isIP(networkInterface)) { - if ( ! have_if_nametoindex) { - throw new Error('IP address to interface index conversion is not ' + - 'supported on this platform'); - } - index = dns_sd.if_nametoindex(addressToName(networkInterface)); - //console.log('got IP', networkInterface, '->', index); - } else if (isString(networkInterface)) { - if ( ! have_if_nametoindex) { - throw new Error('interface name to index conversion is not supported ' + - 'on this platform'); - } - index = dns_sd.if_nametoindex(networkInterface); - //console.log('got if name', networkInterface, '->', index); - } else { - //console.log('got index', networkInterface); - index = networkInterface; - } - } - //console.log('interface index:', index); - return index; -} - -exports.loopbackInterface = function loopbackInterface() { - if (typeof dns_sd.kDNSServiceInterfaceIndexLocalOnly !== 'undefined') { - return dns_sd.kDNSServiceInterfaceIndexLocalOnly; - } else { - return loopbackName(); - } -} - -var loopbackName = exports.loopbackName = function loopbackName() { - var interfaces = os.networkInterfaces(); - for (var name in interfaces) { - for (var i = 0; i < interfaces[name].length; ++i) { - if (interfaces[name][i].address === '127.0.0.1') { - return name; - } - } - } - throw new Error('failed to find loopback interface'); -} - -function addressToName(address) { - if (typeof os.networkInterfaces === 'undefined') { - throw new Error('IP address to interface index conversion is not ' + - 'supported with this version of node'); - } - var addresses = os.networkInterfaces(); - for (var name in addresses) { - for (var i = 0; i < addresses[name].length; ++i) { - if (addresses[name][i].address === address) { - return name; - } - } - } - throw new Error('interface with address ' + address + ' does not exist'); -} - -function isString(s) { - return toString.call(s) == '[object String]'; -} - diff --git a/lib/jdiscovery/mdns/lib/resolver_sequence_tasks.js b/lib/jdiscovery/mdns/lib/resolver_sequence_tasks.js deleted file mode 100644 index f017038d..00000000 --- a/lib/jdiscovery/mdns/lib/resolver_sequence_tasks.js +++ /dev/null @@ -1,211 +0,0 @@ -var dns_sd = require('./dns_sd') - , util = require('util') - , MDNSService = require('./mdns_service').MDNSService - ; - -exports.DNSServiceResolve = function DNSServiceResolve(options) { - options = options || {}; - options.flags = options.flags || 0; - options.unwrapTxtRecord = - 'unwrapTxtRecord' in options ? options.unwrapTxtRecord : true; - return function DNSServiceResolve(service, next) { - try { - var resolver = new MDNSService(); - - function on_resolver_done(sdRef, flags, iface, errorCode, fullname, - hosttarget, port, txtRecord, context) - { - try { - var error = dns_sd.buildException(errorCode); - if ( ! error && service.interfaceIndex === iface) { - if (fullname) service.fullname = fullname; - if (hosttarget) service.host = hosttarget; - if (port) service.port = port; - // all services have a TXT record. ignore the empty ones. - if (txtRecord.length > 1) { - service.rawTxtRecord = txtRecord; - if (options.unwrapTxtRecord) { - service.txtRecord = dns_sd.txtRecordBufferToObject(txtRecord) - } - } - } - resolver.stop(); - next(error); - } catch (ex) { - resolver.stop(); - next(ex); - } - } - - dns_sd.DNSServiceResolve(resolver.serviceRef, options.flags, - service.interfaceIndex, service.name, '' + service.type, - service.replyDomain, on_resolver_done, null); - resolver.start(); - } catch (ex) { - resolver.stop(); - next(ex); - } - }; -} - -exports.DNSServiceGetAddrInfo = function DNSServiceGetAddrInfo(options) { - options = options || {}; - var family_flags = 0; - if ('families' in options) { - if (options.families.indexOf(4) !== -1) { - family_flags |= dns_sd.kDNSServiceProtocol_IPv4; - } - if (options.families.indexOf(6) !== -1) { - family_flags |= dns_sd.kDNSServiceProtocol_IPv6; - } - } - return function DNSServiceGetAddrInfo(service, next) { - try { - var adr_getter = new MDNSService() - , addresses = [] - ; - - function on_get_addr_info_done(sdRef, flags, iface, errorCode, hostname, - address, context) - { - try { - var error = dns_sd.buildException(errorCode); - if (error) { - adr_getter.stop() - next(error); - } else { - if (iface === service.interfaceIndex) { - addresses.push(address); - } - if ( ! (dns_sd.kDNSServiceFlagsMoreComing & flags)) { - service.addresses = addresses; - adr_getter.stop() - next(); - } - } - } catch (ex) { - adr_getter.stop(); - next(ex); - } - } - - dns_sd.DNSServiceGetAddrInfo( - adr_getter.serviceRef, 0, service.interfaceIndex, family_flags, - service.host, on_get_addr_info_done, null); - adr_getter.start(); - } catch (ex) { - adr_getter.stop(); - next(ex); - } - } -} - -var _getaddrinfo; -try { - var cares = process.binding('cares_wrap'); - function getaddrinfo_complete(err, addresses, cb) { - if (addresses) { - cb(undefined, addresses); - } else if (err === 'ENOENT') { - cb(undefined, []); - } else { - cb(errnoException(err, 'getaddrinfo')); - } - } - function getaddrinfo_0_11(host, family, cb) { - var req = new cares.GetAddrInfoReqWrap() - , err = cares.getaddrinfo(req, host, family, 0, false) - ; - req.oncomplete = function oncomplete(err, addresses) { - getaddrinfo_complete(err, addresses, cb); - } - if (err) throw errnoException(err, 'getaddrinfo', host); - } - function getaddrinfo_0_10(host, family, cb) { - var wrap = cares.getaddrinfo(host, family); - if ( ! wrap) { - throw errnoException(process._errno || global.errno, 'getaddrinfo'); - } - wrap.oncomplete = function (addresses) { - getaddrinfo_complete((process._errno || global.errno), addresses, cb); - } - } - // node 0.11+ cares.getaddrinfo function uses request object. - // use appropriate version based on node version number - if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) > 0.1) { - _getaddrinfo = getaddrinfo_0_11; - } else { - _getaddrinfo = getaddrinfo_0_10; - } -} catch (ex) { - _getaddrinfo = process.binding('net').getaddrinfo; -} - -exports.getaddrinfo = function getaddrinfo(options) { - options = options || {}; - var families = options.families || [4, 6]; - return function getaddrinfo(service, next) { - var last_error - , counter = 0 - ; - // XXX in older versions of node a zero family value is not supported - families.forEach(function(family) { - _getaddrinfo(service.host, family, function(error, addresses) { - if (error) { - last_error = error - } else { - service.addresses = (service.addresses || []).concat(addresses); - } - if (++counter === families.length) { - next(last_error); - } - }); - }); - } -} - -function unique(array) { - var o = {} , p , r = [] ; - array.forEach(function(e) { o[e] = undefined }); - for (p in o) { r.push(p) } - return r; -} - -exports.makeAddressesUnique = function makeAddressesUnique() { - return function makeAddressesUnique(service, next) { - service.addresses = unique(service.addresses); - next(); - } -} - -exports.filterAddresses = function filterAddresses(filter_function) { - return function filterAddresses(service, next) { - service.addresses = (service.addresses || []).filter(filter_function); - next(); - } -} - -exports.logService = function logService() { - return function logService(service, next) { - console.log(service); - next(); - } -} - -function errnoException(errorno, syscall) { - // TODO make this more compatible with ErrnoException from src/node.cc - // Once all of Node is using this function the ErrnoException from - // src/node.cc should be removed. - var e = new Error(syscall + ' ' + errorno); - - // For backwards compatibility. libuv returns ENOENT on NXDOMAIN. - if (errorno == 'ENOENT') { - errorno = 'ENOTFOUND' - } - - e.errno = e.code = errorno; - e.syscall = syscall; - return e; -} - - diff --git a/lib/jdiscovery/mdns/lib/service_type.js b/lib/jdiscovery/mdns/lib/service_type.js deleted file mode 100644 index c75ea32e..00000000 --- a/lib/jdiscovery/mdns/lib/service_type.js +++ /dev/null @@ -1,199 +0,0 @@ -var ServiceType = exports.ServiceType = function ServiceType(/* ... */) { - this.name = ''; - this.protocol = ''; - this.subtypes = []; - - var args; - if (arguments.length === 1) { - args = Array.isArray(arguments[0]) ? arguments[0] : [arguments[0]]; - } else if (arguments.length > 1) { - args = Array.prototype.slice.call(arguments); - } - if (args) { - if (args.length === 1) { - if (typeof args[0] === 'string') { - this.fromString(args[0]); - } else if (Array.isArray(args[0])) { - this.fromArray(args[0]); - } else if (typeof args[0] === 'object') { - this.fromJSON(args[0]); - } else { - throw new Error('argument must be a string, array or object'); - } - } else if (args.length >= 2) { - this.fromArray(args); - } else { // zero arguments - // uninitialized ServiceType ... fine with me - } - } -} - -ServiceType.wildcard = '_services._dns-sd._udp.'; -ServiceType.prototype.isWildcard = function isWildcard() { - return this.toString() === ServiceType.wildcard; -} - -ServiceType.prototype.toString = function() { - var type_string = _u(this.name) + "." + _u(this.protocol); - if (this.fullyQualified) { - type_string += '.' - } - if (this.subtypes.length > 0) { - var subtypes = this.subtypes.map(function(t) { return _u(t) }); - subtypes.unshift(type_string); - type_string = subtypes.join(','); - } - return type_string; -} - -ServiceType.prototype.fromString = function fromString(string) { - var is_wildcard = ServiceType.prototype.isWildcard.call(string) - , subtypes = string.split(',') - , primary_string = subtypes.shift() - , service_tokens = primary_string.split('.') - , service_type = service_tokens.shift() - , protocol - ; - if (is_wildcard) { - service_type += '.' + service_tokens.shift(); - } - protocol = service_tokens.shift() - - checkProtocolU(protocol); - if ( ! is_wildcard) { - checkFormat(service_type); - } - subtypes.forEach(function(t) { checkFormat(t) }); - if (service_tokens.length === 1 && service_tokens[0] === '') { - // trailing dot - this.fullyQualified = true - } else if (service_tokens.length > 0) { - throw new Error("trailing tokens '" + service_tokens.join('.') + "' in " + - "service type string '" + string + "'"); - } - - this.name = service_type.substr(1); - this.protocol = protocol.substr(1); - this.subtypes = subtypes.map(function(t) { return t.substr(1) }); -} - -ServiceType.prototype.toArray = function toArray() { - return [this.name, this.protocol].concat(this.subtypes); -} - -ServiceType.prototype.fromArray = function fromArray(array) { - var service_type = _uu(array.shift()) - , protocol = _uu(array.shift()) - , subtypes = array.map(function(t) { return _uu(t) }) - ; - checkLengthAndCharset(service_type); - checkProtocol(protocol); - subtypes.forEach(function(t) { checkLengthAndCharset(t) }); - - this.name = service_type; - this.protocol = protocol; - this.subtypes = subtypes -} - -ServiceType.prototype.fromJSON = function fromJSON(obj) { - if ( ! ('name' in obj)) { - throw new Error('required property name is missing'); - } - if ( ! ('protocol' in obj)) { - throw new Error('required property protocol is missing'); - } - - var service_type = _uu(obj.name) - , protocol = _uu(obj.protocol) - , subtypes = 'subtypes' in obj ? - obj.subtypes.map(function(t) { return _uu(t) }) : [] - ; - - checkLengthAndCharset(service_type); - checkProtocol(protocol); - subtypes.forEach(function(t) { checkLengthAndCharset(t) }); - - this.name = service_type; - this.protocol = protocol; - this.subtypes = subtypes; - if ('fullyQualified' in obj) { - this.fullyQualified = obj.fullyQualified; - } -} - -ServiceType.prototype.matches = function matches(other) { - return this.name === other.name && this.protocol === other.protocol; - // XXX handle subtypes -} - -exports.makeServiceType = function makeServiceType() { - if (arguments.length === 1 && arguments[0] instanceof ServiceType) { - return arguments[0]; - } - return new ServiceType(Array.prototype.slice.call(arguments)); -} - -exports.protocolHelper = function protocolHelper(protocol) { - return function() { - var args = Array.prototype.slice.call(arguments); - if (isProtocol(args[1])) { - throw new Error("duplicate protocol '" + args[1] + "' in arguments"); - } - args.splice(1,0, protocol); - return exports.makeServiceType.apply(this, args); - } -} - -function isProtocol(str) { - return str === 'tcp' || str === '_tcp' || str === 'udp' || str === '_udp'; -} - -function _u(str) { return "_" + str; } -function _uu(str) { return str[0] === '_' ? str.substr(1) : str; } - -var charset_regex = /[^-a-zA-Z0-9]/; -function checkLengthAndCharset(str) { - if (str.length === 0) { - throw new Error('type ' + str + ' must not be empty'); - } -/* - if (str.length > 15) { - throw new Error('type ' + str + ' has more than 15 characters'); - } - if (str.match(charset_regex)) { - throw new Error('type ' + str + ' may only contain alphanumeric ' + - 'characters and hyphens'); - } -*/ -} - -var format_regex = /_[-a-zA-Z0-9]+/; -function checkFormat(str) { - if (str.length === 0) { - throw new Error('type string must not be empty'); - } -/* - if (str.length > 16) { // 16 is correct because we have a leading underscore - throw new Error('type ' + _uu(str) + ' has more than 15 characters'); - } - if ( ! str.match(format_regex)) { - throw new Error('type ' + str + ' must start with an underscore ' + - 'followed by alphanumeric characters and hyphens only'); - } -*/ -} - -function checkProtocolU(str) { - if ( ! (str === '_tcp' || str === '_udp')) { - throw new Error("protocol must be either '_tcp' or '_udp' but is '" + - str + "'"); - } -} - -function checkProtocol(str) { - if ( ! (str === 'tcp' || str === 'udp')) { - throw new Error("protocol must be either '_tcp' or '_udp' but is '" + - str + "'"); - } -} - diff --git a/lib/jdiscovery/mdns/node-waf.bat b/lib/jdiscovery/mdns/node-waf.bat deleted file mode 100644 index caf61c47..00000000 --- a/lib/jdiscovery/mdns/node-waf.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -REM A creative way to make 'npm install' succeed on windows -REM without breaking the package diff --git a/lib/jdiscovery/mdns/out/reports/tests.json b/lib/jdiscovery/mdns/out/reports/tests.json deleted file mode 100644 index cbc33a08..00000000 --- a/lib/jdiscovery/mdns/out/reports/tests.json +++ /dev/null @@ -1,1275 +0,0 @@ -{ - "test_browser": { - "Browser": { - "Should retrieve interface name from cache when interface index is no longer valid": [ - { - "test": "equal" - }, - { - "test": "ok" - }, - { - "test": "ok" - }, - { - "test": "equal" - } - ], - "Should survive invalid MDNS advert": [ - { - "test": "equal" - } - ] - } - }, - "test_dns_sd": { - "DNSServiceRef": [ - { - "test": "ok", - "message": "DNSServiceRef must be truthy" - }, - { - "test": "strictEqual", - "message": "File descriptor must be -1" - }, - { - "test": "strictEqual", - "message": "DNSServiceRef must not be initialized" - } - ], - "DNSServiceRegister()": [ - { - "test": "doesNotThrow", - "message": "Call with minimal argumentss must succeed." - }, - { - "test": "notStrictEqual", - "message": "File descriptor must not be -1 after initialization" - }, - { - "test": "strictEqual", - "message": "DNSServiceRef must be initialized" - }, - { - "test": "throws", - "message": "Duplicate initialization of DNSServiceRef must throw" - }, - { - "test": "doesNotThrow", - "message": "Call with all arguments on must succed." - }, - { - "test": "throws", - "message": "Call with zero arguments must throw." - }, - { - "test": "throws", - "message": "Call with eight arguments must throw." - }, - { - "test": "throws", - "message": "'flags' must be a number, not a string." - }, - { - "test": "throws", - "message": "'flags' must be a number, not a string." - }, - { - "test": "throws", - "message": "'interfaceIndex' must be a number, not a string." - }, - { - "test": "throws", - "message": "'name' must be a string, not a number." - }, - { - "test": "throws", - "message": "'regtype' must be a string, not null." - }, - { - "test": "throws", - "message": "'regtype' has to be a string, not a number." - }, - { - "test": "throws", - "message": "'domain' must not be a string, not a number." - }, - { - "test": "throws", - "message": "'host' must be a string, not a number." - }, - { - "test": "throws", - "message": "'port' must be a number, not a string." - }, - { - "test": "throws", - "message": "'txtRecord' must be a TXTRecordRef or buffer, not a number." - }, - { - "test": "throws", - "message": "'callback' must be a function, not a string." - }, - { - "test": "throws", - "message": "port number must be <= 65535." - }, - { - "test": "throws", - "message": "port number must >= 0." - } - ], - "DNSServiceProcessResult()": [ - { - "test": "throws" - }, - { - "test": "throws" - }, - { - "test": "throws" - }, - { - "test": "throws" - }, - { - "test": "strictEqual", - "message": "serviceRef must be identical" - }, - { - "test": "strictEqual", - "message": "'flags' must be of type number" - }, - { - "test": "strictEqual", - "message": "'errorCode' must be of type number" - }, - { - "test": "strictEqual", - "message": "'errorCode' must be kDNSServiceErr_NoError" - }, - { - "test": "strictEqual", - "message": "'name' must be of type string" - }, - { - "test": "strictEqual", - "message": "'serviceType' must be of type string" - }, - { - "test": "strictEqual", - "message": "'domain' must be of type string" - }, - { - "test": "strictEqual", - "message": "'context' must be of type string (in this test)" - }, - { - "test": "strictEqual", - "message": "expected 'foobar' but got 'foobar'" - } - ], - "DNSServiceRefSockFD()": [ - { - "test": "throws", - "message": "call with uninitialized serviceRef must throw" - }, - { - "test": "doesNotThrow", - "message": "DNSServiceRefSockFD() must not throw" - }, - { - "test": "notEqual", - "message": "file descriptor must not be -1" - }, - { - "test": "strictEqual", - "message": "result of DNSServiceRefSockFD() and fd getter must be the same" - }, - { - "test": "throws", - "message": "argument must be a DNSServiceRef" - }, - { - "test": "throws", - "message": "must throw when called with not enough arguments" - } - ], - "DNSServiceBrowse()": [ - { - "test": "doesNotThrow", - "message": "DNSServiceBrowse() must not throw" - }, - { - "test": "throws", - "message": "serviceRef already initialized" - }, - { - "test": "throws", - "message": "not enough arguments" - }, - { - "test": "throws", - "message": "'serviceRef' must not be a string" - }, - { - "test": "throws", - "message": "'flags' must be a number, not a string" - }, - { - "test": "throws", - "message": "'interfaceIndex' must be a number, not a string" - }, - { - "test": "throws", - "message": "'regtype' must be a string, not null" - }, - { - "test": "throws", - "message": "'regtype' must be a string, not a number" - }, - { - "test": "throws", - "message": "'domain' must be a string, not a number" - }, - { - "test": "throws", - "message": "'callback' must be a function, not a number" - }, - { - "test": "doesNotThrow", - "message": "DNSServiceBrowse() must not throw" - }, - { - "test": "doesNotThrow", - "message": "DNSServiceBrowse() must not throw" - }, - { - "test": "doesNotThrow", - "message": "DNSServiceBrowse() must not throw" - } - ], - "DNSServiceRefDeallocate()": [ - { - "test": "strictEqual", - "message": "'initialized' must be true after inititalization" - }, - { - "test": "strictEqual", - "message": "'initialized' must be false after deallocation" - }, - { - "test": "strictEqual", - "message": "'fd' must be -1 after deallocation" - }, - { - "test": "throws", - "message": "serviceRef is already deallocated" - }, - { - "test": "throws", - "message": "not enough arguments" - }, - { - "test": "throws", - "message": "argument must be DNSServiceRef, not undefined" - }, - { - "test": "throws", - "message": "to many arguments" - }, - { - "test": "throws", - "message": "call with non serviceRef object must throw" - } - ], - "DNSServiceResolve()": [ - { - "test": "doesNotThrow", - "message": "DNSServiceResolve() must not throw" - }, - { - "test": "strictEqual", - "message": "'initialized' must be true after inititalization" - }, - { - "test": "throws", - "message": "duplicate initialization must throw" - }, - { - "test": "throws", - "message": "not enough arguments" - }, - { - "test": "throws", - "message": "serviceRef must be DNSServiceRef object" - }, - { - "test": "throws", - "message": "'flags' must be a number, not a string" - }, - { - "test": "throws", - "message": "'interfaceIndex' must be a number, not null" - }, - { - "test": "throws", - "message": "'name' must be a string, not null" - }, - { - "test": "throws", - "message": "'regtype' must be a string, not null" - }, - { - "test": "throws", - "message": "'domain' must be a string, not null" - }, - { - "test": "throws", - "message": "'callback' must be a function, not null" - } - ], - "DNSServiceEnumerateDomains()": [ - { - "test": "doesNotThrow", - "message": "DNSServiceEnumerateDomains() must not throw" - }, - { - "test": "notEqual", - "message": "'fd' must not be -1 after inititalization" - }, - { - "test": "strictEqual", - "message": "'initialized' must be true after inititalization" - }, - { - "test": "doesNotThrow", - "message": "DNSServiceEnumerateDomains() must not throw" - }, - { - "test": "doesNotThrow", - "message": "DNSServiceEnumerateDomains() must not throw" - }, - { - "test": "throws", - "message": "dupliate inititalization of serviceRef must throw" - }, - { - "test": "throws", - "message": "'flags' must be a number, not a string" - }, - { - "test": "throws", - "message": "'flags' must be kDNSServiceFlagsBrowseDomains or kDNSServiceFlagsRegistrationDomains" - }, - { - "test": "throws", - "message": "'interfaceIndex' must be number, not a string" - }, - { - "test": "throws", - "message": "'callback' must be function, not a string" - }, - { - "test": "throws", - "message": "'callback' must be function, not null" - }, - { - "test": "throws", - "message": "not enough arguments" - }, - { - "test": "throws", - "message": "serviceRef must be a DNSServiceRef object" - } - ], - "DNSServiceGetAddrInfo": [ - { - "test": "doesNotThrow", - "message": "DNSServiceGetAddrInfo() must not throw" - } - ], - "TXTRecordRef": [ - { - "test": "strictEqual", - "message": "length must be 8 bytes after adding 'foo=bar'" - }, - { - "test": "strictEqual", - "message": "length must be 22 bytes after adding 'foobar=foobar'" - }, - { - "test": "strictEqual", - "message": "length must be 33 bytes after adding 'buffer=raw'" - }, - { - "test": "throws", - "message": "TXTRecordCreate() must throw when called without arguments" - }, - { - "test": "throws", - "message": "TXTRecordCreate() must throw when called with a string" - }, - { - "test": "throws", - "message": "duplicate call to TXTRecordCreate() must throw" - }, - { - "test": "throws", - "message": "txtRecord must be a TXTRecordRef object" - }, - { - "test": "throws", - "message": "txtRecord must be a TXTRecordRef object" - }, - { - "test": "doesNotThrow", - "message": "TXTRecordCreate() with undefined buffer must succeed" - }, - { - "test": "throws", - "message": "illegal buffer argument must throw" - }, - { - "test": "throws", - "message": "illegal buffer argument must throw" - }, - { - "test": "throws", - "message": "illegal argument must throw" - }, - { - "test": "throws", - "message": "illegal argument must throw" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called without arguments" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called with non TXTRecordRef object" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called with non TXTRecordRef object" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called with non TXTRecordRef object" - }, - { - "test": "doesNotThrow", - "message": "TXTRecordSetValue() must not throw when called with null value" - }, - { - "test": "doesNotThrow", - "message": "TXTRecordSetValue() must not throw when called with undefined value" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called with non string key" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called with strange value" - }, - { - "test": "throws", - "message": "TXTRecordSetValue() must throw when called with strange value" - }, - { - "test": "throws", - "message": "not enough arguments must throw" - }, - { - "test": "throws", - "message": "illegal arguments must throw" - }, - { - "test": "throws", - "message": "illegal arguments must throw" - }, - { - "test": "doesNotThrow", - "message": "deallocating a txtRecord must not throw" - }, - { - "test": "throws", - "message": "TXTRecordDeallocate() must throw when called without arguments" - }, - { - "test": "throws", - "message": "TXTRecordDeallocate() must throw when called with more than one argument" - }, - { - "test": "throws", - "message": "txtRecordBufferToObject() must throw when called with no arguments" - }, - { - "test": "throws", - "message": "txtRecordBufferToObject() must throw when called with a non-object" - }, - { - "test": "throws", - "message": "txtRecordBufferToObject() must throw when called with strange objects" - } - ], - "buildException()": [ - { - "test": "strictEqual", - "message": "buildException(kDNSServiceErr_NoError) must return undefined" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_Unknwon) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NoSuchName) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NoMemory) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException() must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_BadReference) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_BadState) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_BadFlags) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_Unsupported) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NotInitialized) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_AlreadyRegistered) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NameConflict) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_Invalid) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_Firewall) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_Incompatible) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_BadInterfaceIndex) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_Refused) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NoSuchRecord) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NoAuth) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NoSuchKey) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_NATTraversal) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_DoubleNAT) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "ok", - "message": "buildException(kDNSServiceErr_BadTime) must return an Error object" - }, - { - "test": "strictEqual" - }, - { - "test": "throws", - "message": "not enough arguments" - }, - { - "test": "throws", - "message": "argument must be a string" - } - ], - "exportConstants()": [ - { - "test": "ok" - }, - { - "test": "throws" - }, - { - "test": "throws" - } - ] - }, - "test_functional": { - "simple browsing": [ - { - "test": "strictEqual", - "message": "'flags' must be a number" - }, - { - "test": "ok", - "message": "'flags' must have kDNSServiceFlagsAdd set" - }, - { - "test": "strictEqual", - "message": "'fullname' must be a string" - }, - { - "test": "strictEqual", - "message": "'host' must be a string" - }, - { - "test": "strictEqual", - "message": "'port' must be a number" - }, - { - "test": "strictEqual", - "message": "'port' must match the advertisement" - }, - { - "test": "ok", - "message": "'service' must have a address property" - }, - { - "test": "ok", - "message": "'addresses' must be an array" - }, - { - "test": "ok", - "message": "addresses must not be empty" - }, - { - "test": "strictEqual", - "message": "'interfaceIndex' must be a number" - }, - { - "test": "strictEqual", - "message": "'name' must be a string" - }, - { - "test": "ok", - "message": "'type' must be a service type object" - }, - { - "test": "strictEqual", - "message": "type must match the target type" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must be a string" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must match 'local.'" - }, - { - "test": "strictEqual", - "message": "must have a networkInterface" - }, - { - "test": "ok", - "message": "must have context" - }, - { - "test": "strictEqual", - "message": "property must match input" - }, - { - "test": "strictEqual", - "message": "'flags' must be a number" - }, - { - "test": "strictEqual", - "message": "'interfaceIndex' must be a number" - }, - { - "test": "strictEqual", - "message": "'name' must be a string" - }, - { - "test": "ok", - "message": "'type' must be ServiceType object" - }, - { - "test": "strictEqual", - "message": "'type' must match target type" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must be a string" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must match 'local.'" - }, - { - "test": "strictEqual", - "message": "'fullname' must be a string" - }, - { - "test": "strictEqual", - "message": "'host' must be a string" - }, - { - "test": "strictEqual", - "message": "'port' must be a number" - }, - { - "test": "strictEqual", - "message": "'port' must match" - }, - { - "test": "ok", - "message": "'service' must have a addresses property" - }, - { - "test": "ok", - "message": "'addresses' must be a string" - }, - { - "test": "ok", - "message": "'addresses' must not be empty" - }, - { - "test": "ok", - "message": "'service' must have a rawTxtRecord property" - }, - { - "test": "ok", - "message": "'rawTxtRecord' must be truthy" - }, - { - "test": "ok", - "message": "'txtRecord' must be truthy" - }, - { - "test": "strictEqual", - "message": "must have a networkInterface" - }, - { - "test": "strictEqual", - "message": "property type in txtRecord must match" - }, - { - "test": "strictEqual", - "message": "property chunky in txtRecord must match" - }, - { - "test": "strictEqual", - "message": "property strips in txtRecord must match" - }, - { - "test": "strictEqual", - "message": "property buffer in txtRecord must match" - }, - { - "test": "ok", - "message": "must have context" - }, - { - "test": "strictEqual", - "message": "property must match input" - }, - { - "test": "strictEqual", - "message": "'flags' must be a number" - }, - { - "test": "strictEqual", - "message": "'interfaceIndex' must be a number" - }, - { - "test": "strictEqual", - "message": "'name' must be a string" - }, - { - "test": "ok", - "message": "'type' must be a service type object" - }, - { - "test": "strictEqual", - "message": "type must match the target type" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must be a string" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must match 'local.'" - }, - { - "test": "strictEqual", - "message": "must have a networkInterface" - }, - { - "test": "ok", - "message": "must have context" - }, - { - "test": "strictEqual", - "message": "property must match input" - }, - { - "test": "strictEqual", - "message": "'flags' must be a number" - }, - { - "test": "strictEqual", - "message": "'interfaceIndex' must be a number" - }, - { - "test": "strictEqual", - "message": "'name' must be a string" - }, - { - "test": "ok", - "message": "'type' must be a ServiceType object" - }, - { - "test": "strictEqual", - "message": "'type' must match target aervice type" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must be a string" - }, - { - "test": "strictEqual", - "message": "'replyDomain' must match 'local.'" - }, - { - "test": "strictEqual", - "message": "must have a networkInterface" - }, - { - "test": "ok", - "message": "must have context" - }, - { - "test": "strictEqual", - "message": "property must match input" - } - ], - "create ads": [ - { - "test": "ok", - "message": "service must have a flags property" - }, - { - "test": "strictEqual", - "message": "'flags' must be a number" - }, - { - "test": "ok", - "message": "'type' must be a ServiceType object" - }, - { - "test": "strictEqual", - "message": "'type' must be as advertised" - }, - { - "test": "ok", - "message": "service must have a flags property" - }, - { - "test": "strictEqual", - "message": "'flags' must be a number" - }, - { - "test": "ok", - "message": "'type' must be a ServiceType object" - }, - { - "test": "strictEqual", - "message": "'type' must be as advertised" - } - ], - "update ad record": [ - { - "test": "ok", - "message": "'service' must have a rawTxtRecord property" - }, - { - "test": "ok", - "message": "'rawTxtRecord' must be truthy" - }, - { - "test": "ok", - "message": "'txtRecord' must be truthy" - }, - { - "test": "strictEqual", - "message": "'txtRecord' doesn't match" - }, - { - "test": "ok", - "message": "'service' must have a rawTxtRecord property" - }, - { - "test": "ok", - "message": "'rawTxtRecord' must be truthy" - }, - { - "test": "ok", - "message": "'txtRecord' must be truthy" - }, - { - "test": "strictEqual", - "message": "'txtRecord' doesn't match" - } - ], - "browseThemAll()": [], - "resolver sequence": [ - { - "test": "ok", - "message": "service must not have a 'host' property" - }, - { - "test": "ok", - "message": "service must not have a 'port' property" - }, - { - "test": "ok", - "message": "service must not have a 'fullname' property" - }, - { - "test": "ok", - "message": "service must not have an 'addresses' property" - }, - { - "test": "ok", - "message": "service must have a 'host' property" - }, - { - "test": "ok", - "message": "service must have a 'port' property" - }, - { - "test": "ok", - "message": "service must have a 'fullname' property" - }, - { - "test": "ok", - "message": "service must not have an 'addresses' property" - }, - { - "test": "ok", - "message": "service must have a 'host' property" - }, - { - "test": "ok", - "message": "service must have a 'port' property" - }, - { - "test": "ok", - "message": "service must have a 'fullname' property" - }, - { - "test": "ok", - "message": "service must have an 'addresses' property" - }, - { - "test": "ok", - "message": "service must have a 'host' property" - }, - { - "test": "ok", - "message": "service must have a 'port' property" - }, - { - "test": "ok", - "message": "service must have a 'fullname' property" - }, - { - "test": "ok", - "message": "service must have an 'addresses' property" - } - ], - "local advertisement invisible on external interfaces": [ - { - "test": "strictEqual", - "message": "service must have the loopback interface index" - }, - { - "test": "strictEqual", - "message": "service must have the loopback interface name" - }, - { - "test": "strictEqual", - "message": "service must have the loopback interface index" - }, - { - "test": "strictEqual", - "message": "service must have the loopback interface name" - }, - { - "test": "strictEqual", - "message": "browser on external interface must not receive events" - } - ] - }, - "test_mdns_service": { - "MDNSService": { - "DNS errors should propagate": [ - { - "test": "equal" - } - ] - } - }, - "test_network_interface": { - "if_nametoindex <-> if_indextoname": [ - { - "test": "ok" - }, - { - "test": "strictEqual" - }, - { - "test": "ok" - }, - { - "test": "strictEqual" - } - ], - "interfaceIndex": [ - { - "test": "strictEqual" - }, - { - "test": "strictEqual" - }, - { - "test": "strictEqual" - }, - { - "test": "strictEqual" - }, - { - "test": "ok" - }, - { - "test": "ok" - }, - { - "test": "strictEqual" - } - ] - }, - "test_odd_ends": { - "DNSServiceEnumerateDomains": [ - { - "test": "strictEqual", - "message": "error must be NoError" - }, - { - "test": "strictEqual", - "message": "'flags' must be of type number" - }, - { - "test": "strictEqual", - "message": "'iface' must be of type number" - } - ] - }, - "test_service_type": { - "protocol helpers": [ - { - "test": "strictEqual", - "message": "comparing simple udp service type" - }, - { - "test": "strictEqual", - "message": "comparing tcp service type with subtype" - }, - { - "test": "strictEqual", - "message": "comparing tcp service types with two subtypes" - } - ], - "makeServiceType()": [ - { - "test": "strictEqual", - "message": "construct from string form" - }, - { - "test": "strictEqual", - "message": "construct from tokens" - }, - { - "test": "strictEqual", - "message": "construct from tokens with underscores" - }, - { - "test": "strictEqual", - "message": "construct from array" - }, - { - "test": "strictEqual", - "message": "construct with protocol helper" - }, - { - "test": "strictEqual", - "message": "construct from object (json)" - } - ], - "json round-trip": [ - { - "test": "strictEqual", - "message": "construct from result of JSON.parse(JSON.stringify(...))" - } - ], - "ServiceType() constructor": [ - { - "test": "strictEqual", - "message": "construct from tokens" - }, - { - "test": "strictEqual", - "message": "construct from array" - }, - { - "test": "strictEqual", - "message": "construct from object" - } - ], - "illegal arguments": [ - { - "test": "throws", - "message": "service type to long" - }, - { - "test": "throws", - "message": "illegal characters in primary type" - }, - { - "test": "throws", - "message": "subtype to long" - }, - { - "test": "throws", - "message": "illegal characters in subtype" - }, - { - "test": "throws", - "message": "illegal chars in subtype" - }, - { - "test": "throws", - "message": "type token already present" - }, - { - "test": "throws", - "message": "missing properties" - }, - { - "test": "throws", - "message": "illegal protocol" - }, - { - "test": "throws", - "message": "attempt to construct from number" - }, - { - "test": "throws", - "message": "aatempt to construct with an empty string" - } - ] - } -} \ No newline at end of file diff --git a/lib/jdiscovery/mdns/package.json b/lib/jdiscovery/mdns/package.json deleted file mode 100644 index b1ac8a64..00000000 --- a/lib/jdiscovery/mdns/package.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "mdns", - "version": "2.4.0", - "description": "multicast DNS service discovery", - "main": "./lib/mdns.js", - "scripts": { - "test": "node utils/testrun" - }, - "keywords": [ - "zeroconf", - "bonjour", - "dns_sd", - "mDNSResponder" - ], - "devDependencies": { - "ejs": "*", - "less": "*", - "mkdirp": "*", - "nopt": "*", - "slide": "*", - "glob": "*", - "ncp": "*", - "minimatch": "*", - "proxyquire": "^1.7.3" - }, - "repository": { - "type": "git", - "url": "http://github.com/agnat/node_mdns.git" - }, - "homepage": "http://agnat.github.com/node_mdns", - "bugs": { - "url": "http://github.com/agnat/node_mdns/issues" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://github.com/agnat/node_mdns/raw/master/LICENSE" - } - ], - "author": { - "name": "David Siegel", - "email": "agnat@me.com", - "github": "agnat" - }, - "contributors": [ - { - "name": "Orlando Vazquez", - "email": "ovazquez@gmail.com", - "url": "http://or.lan.do/", - "github": "orlandov" - }, - { - "name": "Ryan Dahl", - "email": "ry at tiny clouds dot org", - "url": "http://four.livejournal.com/", - "github": "ry" - }, - { - "name": "Dominic Tarr", - "url": "http://twitter.com/dominictarr", - "github": "dominictarr" - }, - { - "name": "Emil Stenqvist", - "github": "emilisto" - }, - { - "name": "Toby Ealden", - "github": "TobyEalden" - }, - { - "name": "Cong Liu", - "github": "ghostoy" - }, - { - "name": "Tian Zhang", - "github": "KhaosT" - } - ], - "dependencies": { - "bindings": "~1.2.1", - "nan": "^2.10.0" - }, - "gypfile": true -} diff --git a/lib/jdiscovery/mdns/src/demangle.cpp b/lib/jdiscovery/mdns/src/demangle.cpp deleted file mode 100644 index 8704832e..00000000 --- a/lib/jdiscovery/mdns/src/demangle.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#ifdef __GNUC__ -# include -# include -#endif -using namespace v8; - -namespace { - -Handle -demangle(Arguments const& info) { - Nan::HandleScope scope; - String::Utf8Value str(info[0]->ToString()); -#ifdef __GNUC__ - int status; - char * ret = abi::__cxa_demangle(*str, NULL, NULL, & status); - Local demangled = Nan::New(ret); - ::free(ret); -#endif - info.GetReturnValue().Set(demangled); -} - -} // end of anaonymous namespace - -extern "C" -void -init(Handle target) { - Nan::Set(target, Nan::New("demangle").ToLocalChecked(), - Nan::GetFunction(Nan::New(demangle))); -} diff --git a/lib/jdiscovery/mdns/src/dns_sd.cpp b/lib/jdiscovery/mdns/src/dns_sd.cpp deleted file mode 100644 index eaa8fdbe..00000000 --- a/lib/jdiscovery/mdns/src/dns_sd.cpp +++ /dev/null @@ -1,319 +0,0 @@ -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" -#include "txt_record_ref.hpp" -#ifdef NODE_MDNS_USE_SOCKET_WATCHER -# include "socket_watcher.hpp" -#endif - -using namespace v8; -using namespace node; - -namespace node_mdns { - -// === dns_sd =========================================== -NAN_METHOD(DNSServiceRegister); -NAN_METHOD(DNSServiceUpdateRecord); -NAN_METHOD(DNSServiceRefSockFD); -NAN_METHOD(DNSServiceProcessResult); -NAN_METHOD(DNSServiceBrowse); -NAN_METHOD(DNSServiceRefDeallocate); -NAN_METHOD(DNSServiceResolve); -NAN_METHOD(DNSServiceEnumerateDomains); -#ifdef HAVE_DNSSERVICEGETADDRINFO -NAN_METHOD(DNSServiceGetAddrInfo); -#endif -NAN_METHOD(TXTRecordCreate); -NAN_METHOD(TXTRecordDeallocate); -//NAN_METHOD(TXTRecordGetCount); -NAN_METHOD(TXTRecordSetValue); -NAN_METHOD(TXTRecordGetLength); - -// === posix ============================================ -#ifdef NODE_MDNS_HAVE_INTERFACE_NAME_CONVERSION -NAN_METHOD(if_nametoindex); -NAN_METHOD(if_indextoname); -#endif - -// === additions ======================================== -NAN_METHOD(txtRecordBufferToObject); -NAN_METHOD(exportConstants); -NAN_METHOD(buildException); - -// === locals =========================================== - -void defineFunction(Local target, const char * name, Nan::FunctionCallback f); -void addConstants(Local target); - -void -init(Local target) { - Nan::HandleScope scope; - - ServiceRef::Initialize( target ); - TxtRecordRef::Initialize( target ); -#ifdef NODE_MDNS_USE_SOCKET_WATCHER - SocketWatcher::Initialize( target ); -#endif - - defineFunction(target, "DNSServiceRegister", DNSServiceRegister); - defineFunction(target, "DNSServiceUpdateRecord", DNSServiceUpdateRecord); - defineFunction(target, "DNSServiceRefSockFD", DNSServiceRefSockFD); - defineFunction(target, "DNSServiceProcessResult", DNSServiceProcessResult); - defineFunction(target, "DNSServiceBrowse", DNSServiceBrowse); - defineFunction(target, "DNSServiceRefDeallocate", DNSServiceRefDeallocate); - defineFunction(target, "DNSServiceResolve", DNSServiceResolve); - defineFunction(target, "DNSServiceEnumerateDomains", - DNSServiceEnumerateDomains); -#ifdef HAVE_DNSSERVICEGETADDRINFO - defineFunction(target, "DNSServiceGetAddrInfo", DNSServiceGetAddrInfo); -#endif - defineFunction(target, "TXTRecordCreate", TXTRecordCreate); - defineFunction(target, "TXTRecordDeallocate", TXTRecordDeallocate); - //defineFunction(target, "TXTRecordGetCount", TXTRecordGetCount); - defineFunction(target, "TXTRecordSetValue", TXTRecordSetValue); - defineFunction(target, "TXTRecordGetLength", TXTRecordGetLength); - -#ifdef NODE_MDNS_HAVE_INTERFACE_NAME_CONVERSION - defineFunction(target, "if_nametoindex", if_nametoindex); - defineFunction(target, "if_indextoname", if_indextoname); -#endif - - defineFunction(target, "txtRecordBufferToObject", txtRecordBufferToObject); - defineFunction(target, "buildException", buildException); - defineFunction(target, "exportConstants", exportConstants); - - addConstants(target); -} - -inline -void -defineFunction(Local target, const char * name, Nan::FunctionCallback f) { - Nan::Set(target, Nan::New(name).ToLocalChecked(), - Nan::GetFunction(Nan::New(f)).ToLocalChecked()); -} - -NAN_METHOD(buildException) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsInt32()) { - return throwTypeError("argument 1 must be an integer " - "(DNSServiceErrorType)"); - } - - DNSServiceErrorType error = Nan::To(info[0]).FromJust(); - info.GetReturnValue().Set(buildException(error)); -} - -void -addConstants(Local target) { - // DNS Classes - NODE_DEFINE_CONSTANT(target, kDNSServiceClass_IN); - - // DNS Error Codes - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoError); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Unknown); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoSuchName); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoMemory); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadParam); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadReference); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadState); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadFlags); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Unsupported); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NotInitialized); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_AlreadyRegistered); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NameConflict); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Invalid); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Firewall); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Incompatible); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadInterfaceIndex); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Refused); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoSuchRecord); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoAuth); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoSuchKey); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NATTraversal); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_DoubleNAT); - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadTime); -#ifdef kDNSServiceErr_BadSig - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadSig); -#endif -#ifdef kDNSServiceErr_BadKey - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_BadKey); -#endif -#ifdef kDNSServiceErr_Transient - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_Transient); -#endif -#ifdef kDNSServiceErr_ServiceNotRunning - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_ServiceNotRunning); -#endif -#ifdef kDNSServiceErr_NATPortMappingUnsupported - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NATPortMappingUnsupported); -#endif -#ifdef kDNSServiceErr_NATPortMappingDisabled - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NATPortMappingDisabled); -#endif -#ifdef kDNSServiceErr_NoRouter - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_NoRouter); -#endif -#ifdef kDNSServiceErr_PollingMode - NODE_DEFINE_CONSTANT(target, kDNSServiceErr_PollingMode); -#endif - - // Interface Index -#ifdef kDNSServiceInterfaceIndexAny - NODE_DEFINE_CONSTANT(target, kDNSServiceInterfaceIndexAny); -#endif -#ifdef kDNSServiceInterfaceIndexLocalOnly - NODE_DEFINE_CONSTANT(target, kDNSServiceInterfaceIndexLocalOnly); -#endif -#ifdef kDNSServiceInterfaceIndexP2P - NODE_DEFINE_CONSTANT(target, kDNSServiceInterfaceIndexP2P); -#endif -#ifdef kDNSServiceInterfaceIndexUnicast - NODE_DEFINE_CONSTANT(target, kDNSServiceInterfaceIndexUnicast); -#endif - - // DNS Service Types - NODE_DEFINE_CONSTANT(target, kDNSServiceType_A); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NS); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MD); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MF); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_CNAME); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_SOA); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MB); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MG); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MR); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NULL); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_WKS); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_PTR); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_HINFO); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MINFO); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MX); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_TXT); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_RP); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_AFSDB); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_X25); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_ISDN); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_RT); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NSAP); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NSAP_PTR); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_SIG); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_KEY); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_PX); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_GPOS); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_AAAA); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_LOC); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NXT); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_EID); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NIMLOC); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_SRV); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_ATMA); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NAPTR); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_KX); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_CERT); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_A6); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_DNAME); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_SINK); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_OPT); -#ifdef kDNSServiceType_APL - NODE_DEFINE_CONSTANT(target, kDNSServiceType_APL); -#endif -#ifdef kDNSServiceType_DS - NODE_DEFINE_CONSTANT(target, kDNSServiceType_DS); -#endif -#ifdef kDNSServiceType_SSHFP - NODE_DEFINE_CONSTANT(target, kDNSServiceType_SSHFP); -#endif -#ifdef kDNSServiceType_IPSECKEY - NODE_DEFINE_CONSTANT(target, kDNSServiceType_IPSECKEY); -#endif -#ifdef kDNSServiceType_RRSIG - NODE_DEFINE_CONSTANT(target, kDNSServiceType_RRSIG); -#endif -#ifdef kDNSServiceType_NSEC - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NSEC); -#endif -#ifdef kDNSServiceType_DNSKEY - NODE_DEFINE_CONSTANT(target, kDNSServiceType_DNSKEY); -#endif -#ifdef kDNSServiceType_DHCID - NODE_DEFINE_CONSTANT(target, kDNSServiceType_DHCID); -#endif -#ifdef kDNSServiceType_NSEC3 - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NSEC3); -#endif -#ifdef kDNSServiceType_NSEC3PARAM - NODE_DEFINE_CONSTANT(target, kDNSServiceType_NSEC3PARAM); -#endif -#ifdef kDNSServiceType_HIP - NODE_DEFINE_CONSTANT(target, kDNSServiceType_HIP); -#endif -#ifdef kDNSServiceType_SPF - NODE_DEFINE_CONSTANT(target, kDNSServiceType_SPF); -#endif -#ifdef kDNSServiceType_UINFO - NODE_DEFINE_CONSTANT(target, kDNSServiceType_UINFO); -#endif -#ifdef kDNSServiceType_UID - NODE_DEFINE_CONSTANT(target, kDNSServiceType_UID); -#endif -#ifdef kDNSServiceType_GID - NODE_DEFINE_CONSTANT(target, kDNSServiceType_GID); -#endif -#ifdef kDNSServiceType_UNSPEC - NODE_DEFINE_CONSTANT(target, kDNSServiceType_UNSPEC); -#endif - NODE_DEFINE_CONSTANT(target, kDNSServiceType_TKEY); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_TSIG); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_IXFR); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_AXFR); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MAILB); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_MAILA); - NODE_DEFINE_CONSTANT(target, kDNSServiceType_ANY); - - // General Flags - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsMoreComing); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsAdd); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsDefault); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsNoAutoRename); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsShared); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsUnique); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsBrowseDomains); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsRegistrationDomains); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsLongLivedQuery); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsAllowRemoteQuery); - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsForceMulticast); -#ifdef kDNSServiceFlagsForce - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsForce); -#endif -#ifdef kDNSServiceFlagsReturnIntermediates - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsReturnIntermediates); -#endif -#ifdef kDNSServiceFlagsNonBrowsable - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsNonBrowsable); -#endif -#ifdef kDNSServiceFlagsShareConnection - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsShareConnection); -#endif -#ifdef kDNSServiceFlagsSuppressUnusable - NODE_DEFINE_CONSTANT(target, kDNSServiceFlagsSuppressUnusable); -#endif -} - -NAN_METHOD(exportConstants) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject()) { - return throwTypeError("argument 1 must be an object."); - } - - addConstants(info[0]->ToObject()); -} - -} // end of namespace node_mdns - -NODE_MODULE(dns_sd_bindings,node_mdns::init); diff --git a/lib/jdiscovery/mdns/src/dns_service_browse.cpp b/lib/jdiscovery/mdns/src/dns_service_browse.cpp deleted file mode 100644 index 04967abc..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_browse.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "mdns.hpp" -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -static -void -DNSSD_API -OnServiceChanged(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char * serviceName, const char * serviceType, - const char * replyDomain, void * context) -{ - Nan::HandleScope scope; - ServiceRef * serviceRef = static_cast(context); - Local callback = serviceRef->GetCallback(); - Local this_ = serviceRef->GetThis(); - - const size_t argc(8); - Local info[argc]; - info[0] = serviceRef->handle(); - info[1] = Nan::New(flags); - info[2] = Nan::New(interfaceIndex); - info[3] = Nan::New(errorCode); - info[4] = stringOrUndefined(serviceName); - info[5] = stringOrUndefined(serviceType); - info[6] = stringOrUndefined(replyDomain); - if (serviceRef->GetContext().IsEmpty()) { - info[7] = Nan::Undefined(); - } else { - info[7] = serviceRef->GetContext(); - } - Nan::MakeCallback(this_, callback, argc, info); -} - -NAN_METHOD(DNSServiceBrowse) { - if (argumentCountMismatch(info, 7)) { - return throwArgumentCountMismatchException(info, 7); - } - - if ( ! ServiceRef::HasInstance(info[0])) { - return throwTypeError("argument 1 must be a DNSServiceRef (sdRef)"); - } - ServiceRef * serviceRef = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if (serviceRef->IsInitialized()) { - return throwError("DNSServiceRef is already initialized"); - } - - if ( ! info[1]->IsInt32()) { - return throwError("argument 2 must be an integer (DNSServiceFlags)"); - } - DNSServiceFlags flags = info[1]->ToInteger()->Int32Value(); - - if ( ! info[2]->IsUint32() && ! info[2]->IsInt32()) { - return throwTypeError("argument 3 must be an integer (interfaceIndex)"); - } - uint32_t interfaceIndex = info[2]->ToInteger()->Uint32Value(); - - if ( ! info[3]->IsString()) { - return throwTypeError("argument 4 must be a string (service type)"); - } - String::Utf8Value serviceType(info[3]->ToString()); - - bool has_domain = false; - if ( ! info[4]->IsNull() && ! info[4]->IsUndefined()) { - if ( ! info[4]->IsString()) { - return throwTypeError("argument 5 must be a string (domain)"); - } - has_domain = true; - } - String::Utf8Value domain(info[4]); - - if ( ! info[5]->IsFunction()) { - return throwTypeError("argument 6 must be a function (callBack)"); - } - serviceRef->SetCallback(Local::Cast(info[5])); - - if ( ! info[6]->IsNull() && ! info[6]->IsUndefined()) { - serviceRef->SetContext(info[6]); - } - - DNSServiceErrorType error = DNSServiceBrowse( & serviceRef->GetServiceRef(), - flags, interfaceIndex, *serviceType, has_domain ? *domain : NULL, - OnServiceChanged, serviceRef); - - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } - - if ( ! serviceRef->SetSocketFlags()) { - return throwError("Failed to set socket flags (O_NONBLOCK, FD_CLOEXEC)"); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_enumerate_domains.cpp b/lib/jdiscovery/mdns/src/dns_service_enumerate_domains.cpp deleted file mode 100644 index fa1ce542..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_enumerate_domains.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "mdns.hpp" - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -void -DNSSD_API -OnEnumeration(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, - DNSServiceErrorType errorCode, const char * replyDomain, void * context) -{ - Nan::HandleScope scope; - ServiceRef * serviceRef = static_cast(context); - Local callback = serviceRef->GetCallback(); - Local this_ = serviceRef->GetThis(); - - const size_t argc(6); - Local info[argc]; - info[0] = serviceRef->handle(); - info[1] = Nan::New(flags); - info[2] = Nan::New(interfaceIndex); - info[3] = Nan::New(errorCode); - info[4] = stringOrUndefined(replyDomain); - info[5] = serviceRef->GetContext(); - Nan::MakeCallback(this_, callback, argc, info); -} - -NAN_METHOD(DNSServiceEnumerateDomains) { - if (argumentCountMismatch(info, 5)) { - return throwArgumentCountMismatchException(info, 5); - } - - if ( ! ServiceRef::HasInstance(info[0])) { - return throwTypeError("argument 1 must be a DNSServiceRef (sdRef)"); - } - ServiceRef * serviceRef = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if (serviceRef->IsInitialized()) { - return throwError("DNSServiceRef is already initialized"); - } - - if ( ! info[1]->IsInt32()) { - return throwError("argument 2 must be an integer (DNSServiceFlags)"); - } - DNSServiceFlags flags = info[1]->ToInteger()->Int32Value(); - - if ( ! info[2]->IsUint32() && ! info[2]->IsInt32()) { - return throwTypeError("argument 3 must be an integer (interfaceIndex)"); - } - uint32_t interfaceIndex = info[2]->ToInteger()->Uint32Value(); - - if ( ! info[3]->IsFunction()) { - return throwTypeError("argument 4 must be a function (callBack)"); - } - serviceRef->SetCallback(Local::Cast(info[3])); - - serviceRef->SetContext(info[4]); - - DNSServiceErrorType error = DNSServiceEnumerateDomains( & serviceRef->GetServiceRef(), - flags, interfaceIndex, OnEnumeration, serviceRef); - - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } - if ( ! serviceRef->SetSocketFlags()) { - return throwError("Failed to set socket flags (O_NONBLOCK, FD_CLOEXEC)"); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_get_addr_info.cpp b/lib/jdiscovery/mdns/src/dns_service_get_addr_info.cpp deleted file mode 100644 index f711c400..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_get_addr_info.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "mdns.hpp" - -#ifndef WIN32 // XXX -#include -#include -#include // AF_INET and AF_INET6 on freebsd -#endif - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -#ifdef HAVE_DNSSERVICEGETADDRINFO - -void -DNSSD_API -OnAddressInfo(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char * hostname, const struct sockaddr * address, - uint32_t ttl, void * context) -{ - if ( ! context) return; - - Nan::HandleScope scope; - ServiceRef * serviceRef = static_cast(context); - Local callback = serviceRef->GetCallback(); - Local this_ = serviceRef->GetThis(); - - const size_t argc(8); - Local info[argc]; - info[0] = serviceRef->handle(); - info[1] = Nan::New(flags); - info[2] = Nan::New(interfaceIndex); - info[3] = Nan::New(errorCode); - info[4] = stringOrUndefined(hostname); - info[5] = Nan::New().ToLocalChecked(); - char ip[INET6_ADDRSTRLEN]; - struct sockaddr_in *a4; - struct sockaddr_in6 *a6; - switch (address->sa_family) { - case AF_INET6: - a6 = (struct sockaddr_in6*)(address); - inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); - info[5] = Nan::New(ip).ToLocalChecked(); - break; - case AF_INET: - a4 = (struct sockaddr_in*)(address); - inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); - info[5] = Nan::New(ip).ToLocalChecked(); - break; - default: - break; - } - - info[6] = Nan::New(ttl); - - if (serviceRef->GetContext().IsEmpty()) { - info[7] = Nan::Undefined(); - } else { - info[7] = serviceRef->GetContext(); - } - Nan::MakeCallback(this_, callback, argc, info); -} - -NAN_METHOD(DNSServiceGetAddrInfo) { - - if (argumentCountMismatch(info, 7)) { - return throwArgumentCountMismatchException(info, 7); - } - - if ( ! ServiceRef::HasInstance(info[0])) { - return throwTypeError("argument 1 must be a DNSServiceRef (sdRef)"); - } - ServiceRef * serviceRef = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if (serviceRef->IsInitialized()) { - return throwError("DNSServiceRef is already initialized"); - } - - if ( ! info[1]->IsInt32()) { - return throwError("argument 2 must be an integer (DNSServiceFlags)"); - } - DNSServiceFlags flags = info[1]->ToInteger()->Int32Value(); - - if ( ! info[2]->IsUint32() && ! info[2]->IsInt32()) { - return throwTypeError("argument 3 must be an integer (interfaceIndex)"); - } - uint32_t interfaceIndex = info[2]->ToInteger()->Uint32Value(); - - if ( ! info[3]->IsInt32()) { - return throwTypeError("argument 4 must be an integer (DNSServiceProtocol)"); - } - uint32_t protocol = info[3]->ToInteger()->Int32Value(); - - if ( ! info[4]->IsString()) { - return throwTypeError("argument 5 must be a string (hostname)"); - } - String::Utf8Value hostname(info[4]->ToString()); - - if ( ! info[5]->IsFunction()) { - return throwTypeError("argument 6 must be a function (callBack)"); - } - serviceRef->SetCallback(Local::Cast(info[5])); - - if ( ! info[6]->IsNull() && ! info[6]->IsUndefined()) { - serviceRef->SetContext(info[6]); - } - - DNSServiceErrorType error = DNSServiceGetAddrInfo( & serviceRef->GetServiceRef(), - flags, interfaceIndex, protocol, *hostname, OnAddressInfo, serviceRef); - - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } - if ( ! serviceRef->SetSocketFlags()) { - return throwError("Failed to set socket flags (O_NONBLOCK, FD_CLOEXEC)"); - } -} - -#endif // HAVE_DNSSERVICEGETADDRINFO - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_process_result.cpp b/lib/jdiscovery/mdns/src/dns_service_process_result.cpp deleted file mode 100644 index 0e751771..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_process_result.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(DNSServiceProcessResult) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject()) { - return throwTypeError("argument 1 must be a DNSServiceRef object"); - } - - ServiceRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - ref->SetThis(info.This()); - DNSServiceErrorType error = DNSServiceProcessResult(ref->GetServiceRef()); - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_ref.cpp b/lib/jdiscovery/mdns/src/dns_service_ref.cpp deleted file mode 100644 index 5f522706..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_ref.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "mdns.hpp" - -#include "dns_service_ref.hpp" -#include "mdns_utils.hpp" - -using namespace v8; - -namespace node_mdns { - -Nan::Persistent ServiceRef::constructor_template; - -ServiceRef::ServiceRef() : ref_(), callback_(), context_() {} - -ServiceRef::~ServiceRef() { - // First, dispose the serice ref. This cancels all asynchronous operations. - if (ref_) { - DNSServiceRefDeallocate(ref_); - } - // Then release the js objects. - if ( ! callback_.IsEmpty()) { - callback_.Reset(); - } - if ( ! context_.IsEmpty()) { - context_.Reset(); - } -} - -void -ServiceRef::Initialize(Local target) { - Local t = Nan::New(New); - constructor_template.Reset(t); - t->InstanceTemplate()->SetInternalFieldCount(1); - t->SetClassName(Nan::New("DNSServiceRef").ToLocalChecked()); - - Nan::SetAccessor(t->InstanceTemplate(), Nan::New("fd").ToLocalChecked(), fd_getter); - Nan::SetAccessor(t->InstanceTemplate(), Nan::New("initialized").ToLocalChecked(), initialized_getter); - Nan::Set(target, Nan::New("DNSServiceRef").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked()); -} - -NAN_METHOD(ServiceRef::New) { - if (argumentCountMismatch(info, 0)) { - return throwArgumentCountMismatchException(info, 0); - } - ServiceRef * o = new ServiceRef(); - o->Wrap(info.Holder()); - info.GetReturnValue().Set(info.This()); -} - -bool -ServiceRef::IsInitialized() const { return ref_ != NULL; } - -bool -ServiceRef::HasInstance(v8::Local value) { - if ( ! value->IsObject() ) return false; - v8::Local object = value->ToObject(); - return Nan::New(constructor_template)->HasInstance( object ); -} - -void -ServiceRef::SetCallback(v8::Local callback) { - if ( ! callback_.IsEmpty()) { - callback_.Reset(); - } - callback_.Reset(callback); -} - -v8::Local -ServiceRef::GetCallback() const { return Nan::New(callback_); } - -DNSServiceRef & -ServiceRef::GetServiceRef() { return ref_; } - -void -ServiceRef::SetServiceRef(DNSServiceRef ref) { ref_ = ref; } - -v8::Local -ServiceRef::GetContext() { return Nan::New(context_); } - -void -ServiceRef::SetContext(v8::Local context) { - if ( ! context_.IsEmpty()) { - context_.Reset(); - } - context_.Reset(context); -} - -v8::Local -ServiceRef::GetThis() { return this_; } - -void -ServiceRef::SetThis(v8::Local This) { this_ = This; } - -bool -ServiceRef::SetSocketFlags() { - return true; -#if 0 // XXX I think IOWatcher does the right thing. TODO: check! - int fd = DNSServiceRefSockFD(ref_); - if (fd == -1) return false; - return fcntl(fd, F_SETFD, FD_CLOEXEC) != -1 && - fcntl(fd, F_SETFL, O_NONBLOCK) != -1; -#endif -} - -NAN_PROPERTY_GETTER(ServiceRef::fd_getter) { - ServiceRef * service_ref = Nan::ObjectWrap::Unwrap(info.This()); - int fd = -1; - if (service_ref->ref_) { - fd = DNSServiceRefSockFD(service_ref->ref_); - if (fd == -1) { - return Nan::ThrowError("DNSServiceRefSockFD() failed"); - } - } - Local v = Nan::New(fd); - info.GetReturnValue().Set(v); -} - -NAN_PROPERTY_GETTER(ServiceRef::initialized_getter) { - ServiceRef * service_ref = Nan::ObjectWrap::Unwrap(info.This()); - info.GetReturnValue().Set(Nan::New(service_ref->IsInitialized())); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_ref.hpp b/lib/jdiscovery/mdns/src/dns_service_ref.hpp deleted file mode 100644 index 36b30dee..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_ref.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef NODE_MDNS_SERVICE_REF_INCLUDED -#define NODE_MDNS_SERVICE_REF_INCLUDED - -#include - -namespace node_mdns { - -class ServiceRef : public Nan::ObjectWrap { - public: - ServiceRef(); - ~ServiceRef(); - - static void Initialize(v8::Local target); - static NAN_METHOD(New); - - bool IsInitialized() const; - - static bool HasInstance(v8::Local value); - - void SetCallback(v8::Local callback); - v8::Local GetCallback() const; - - - DNSServiceRef & GetServiceRef(); - void SetServiceRef(DNSServiceRef ref); - - v8::Local GetContext(); - void SetContext(v8::Local context); - - v8::Local GetThis(); - void SetThis(v8::Local This); - - bool SetSocketFlags(); - - private: - static NAN_PROPERTY_GETTER(fd_getter); - static NAN_PROPERTY_GETTER(initialized_getter); - - DNSServiceRef ref_; - Nan::Persistent callback_; - v8::Local this_; - Nan::Persistent context_; - - static Nan::Persistent constructor_template; -}; - -} // end of namespace node_mdns -#endif // NODE_MDNS_SERVICE_REF_INCLUDED diff --git a/lib/jdiscovery/mdns/src/dns_service_ref_deallocate.cpp b/lib/jdiscovery/mdns/src/dns_service_ref_deallocate.cpp deleted file mode 100644 index 31f74e26..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_ref_deallocate.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(DNSServiceRefDeallocate) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject() || ! ServiceRef::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a DNSServiceRef object"); - } - - ServiceRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if ( ! ref->IsInitialized()) { - return throwError("DNSServiceRef is not initialized"); - } - DNSServiceRefDeallocate( ref->GetServiceRef()); - ref->SetServiceRef(NULL); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_ref_sock_fd.cpp b/lib/jdiscovery/mdns/src/dns_service_ref_sock_fd.cpp deleted file mode 100644 index 307aeb90..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_ref_sock_fd.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(DNSServiceRefSockFD) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject() || ! ServiceRef::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a DNSServiceRef object"); - } - - ServiceRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if ( ! ref->IsInitialized()) { - return throwError("DNSServiceRef is not initialized"); - } - int fd = DNSServiceRefSockFD( ref->GetServiceRef()); - if (fd == -1) { - return throwError("failed to get socket file descriptor"); - } - info.GetReturnValue().Set( Nan::New( fd )); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_register.cpp b/lib/jdiscovery/mdns/src/dns_service_register.cpp deleted file mode 100644 index 5f2b253b..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_register.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "mdns.hpp" - -#include - -#ifndef WIN32 // XXX -#include -#endif - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -static -void -DNSSD_API -OnServiceRegistered(DNSServiceRef sdRef, DNSServiceFlags flags, - DNSServiceErrorType errorCode, const char * name, - const char * serviceType, const char * domain, void * context) -{ - if ( ! context) return; - - Nan::HandleScope scope; - ServiceRef * serviceRef = static_cast(context); - Local callback = serviceRef->GetCallback(); - Local this_ = serviceRef->GetThis(); - - if ( ! callback.IsEmpty() && ! this_.IsEmpty()) { - const size_t argc(7); - Local info[argc]; - info[0] = serviceRef->handle(); - info[1] = Nan::New(flags); - info[2] = Nan::New(errorCode); - info[3] = stringOrUndefined(name); - info[4] = stringOrUndefined(serviceType); - info[5] = stringOrUndefined(domain); - if (serviceRef->GetContext().IsEmpty()) { - info[6] = Nan::Undefined(); - } else { - info[6] = serviceRef->GetContext(); - } - Nan::MakeCallback(this_, callback, argc, info); - } -} - -NAN_METHOD(DNSServiceRegister) { - if (argumentCountMismatch(info, 11)) { - return throwArgumentCountMismatchException(info, 11); - } - - if ( ! ServiceRef::HasInstance(info[0])) { - return throwTypeError("argument 1 must be a DNSServiceRef (sdRef)"); - } - ServiceRef * serviceRef = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if (serviceRef->IsInitialized()) { - return throwError("DNSServiceRef is already initialized"); - } - - if ( ! info[1]->IsInt32()) { - return throwError("argument 2 must be an integer (DNSServiceFlags)"); - } - DNSServiceFlags flags = info[1]->ToInteger()->Int32Value(); - - if ( ! info[2]->IsUint32() && ! info[2]->IsInt32()) { - return throwTypeError("argument 3 must be an integer (interfaceIndex)"); - } - uint32_t interfaceIndex = info[2]->ToInteger()->Uint32Value(); - - bool has_name = false; - if ( ! info[3]->IsNull() && ! info[3]->IsUndefined()) { - if ( ! info[3]->IsString()) { - return throwTypeError("argument 4 must be a string (name)"); - } - has_name = true; - } - String::Utf8Value name(info[3]); - - if ( ! info[4]->IsString()) { - return throwTypeError("argument 5 must be a string (service type)"); - } - String::Utf8Value serviceType(info[4]->ToString()); - - bool has_domain = false; - if ( ! info[5]->IsNull() && ! info[5]->IsUndefined()) { - if ( ! info[5]->IsString()) { - return throwTypeError("argument 6 must be a string (domain)"); - } - has_domain = true; - } - String::Utf8Value domain(info[5]); - - bool has_host = false; - if ( ! info[6]->IsNull() && ! info[6]->IsUndefined()) { - if ( ! info[6]->IsString()) { - return throwTypeError("argument 7 must be a string (host)"); - } - has_host = true; - } - String::Utf8Value host(info[6]); - - if ( ! info[7]->IsInt32()) { - return throwTypeError("argument 8 must be an integer (port)"); - } - int raw_port = info[7]->ToInteger()->Int32Value(); - if (raw_port > std::numeric_limits::max() || raw_port < 0) { - return throwError("argument 8: port number is out of bounds."); - } - uint16_t port = static_cast(raw_port); - - uint16_t txtLen(0); - const void * txtRecord(NULL); - if ( ! info[8]->IsNull() && ! info[8]->IsUndefined()) { - if (Buffer::HasInstance(info[8])) { - Local bufferObject = info[8]->ToObject(); - txtRecord = Buffer::Data(bufferObject); - txtLen = Buffer::Length(bufferObject); - } else if (TxtRecordRef::HasInstance(info[8])) { - TxtRecordRef * ref = Nan::ObjectWrap::Unwrap(info[8]->ToObject()); - txtLen = TXTRecordGetLength( & ref->GetTxtRecordRef()); - txtRecord = TXTRecordGetBytesPtr( & ref->GetTxtRecordRef()); - } else { - return throwTypeError("argument 9 must be a buffer or a dns_sd.TXTRecordRef"); - } - } - - if ( ! info[9]->IsNull() && ! info[9]->IsUndefined()) { - if ( ! info[9]->IsFunction()) { - return throwTypeError("argument 10 must be a function (callBack)"); - } - serviceRef->SetCallback(Local::Cast(info[9])); - } - - if ( ! info[10]->IsNull() && ! info[10]->IsUndefined()) { - serviceRef->SetContext(info[10]); - } - - // eleven arguments ... srsly? - DNSServiceErrorType error = DNSServiceRegister( - & serviceRef->GetServiceRef(), - flags, - interfaceIndex, - has_name ? * name : NULL, - *serviceType, - has_domain ? * domain : NULL, - has_host ? * host : NULL, - htons(port), - txtLen, - txtRecord, - info[9]->IsFunction() ? OnServiceRegistered : NULL, - serviceRef); - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } - if ( ! serviceRef->SetSocketFlags()) { - return throwError("Failed to set socket flags (O_NONBLOCK, FD_CLOEXEC)"); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_resolve.cpp b/lib/jdiscovery/mdns/src/dns_service_resolve.cpp deleted file mode 100644 index 29e06ac9..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_resolve.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "mdns.hpp" - -#include - -#ifndef WIN32 // XXX -#include -#endif - -#include -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - - -using namespace v8; -using namespace node; - -namespace node_mdns { - -void -DNSSD_API -OnResolve(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char * fullname, const char * hosttarget, uint16_t port, - uint16_t txtLen, const unsigned char * txtRecord, void * context) -{ - - Nan::HandleScope scope; - ServiceRef * serviceRef = static_cast(context); - Local callback = serviceRef->GetCallback(); - Local this_ = serviceRef->GetThis(); - - const size_t argc(9); - Local info[argc]; - info[0] = serviceRef->handle(); - info[1] = Nan::New(flags); - info[2] = Nan::New(interfaceIndex); - info[3] = Nan::New(errorCode); - info[4] = stringOrUndefined(fullname); - info[5] = stringOrUndefined(hosttarget); - info[6] = Nan::New( ntohs(port) ); - Local buffer = Nan::NewBuffer(txtLen).ToLocalChecked(); - memcpy(Buffer::Data(buffer), txtRecord, txtLen); - info[7] = buffer; - if (serviceRef->GetContext().IsEmpty()) { - info[8] = Nan::Undefined(); - } else { - info[8] = serviceRef->GetContext(); - } - Nan::MakeCallback(this_, callback, argc, info); -} - -NAN_METHOD(DNSServiceResolve) { - - if (argumentCountMismatch(info, 8)) { - return throwArgumentCountMismatchException(info, 8); - } - - if ( ! ServiceRef::HasInstance(info[0])) { - return throwTypeError("argument 1 must be a DNSServiceRef (sdRef)"); - } - ServiceRef * serviceRef = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - if (serviceRef->IsInitialized()) { - return throwError("DNSServiceRef is already initialized"); - } - - if ( ! info[1]->IsInt32()) { - return throwError("argument 2 must be an integer (DNSServiceFlags)"); - } - DNSServiceFlags flags = info[1]->ToInteger()->Int32Value(); - - if ( ! info[2]->IsUint32() && ! info[2]->IsInt32()) { - return throwTypeError("argument 3 must be an integer (interfaceIndex)"); - } - uint32_t interfaceIndex = info[2]->ToInteger()->Uint32Value(); - - if ( ! info[3]->IsString()) { - return throwTypeError("argument 4 must be a string (name)"); - } - String::Utf8Value name(info[3]->ToString()); - - if ( ! info[4]->IsString()) { - return throwTypeError("argument 5 must be a string (service type)"); - } - String::Utf8Value serviceType(info[4]->ToString()); - - if ( ! info[5]->IsString()) { - return throwTypeError("argument 6 must be a string (domain)"); - } - String::Utf8Value domain(info[5]->ToString()); - - if ( ! info[6]->IsFunction()) { - return throwTypeError("argument 7 must be a function (callBack)"); - } - serviceRef->SetCallback(Local::Cast(info[6])); - - if ( ! info[7]->IsNull() && ! info[7]->IsUndefined()) { - serviceRef->SetContext(info[7]); - } - - DNSServiceErrorType error = DNSServiceResolve( & serviceRef->GetServiceRef(), - flags, interfaceIndex, *name, *serviceType, *domain, OnResolve, serviceRef); - - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } - if ( ! serviceRef->SetSocketFlags()) { - return throwError("Failed to set socket flags (O_NONBLOCK, FD_CLOEXEC)"); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/dns_service_update_record.cpp b/lib/jdiscovery/mdns/src/dns_service_update_record.cpp deleted file mode 100644 index ff152ac6..00000000 --- a/lib/jdiscovery/mdns/src/dns_service_update_record.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "mdns.hpp" - -#include - -#ifndef WIN32 // XXX -#include -#endif - -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(DNSServiceUpdateRecord) { - if (argumentCountMismatch(info, 5)) { - return throwArgumentCountMismatchException(info, 5); - } - - if ( ! ServiceRef::HasInstance(info[0])) { - return throwTypeError("argument 1 must be a DNSServiceRef (sdRef)"); - } - ServiceRef * serviceRef = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - - if ( ! info[1]->IsNull()) { - return throwError("argument 2 must be zero. Custom records are not supported yet."); - } - - if ( ! info[2]->IsInt32()) { - return throwError("argument 3 must be an integer (DNSServiceFlags)"); - } - DNSServiceFlags flags = info[2]->ToInteger()->Int32Value(); - - uint16_t txtLen(0); - const void * txtRecord(NULL); - if ( ! info[3]->IsNull() && ! info[3]->IsUndefined()) { - if (Buffer::HasInstance(info[3])) { - Local bufferObject = info[3]->ToObject(); - txtRecord = Buffer::Data(bufferObject); - txtLen = Buffer::Length(bufferObject); - } else if (TxtRecordRef::HasInstance(info[3])) { - TxtRecordRef * ref = Nan::ObjectWrap::Unwrap(info[3]->ToObject()); - txtLen = TXTRecordGetLength( & ref->GetTxtRecordRef()); - txtRecord = TXTRecordGetBytesPtr( & ref->GetTxtRecordRef()); - } else { - return throwTypeError("argument 4 must be a buffer or a dns_sd.TXTRecordRef"); - } - } - - if ( ! info[4]->IsInt32()) { - return throwError("argument 5 must be an integer (ttl)"); - } - int ttl = info[4]->ToInteger()->Int32Value(); - - DNSServiceErrorType error = DNSServiceUpdateRecord( - serviceRef->GetServiceRef(), - NULL, - flags, - txtLen, - txtRecord, - ttl - ); - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/mdns.hpp b/lib/jdiscovery/mdns/src/mdns.hpp deleted file mode 100644 index df2ce73f..00000000 --- a/lib/jdiscovery/mdns/src/mdns.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef NODE_MDNS_INCLUDED -#define NODE_MDNS_INCLUDED - -#include "mdns_settings.hpp" - -#ifdef WIN32 -# pragma warning( push ) -# pragma warning( disable: 4251 ) -#endif - -#include -#include "nan.h" - -#ifdef WIN32 -# pragma warning( pop ) -#endif - -#ifndef NODE_VERSION_AT_LEAST -# include -#endif - -// XXX It would be better to test UV_VERSION_MAJOR and UV_VERSION_MINOR. -// However, libuv didn't bump the version when uv_poll_t was introduced. -#if NODE_VERSION_AT_LEAST(0, 7, 9) -# define NODE_MDNS_USE_SOCKET_WATCHER -//# warning Using SocketWatcher -#else -//# warning Using IOWatcher -#endif - - -#include - -#endif // NODE_MDNS_INCLUDED diff --git a/lib/jdiscovery/mdns/src/mdns_settings.hpp b/lib/jdiscovery/mdns/src/mdns_settings.hpp deleted file mode 100644 index e5e0df8b..00000000 --- a/lib/jdiscovery/mdns/src/mdns_settings.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef NODE_MDNS_SETTINGS_INCLUDED -# define NODE_MDNS_SETTINGS_INCLUDED - -# ifdef WIN32 -# define _WINSOCKAPI_ -# include - - // Microsoft namespace pollution. A macro called 'max'? Srsly? -# ifdef max -# undef max -# endif - -# ifndef NTDDI_VISTA -# define NTDDI_VISTA 0x6000000 -# endif - -# if NTDDI_VERSION >= NTDDI_VISTA -# define NODE_MDNS_HAVE_INTERFACE_NAME_CONVERSION -# endif - -# else // Unices - -# define NODE_MDNS_HAVE_INTERFACE_NAME_CONVERSION - -# endif // WIN32 - - -#endif // NODE_MDNS_SETTINGS_INCLUDED diff --git a/lib/jdiscovery/mdns/src/mdns_utils.cpp b/lib/jdiscovery/mdns/src/mdns_utils.cpp deleted file mode 100644 index 2a843688..00000000 --- a/lib/jdiscovery/mdns/src/mdns_utils.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "mdns.hpp" - -#include "mdns_utils.hpp" - -#include - -namespace node_mdns { - -using namespace v8; - -Local -buildException(DNSServiceErrorType error_code) { - if (error_code == kDNSServiceErr_NoError) { - return Nan::Undefined(); - } - - std::string error_str("dns service error: "); - error_str += errorString(error_code); - Local error_msg = Nan::New(error_str.c_str()).ToLocalChecked(); - Local error_v = Exception::Error(error_msg); - Local error = error_v->ToObject(); - Nan::Set(error, Nan::New("errorCode").ToLocalChecked(), Nan::New(error_code)); - return error_v; -} - -const char * -errorString(DNSServiceErrorType error) { - switch (error) { - case kDNSServiceErr_NoError: - return "no error"; - case kDNSServiceErr_Unknown: - return "unknown"; - case kDNSServiceErr_NoSuchName: - return "no such name"; - case kDNSServiceErr_NoMemory: - return "no memory"; - case kDNSServiceErr_BadParam: - return "bad param"; - case kDNSServiceErr_BadReference: - return "bad reference"; - case kDNSServiceErr_BadState: - return "bad state"; - case kDNSServiceErr_BadFlags: - return "bad flags"; - case kDNSServiceErr_Unsupported: - return "unsupported"; - case kDNSServiceErr_NotInitialized: - return "not initialized"; - case kDNSServiceErr_AlreadyRegistered: - return "already registered"; - case kDNSServiceErr_NameConflict: - return "name conflict"; - case kDNSServiceErr_Invalid: - return "invalid"; - case kDNSServiceErr_Firewall: - return "firewall"; - case kDNSServiceErr_Incompatible: - return "incompatible"; - case kDNSServiceErr_BadInterfaceIndex: - return "bad interface index"; - case kDNSServiceErr_Refused: - return "refused"; - case kDNSServiceErr_NoSuchRecord: - return "no such record"; - case kDNSServiceErr_NoAuth: - return "no auth"; - case kDNSServiceErr_NoSuchKey: - return "no such key"; - case kDNSServiceErr_NATTraversal: - return "NAT traversal"; - case kDNSServiceErr_DoubleNAT: - return "double NAT"; - case kDNSServiceErr_BadTime: - return "bad time"; -#ifdef kDNSServiceErr_BadSig - case kDNSServiceErr_BadSig: - return "bad sig"; -#endif -#ifdef kDNSServiceErr_BadKey - case kDNSServiceErr_BadKey: - return "bad key"; -#endif -#ifdef kDNSServiceErr_Transient - case kDNSServiceErr_Transient: - return "transient"; -#endif -#ifdef kDNSServiceErr_ServiceNotRunning - case kDNSServiceErr_ServiceNotRunning: - return "service not running"; -#endif -#ifdef kDNSServiceErr_NATPortMappingUnsupported - case kDNSServiceErr_NATPortMappingUnsupported: - return "NAT port mapping unsupported"; -#endif -#ifdef kDNSServiceErr_NATPortMappingDisabled - case kDNSServiceErr_NATPortMappingDisabled: - return "NAT port mapping disabled"; -#endif -#ifdef kDNSServiceErr_NoRouter - case kDNSServiceErr_NoRouter: - return "no router"; -#endif -#ifdef kDNSServiceErr_PollingMode - case kDNSServiceErr_PollingMode: - return "polling mode"; -#endif -#ifdef kDNSServiceErr_Timeout - case kDNSServiceErr_Timeout: - return "timeout"; -#endif - default: - return "unknown error code"; - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/mdns_utils.hpp b/lib/jdiscovery/mdns/src/mdns_utils.hpp deleted file mode 100644 index eb01af29..00000000 --- a/lib/jdiscovery/mdns/src/mdns_utils.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef NODE_MDNS_UTILS_INCLUDED -#define NODE_MDNS_UTILS_INCLUDED - -#include -#include -#include - -namespace node_mdns { - -const char * errorString(DNSServiceErrorType error); -v8::Local buildException(DNSServiceErrorType error_code); - -inline -void -throwError(const char * message) { - Nan::ThrowError( Nan::Error(message) ); -} - -inline -void -throwTypeError(const char * message) { - Nan::ThrowTypeError( message ); -} - -inline -void -throwMdnsError(DNSServiceErrorType error_code) { - Nan::ThrowError( buildException(error_code) ); -} - -inline -bool -argumentCountMismatch(Nan::NAN_METHOD_ARGS_TYPE info, int expectedCount) { - return info.Length() != expectedCount; -} - -inline -void -throwArgumentCountMismatchException(Nan::NAN_METHOD_ARGS_TYPE info, size_t expectedCount) { - std::ostringstream msg; - msg << "argument count mismatch: expected " << expectedCount - << ", but got " << info.Length() << " arguments."; - return throwError(msg.str().c_str()); -} - -inline -v8::Local -stringOrUndefined(const char * str) { - if (str) { - return Nan::New(str).ToLocalChecked(); - } else { - return Nan::Undefined(); - } -} - -} // end of namespace node_mdns - -#endif // NODE_MDNS_UTILS_INCLUDED diff --git a/lib/jdiscovery/mdns/src/network_interface.cpp b/lib/jdiscovery/mdns/src/network_interface.cpp deleted file mode 100644 index 1cbbb44f..00000000 --- a/lib/jdiscovery/mdns/src/network_interface.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef NODE_MDNS_NETWORK_INTERFACE_INCLUDED -#define NODE_MDNS_NETWORK_INTERFACE_INCLUDED - -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" - -#ifdef NODE_MDNS_HAVE_INTERFACE_NAME_CONVERSION - -# ifdef WIN32 -# include -# else -# include -# include -# include // if_nametoindex() -# endif - -using namespace v8; - -namespace node_mdns { - -NAN_METHOD(if_nametoindex) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsString()) { - return throwTypeError("argument 1 must be a string (interface name)"); - } - String::Utf8Value interfaceName(info[0]->ToString()); - -#ifdef WIN32 - DWORD aliasLength = MultiByteToWideChar(CP_UTF8, 0, *interfaceName, -1, - NULL, 0); - if (aliasLength == 0) { - return throwError("failed to determine buffer size"); - } - - wchar_t * alias = new wchar_t[aliasLength]; - if ( ! alias) { - return throwError("failed to allocate alias buffer"); - } - - if (MultiByteToWideChar(CP_UTF8, 0, *interfaceName, -1, alias, - aliasLength) == 0) - { - delete [] alias; - return throwError("failed to convert utf8 to unicode"); - } - - NET_LUID luid; - if (ConvertInterfaceAliasToLuid(alias, &luid) != NO_ERROR) { - delete [] alias; - return throwError("failed to convert interface alias to luid"); - } - - delete [] alias; - - NET_IFINDEX index = 0; - if (ConvertInterfaceLuidToIndex(&luid, &index) != NO_ERROR) { - return throwError("failed to convert interface luid to index"); - } -#else - unsigned int index = ::if_nametoindex(*interfaceName); -#endif - if (index == 0) { - return throwError((std::string("interface '") + *interfaceName + - "' does not exist").c_str()); - } - info.GetReturnValue().Set( Nan::New(static_cast(index))); -} - -NAN_METHOD(if_indextoname) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsUint32()) { - return throwTypeError("argument 1 must be a positive integer " - "(interface index)"); - } -#ifdef WIN32 - NET_LUID luid; - if (ConvertInterfaceIndexToLuid(Nan::To(info[0]).FromJust(), &luid) != NO_ERROR) - { - return throwError("failed to convert interface index to luid"); - } - enum { size = NDIS_IF_MAX_STRING_SIZE + 1 }; - wchar_t alias[size]; - if (ConvertInterfaceLuidToAlias(&luid, alias, size) != NO_ERROR) { - return throwError("failed to convert interface luid to alias"); - } - int utf8Length = WideCharToMultiByte(CP_UTF8, 0, alias, -1, - NULL, 0, NULL, NULL); - if (utf8Length == 0) { - return throwError("failed to determine buffer size"); - } - char * nameBuffer = new char[utf8Length]; - - if (WideCharToMultiByte(CP_UTF8, 0, alias, -1, nameBuffer, utf8Length, - NULL, NULL) == 0) - { - delete [] nameBuffer; - return throwError("failed to convert unicode to utf8"); - } - Local name = Nan::New(nameBuffer).ToLocalChecked(); - delete [] nameBuffer; -#else - char nameBuffer[IFNAMSIZ]; - if ( ! ::if_indextoname(Nan::To(info[0]).FromJust(), nameBuffer)) { - return throwError("index has no corresponding interface"); - } - Local name = Nan::New(nameBuffer).ToLocalChecked(); -#endif - info.GetReturnValue().Set(name); -} - -} // end of namespace node_mdns - -#endif // NODE_MDNS_HAVE_INTERFACE_NAME_CONVERSION - -#endif // NODE_MDNS_NETWORK_INTERFACE_INCLUDED diff --git a/lib/jdiscovery/mdns/src/skeleton.cpp_ b/lib/jdiscovery/mdns/src/skeleton.cpp_ deleted file mode 100644 index 4dea5c2e..00000000 --- a/lib/jdiscovery/mdns/src/skeleton.cpp_ +++ /dev/null @@ -1,11 +0,0 @@ -#include - -#include "mdns_utils.hpp" -#include "dns_service_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/socket_watcher.cpp b/lib/jdiscovery/mdns/src/socket_watcher.cpp deleted file mode 100644 index 8883cf2e..00000000 --- a/lib/jdiscovery/mdns/src/socket_watcher.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "mdns.hpp" - -// poor mans conditional compilation. is there a better way to do this with gyp? -#ifdef NODE_MDNS_USE_SOCKET_WATCHER - -#include "socket_watcher.hpp" - -#include // needed for memset() with node v0.7.9 on Mac OS -#include -#include - -using namespace v8; - -#if ! NODE_VERSION_AT_LEAST(0, 7, 8) -namespace node { - -Handle -MakeCallback(const Handle object, const Handle callback, - int argc, Handle argv[]) -{ - Nan::HandleScope scope; - - // TODO Hook for long stack traces to be made here. - - NanTryCatch try_catch; - - Local ret = Nan::MakeCallback(object, callback, argc, info); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - return; - } - - info.GetReturnValue().Set(ret); -} - -} // end of namespace node -#endif - -namespace node_mdns { - - SocketWatcher::SocketWatcher() : poll_(NULL), fd_(0), events_(0) { - } - - void - SocketWatcher::Initialize(Handle target) { - Local t = Nan::New(New); - - Local symbol = Nan::New("SocketWatcher").ToLocalChecked(); - t->SetClassName(symbol); - t->InstanceTemplate()->SetInternalFieldCount(1); - - Nan::SetPrototypeMethod(t, "set", SocketWatcher::Set); - Nan::SetPrototypeMethod(t, "start", SocketWatcher::Start); - Nan::SetPrototypeMethod(t, "stop", SocketWatcher::Stop); - - Nan::Set(target, symbol, Nan::GetFunction(t).ToLocalChecked()); - } - - NAN_METHOD(SocketWatcher::Start) { - SocketWatcher *watcher = Nan::ObjectWrap::Unwrap(info.Holder()); - watcher->Start(); - } - - void - SocketWatcher::Start() { - if (poll_ == NULL) { - poll_ = new uv_poll_t; - memset(poll_,0,sizeof(uv_poll_t)); - poll_->data = this; - uv_poll_init_socket(uv_default_loop(), poll_, fd_); - - Ref(); - } - - if (!uv_is_active((uv_handle_t*)poll_)) { - uv_poll_start(poll_, events_, &SocketWatcher::Callback); - } - } - - void - SocketWatcher::Callback(uv_poll_t *w, int status, int revents) { - Nan::HandleScope scope; - - SocketWatcher *watcher = static_cast(w->data); - assert(w == watcher->poll_); - - Local callback_v = Nan::Get(watcher->handle(), Nan::New("callback").ToLocalChecked()).ToLocalChecked(); - if (!callback_v->IsFunction()) { - watcher->Stop(); - return; - } - - Local callback = Local::Cast(callback_v); - - Local argv[2]; - argv[0] = revents & UV_READABLE ? Nan::True() : Nan::False(); - argv[1] = revents & UV_WRITABLE ? Nan::True() : Nan::False(); - - Nan::MakeCallback(watcher->handle(), callback, 2, argv); - } - - NAN_METHOD(SocketWatcher::Stop) { - SocketWatcher *watcher = Nan::ObjectWrap::Unwrap(info.Holder()); - watcher->Stop(); - } - - void - SocketWatcher::Stop() { - if (poll_ != NULL) { - uv_poll_stop(poll_); - Unref(); - } - } - - NAN_METHOD(SocketWatcher::New) { - SocketWatcher *s = new SocketWatcher(); - s->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - } - - NAN_METHOD(SocketWatcher::Set) { - SocketWatcher *watcher = Nan::ObjectWrap::Unwrap(info.Holder()); - if (!info[0]->IsInt32()) { - return Nan::ThrowTypeError("First arg should be a file descriptor."); - } - int fd = Nan::To(info[0]).FromJust(); - if (!info[1]->IsBoolean()) { - return Nan::ThrowTypeError("Second arg should be a boolean (readable)."); - } - int events = 0; - - if (info[1]->IsTrue()) events |= UV_READABLE; - - if (!info[2]->IsBoolean()) { - return Nan::ThrowTypeError("Third arg should be a boolean (writable)."); - } - - if (info[2]->IsTrue()) events |= UV_WRITABLE; - - assert(watcher->poll_ == NULL); - - watcher->fd_ = fd; - watcher->events_ = events; - } - -} // end of namespace node_mdns - -#endif // NODE_MDNS_USE_SOCKET_WATCHER diff --git a/lib/jdiscovery/mdns/src/socket_watcher.hpp b/lib/jdiscovery/mdns/src/socket_watcher.hpp deleted file mode 100644 index 32166035..00000000 --- a/lib/jdiscovery/mdns/src/socket_watcher.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef NODE_MDNS_SOCKET_WATCHER_INCLUDED -#define NODE_MDNS_SOCKET_WATCHER_INCLUDED - -namespace node_mdns { - -class SocketWatcher : public Nan::ObjectWrap { - public: - SocketWatcher(); - - static void Initialize(v8::Handle target); - - private: - uv_poll_t* poll_; - int fd_; - int events_; - - static NAN_METHOD(New); - static NAN_METHOD(Set); - static NAN_METHOD(Start); - static NAN_METHOD(Stop); - - void Start(); - void Stop(); - static void Callback(uv_poll_t *w, int status, int events); -}; - -} // end of namespace node_mdns - -#endif // NODE_MDNS_SOCKET_WATCHER_INCLUDED diff --git a/lib/jdiscovery/mdns/src/txt_record_buffer_to_object.cpp b/lib/jdiscovery/mdns/src/txt_record_buffer_to_object.cpp deleted file mode 100644 index 1c5ce5a1..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_buffer_to_object.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "mdns.hpp" - -#include - -#include - -#include "mdns_utils.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(txtRecordBufferToObject) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject() || ! Buffer::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a buffer (txtRecord)"); - } - Local buffer = info[0]->ToObject(); - - Local result = Nan::New(); - std::vector key(16); - size_t buffer_length = Buffer::Length(buffer); - void * data = Buffer::Data(buffer); - uint16_t item_count = TXTRecordGetCount(buffer_length, data); - DNSServiceErrorType error; - const void * value_ptr; - uint8_t value_length; - for (uint16_t i = 0; i < item_count; ++i) { - while (kDNSServiceErr_NoMemory == (error = - TXTRecordGetItemAtIndex(buffer_length, data, i, key.size(), - &*key.begin(), & value_length, & value_ptr))) - { - key.resize(key.size() * 2); - } - if (error != kDNSServiceErr_NoError) { - return throwMdnsError(error); - } - if (value_ptr) { - Nan::Set(result, Nan::New(&*key.begin()).ToLocalChecked(), - Nan::New(static_cast(value_ptr), value_length).ToLocalChecked()); - } else { - Nan::Set(result, Nan::New(&*key.begin()).ToLocalChecked(), Nan::Undefined()); - } - } - info.GetReturnValue().Set(result); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/txt_record_create.cpp b/lib/jdiscovery/mdns/src/txt_record_create.cpp deleted file mode 100644 index 0978a246..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_create.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(TXTRecordCreate) { - if (argumentCountMismatch(info, 2)) { - return throwArgumentCountMismatchException(info, 2); - } - if ( ! info[0]->IsObject() || ! TxtRecordRef::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a TXTRecordRef object"); - } - - void * buffer = NULL; - uint16_t buffer_length = 0; - if ( ! info[1]->IsUndefined() && ! info[1]->IsNull()) { - if ( ! info[1]->IsObject() || ! Buffer::HasInstance(info[1]->ToObject())) { - return throwTypeError("argument 1 must be a buffer"); - } - Local buffer_object = info[1]->ToObject(); - buffer = Buffer::Data(buffer_object); - buffer_length = Buffer::Length(buffer_object); - } - - TxtRecordRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - TXTRecordCreate( & ref->GetTxtRecordRef(), buffer_length, buffer); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/txt_record_deallocate.cpp b/lib/jdiscovery/mdns/src/txt_record_deallocate.cpp deleted file mode 100644 index f739dcda..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_deallocate.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "mdns.hpp" - -#include "mdns_utils.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(TXTRecordDeallocate) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject() || ! TxtRecordRef::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a TXTRecordRef object"); - } - - TxtRecordRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - TXTRecordDeallocate( & ref->GetTxtRecordRef()); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/txt_record_get_length.cpp b/lib/jdiscovery/mdns/src/txt_record_get_length.cpp deleted file mode 100644 index 75cf8cfc..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_get_length.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "mdns.hpp" - -#include "mdns_utils.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -NAN_METHOD(TXTRecordGetLength) { - if (argumentCountMismatch(info, 1)) { - return throwArgumentCountMismatchException(info, 1); - } - if ( ! info[0]->IsObject() || ! TxtRecordRef::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a buffer (txtRecord)"); - } - TxtRecordRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - uint16_t result = ::TXTRecordGetLength( & ref->GetTxtRecordRef()); - info.GetReturnValue().Set(result); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/txt_record_ref.cpp b/lib/jdiscovery/mdns/src/txt_record_ref.cpp deleted file mode 100644 index 92461f57..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_ref.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "mdns.hpp" - -#include "txt_record_ref.hpp" - -using namespace v8; - -namespace node_mdns { - -Nan::Persistent TxtRecordRef::constructor_template; - -TxtRecordRef::TxtRecordRef() : - ref_() -{ -} - -TxtRecordRef::~TxtRecordRef() { - TXTRecordDeallocate( & ref_); -} - -void -TxtRecordRef::Initialize(Handle target) { - Local t = Nan::New(New); - constructor_template.Reset(t); - t->InstanceTemplate()->SetInternalFieldCount(1); - t->SetClassName(Nan::New("TXTRecordRef").ToLocalChecked()); - - Nan::Set(target, Nan::New("TXTRecordRef").ToLocalChecked(), - Nan::GetFunction(t).ToLocalChecked()); -} - -NAN_METHOD(TxtRecordRef::New) { - TxtRecordRef * o = new TxtRecordRef(); - o->Wrap(info.Holder()); - info.GetReturnValue().Set(info.This()); -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/src/txt_record_ref.hpp b/lib/jdiscovery/mdns/src/txt_record_ref.hpp deleted file mode 100644 index 2ba53a51..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_ref.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef NODE_MDNS_TXT_RECORD_REF_INCLUDED -#define NODE_MDNS_TXT_RECORD_REF_INCLUDED - -namespace node_mdns { - -class TxtRecordRef : public Nan::ObjectWrap { - public: - TxtRecordRef(); - ~TxtRecordRef(); - - static void Initialize(v8::Handle target); - static NAN_METHOD(New); - - //inline bool IsInitialized() const { return ref_ != NULL; } - - static inline bool HasInstance(v8::Handle value) { - if ( ! value->IsObject() ) return false; - v8::Local object = value->ToObject(); - return Nan::New(constructor_template)->HasInstance( object ); - } - - TXTRecordRef & GetTxtRecordRef() { return ref_; } - void SetTxtRecordRef(TXTRecordRef ref) { ref_ = ref; } - - private: - TXTRecordRef ref_; - - static Nan::Persistent constructor_template; -}; - -} // end of namespace node_mdns -#endif // NODE_MDNS_TXT_RECORD_REF_INCLUDED diff --git a/lib/jdiscovery/mdns/src/txt_record_set_value.cpp b/lib/jdiscovery/mdns/src/txt_record_set_value.cpp deleted file mode 100644 index ed340bc9..00000000 --- a/lib/jdiscovery/mdns/src/txt_record_set_value.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "mdns.hpp" - -#include - -#include "mdns_utils.hpp" -#include "txt_record_ref.hpp" - -using namespace v8; -using namespace node; - -namespace node_mdns { - -size_t length(Handle v) { - if (v->IsString()) { - return v->ToString()->Utf8Length(); - } else if (Buffer::HasInstance(v)) { - return Buffer::Length(v->ToObject()); - } else { - return 0; - } -} - -NAN_METHOD(TXTRecordSetValue) { - if (argumentCountMismatch(info, 3)) { - return throwArgumentCountMismatchException(info, 3); - } - if ( ! info[0]->IsObject() || ! TxtRecordRef::HasInstance(info[0]->ToObject())) { - return throwTypeError("argument 1 must be a TXTRecordRef object"); - } - TxtRecordRef * ref = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - - if ( ! info[1]->IsString()) { - return throwTypeError("argument 1 must be a string (key)"); - } - String::Utf8Value key(info[1]); - - if ( ! (info[2]->IsNull() || info[2]->IsUndefined() || - Buffer::HasInstance(info[2]) || info[2]->IsString())) { - return throwTypeError("argument 1 must be null, undefined, a buffer or a string (value)"); - } - DNSServiceErrorType code = TXTRecordSetValue( & ref->GetTxtRecordRef(), *key, - length(info[2]), - ((info[2]->IsNull()||info[2]->IsUndefined()) - ? NULL : info[2]->IsString() ? *String::Utf8Value(info[2]->ToString()) : Buffer::Data(info[2]->ToObject()))); - - if (code != kDNSServiceErr_NoError) { - return throwMdnsError(code); - } -} - -} // end of namespace node_mdns diff --git a/lib/jdiscovery/mdns/tests/test_browser.js b/lib/jdiscovery/mdns/tests/test_browser.js deleted file mode 100644 index e580644c..00000000 --- a/lib/jdiscovery/mdns/tests/test_browser.js +++ /dev/null @@ -1,98 +0,0 @@ -var st = require('../lib/service_type.js') - , dns_sd = require('../lib/dns_sd') - , proxyquire = require('proxyquire') - ; - -//=== Browser =========================================================== - -module.exports["Browser"] = { - "Should retrieve interface name from cache when interface index is no longer valid": function(test) { - var callback = null - , invocations = 0 - , threwException = false - , interfaceName = "foo" - , serviceName = "_foo._tcp."; - - var mock_dns_sd = { - kDNSServiceErr_NoError: dns_sd.kDNSServiceErr_NoError, - kDNSServiceInterfaceIndexLocalOnly: dns_sd.kDNSServiceInterfaceIndexLocalOnly, - kDNSServiceFlagsAdd: dns_sd.kDNSServiceFlagsAdd, - - // we stub the if_indextoname method - if_indextoname: function() { - invocations++; - - if(invocations == 1) { - return interfaceName; - } - - threwException = true; - throw new Error("Panic!"); - }, - // and stub DNSServiceBrowse to expose a reference to the passed callback - DNSServiceBrowse: function(sdRef, flags, ifaceIdx, serviceType, domain, on_service_changed, context) { - callback = function() { - // pass 1 as the interface index so we don't try to find the name for loopback - on_service_changed(sdRef, flags, 1, dns_sd.kDNSServiceErr_NoError, serviceName, serviceType, domain, context); - }; - } - }; - - // we're going to expect two invocations, one where the interface is present and one where it's not - var serviceDownInvocations = 0; - - // create the browser with our mock of dns_sd - var browser = proxyquire('../lib/browser.js', { './dns_sd': mock_dns_sd }).Browser.create(serviceName); - browser.on("serviceDown", function(service) { - serviceDownInvocations++; - - if(serviceDownInvocations == 1) { - // first invocation, should have interface name from dns_sd callback - test.equal(service.networkInterface, interfaceName); - - // should not have thrown an exception yet - test.ok( ! threwException); - } - - if(serviceDownInvocations == 2) { - // second invocation, should have thrown an exception in the callback - test.ok(threwException); - - // should still have the interface name even though we threw an exception - test.equal(service.networkInterface, interfaceName); - - test.done(); - } - }); - - // simulate two MDNS events, this will trigger the serviceDown event we listen for above. - callback(); - callback(); - }, - - "Should survive invalid MDNS advert": function(test) { - var callback = null - , serviceName = "_foo._tcp."; - - var mock_dns_sd = { - kDNSServiceErr_NoError: dns_sd.kDNSServiceErr_NoError, - - // and stub DNSServiceBrowse to expose a reference to the passed callback - DNSServiceBrowse: function(sdRef, flags, ifaceIdx, serviceType, domain, on_service_changed, context) { - callback = function() { - // pass 1 as the interface index so we don't try to find the name for loopback - on_service_changed(sdRef, flags, 1, dns_sd.kDNSServiceErr_NoError, '', '', domain, context); - }; - } - }; - - // create the browser with our mock of dns_sd - var browser = proxyquire('../lib/browser.js', { './dns_sd': mock_dns_sd }).Browser.create(serviceName); - browser.on('error', function(error) { - test.equal(error.message, "protocol must be either '_tcp' or '_udp' but is 'undefined'"); - test.done(); - }); - - callback(); - } -} diff --git a/lib/jdiscovery/mdns/tests/test_dns_sd.js b/lib/jdiscovery/mdns/tests/test_dns_sd.js deleted file mode 100755 index 2d487b3b..00000000 --- a/lib/jdiscovery/mdns/tests/test_dns_sd.js +++ /dev/null @@ -1,970 +0,0 @@ -var path = require('path') - , mdns_test = require('../utils/lib/mdns_test') - , dns_sd = mdns_test.require('dns_sd') - , service_type = "_mdns_test._tcp" - , test_port = 4321 - ; - -//=== DNSServiceRef =========================================================== - -exports['DNSServiceRef'] = function(t) { - - var sr = new dns_sd.DNSServiceRef(); - - t.ok(sr, - 'DNSServiceRef must be truthy'); - t.strictEqual(sr.fd, -1, - 'File descriptor must be -1'); - t.strictEqual(sr.initialized, false, - 'DNSServiceRef must not be initialized'); - t.done(); -} - -//=== DNSServiceRegister ====================================================== - -exports['DNSServiceRegister()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef(); - - t.doesNotThrow(function() { - var /* uses paren scope serviceRef */ - flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister( serviceRef, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, 'Call with minimal argumentss must succeed.'); - - t.notStrictEqual(serviceRef.fd, -1, - 'File descriptor must not be -1 after initialization'); - - t.strictEqual(serviceRef.initialized, true, - 'DNSServiceRef must be initialized'); - - t.throws(function() { - var /* uses parent scope serviceRef */ - flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister( serviceRef, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, 'Duplicate initialization of DNSServiceRef must throw'); - - t.doesNotThrow(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = 'My sh4red stuff' - , type = service_type - , domain = 'somedomain' - , host = null /* avahi throws 'bad param'*/ - , port = test_port - , txtRec = new Buffer('\0') - , cb = function() {} - , ctx = {anything: true} - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, 'Call with all arguments on must succed.'); - - t.throws(function() { dns_sd.DNSServiceRegister(); }, - 'Call with zero arguments must throw.'); - - t.throws(function() { - var a1, a2, a3, a4, a5, a6, a7, a8; - dns_sd.DNSServiceRegister(a1, a2, a3, a4, a5, a6, a7, a7); - }, 'Call with eight arguments must throw.'); - - t.throws(function() { - var ref = { not_a_service_ref: true } /* broken */ - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'flags' must be a number, not a string."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = '=== KAPUTT ===' /* broken */ - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'flags' must be a number, not a string."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = '=== KAPUTT ===' /* broken */ - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'interfaceIndex' must be a number, not a string."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = 1111111111 /* broken */ - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'name' must be a string, not a number."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = null /* broken */ - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'regtype' must be a string, not null."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = 1111111111 /* broken */ - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'regtype' has to be a string, not a number."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = 1111111111 /* broken */ - , host = null - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'domain' must not be a string, not a number."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = 1111111111 /* broken */ - , port = test_port - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'host' must be a string, not a number."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = '=== KAPUTT ===' /* broken */ - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'port' must be a number, not a string."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = 1111111111 /* broken */ - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'txtRecord' must be a TXTRecordRef or buffer, not a number."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = test_port - , txtRec = null - , cb = '=== KAPUTT ===' /* broken */ - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, "'callback' must be a function, not a string."); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = 1 << 16 /* broken */ - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, 'port number must be <= ' + ((1 << 16) - 1) + '.'); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef() - , flags = 0 - , iface = 0 - , name = null - , type = service_type - , domain = null - , host = null - , port = -1 /* broken */ - , txtRec = null - , cb = null - , ctx = null - ; - dns_sd.DNSServiceRegister(ref, flags, iface, name, type, domain, - host, port, txtRec, cb, ctx); - }, 'port number must >= 0.'); - - t.done(); -}; - -//=== DNSServiceProcessResult ================================================= - -exports['DNSServiceProcessResult()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef() - , IOWatcher = require('../lib/io_watcher').IOWatcher - , watcher = new IOWatcher() - , timeout = 3000 - , timeoutId = setTimeout(function() { - t.ok(false ,"Test did not finish within " + (timeout/1000) + "s"); - watcher.stop(); - t.done(); - } - , timeout); - - t.throws(function() { - dns_sd.DNSServiceProcessResult(); - }); - - t.throws(function() { - dns_sd.DNSServiceProcessResult('flip', 'flap', 'flop'); - }); - - t.throws(function() { - dns_sd.DNSServiceProcessResult(new dns_sd.DNSServiceRef()); - }); - - t.throws(function() { - dns_sd.DNSServiceProcessResult(5); - }); - - watcher.callback = function() { - dns_sd.DNSServiceProcessResult(serviceRef); - } - - function result_callback(sdRef, flags, errorCode, name, serviceType, domain, - context) - { - t.strictEqual(sdRef, serviceRef, - 'serviceRef must be identical'); - t.strictEqual(typeof flags, "number", - "'flags' must be of type number"); - t.strictEqual(typeof errorCode, "number", - "'errorCode' must be of type number"); - t.strictEqual(errorCode, dns_sd.kDNSServiceErr_NoError, - "'errorCode' must be kDNSServiceErr_NoError"); - t.strictEqual(typeof name, "string", - "'name' must be of type string"); - t.strictEqual(typeof serviceType, "string", - "'serviceType' must be of type string"); - t.strictEqual(typeof domain, "string", - "'domain' must be of type string"); - t.strictEqual(typeof context, "string", - "'context' must be of type string (in this test)"); - t.strictEqual(context, "foobar", - "expected 'foobar' but got '" + context + "'"); - - clearTimeout(timeoutId); - watcher.stop(); - watcher.callback = null; - t.done(); - } - - dns_sd.DNSServiceRegister(serviceRef, 0, 0, null, service_type, - null, null, test_port, null, result_callback, "foobar"); - - watcher.set(serviceRef.fd, true, false); - watcher.start(); -} - -//=== DNSServiceRefSockFD ===================================================== - -exports['DNSServiceRefSockFD()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef(); - - t.throws(function() {dns_sd.DNSServiceRefSockFD(serviceRef)}, - 'call with uninitialized serviceRef must throw'); - - dns_sd.DNSServiceRegister(serviceRef, 0, 0, null, service_type, - null, null, test_port, null, null, null); - - var fd; - t.doesNotThrow(function() {fd = dns_sd.DNSServiceRefSockFD(serviceRef)}, - "DNSServiceRefSockFD() must not throw"); - - t.notEqual(fd, -1, 'file descriptor must not be -1'); - - t.strictEqual(serviceRef.fd, fd, - 'result of DNSServiceRefSockFD() and fd getter must be the same'); - - t.throws(function() { dns_sd.DNSServiceRefSockFD("narf"); }, - 'argument must be a DNSServiceRef'); - - t.throws(function() { dns_sd.DNSServiceRefSockFD(); }, - 'must throw when called with not enough arguments'); - - t.done(); -} - -//=== DNSServiceBrowse ======================================================== - -exports['DNSServiceBrowse()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef(); - - t.doesNotThrow(function() { - dns_sd.DNSServiceBrowse(serviceRef, 0, 0, service_type, null, - function() {}, null); - }, "DNSServiceBrowse() must not throw"); - - t.throws(function() { - dns_sd.DNSServiceBrowse(serviceRef, 0, 0, service_type, null, - function() {}, null); - }, 'serviceRef already initialized'); - - t.throws(function() { - dns_sd.DNSServiceBrowse(); - }, 'not enough arguments'); - - t.throws(function() { - dns_sd.DNSServiceBrowse("", 0, 0, service_type, null, - function() {}, null); - }, "'serviceRef' must not be a string"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, "", 0, service_type, null, - function() {}, null); - }, "'flags' must be a number, not a string"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, "", service_type, null, - function() {}, null); - }, "'interfaceIndex' must be a number, not a string"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, null, null, function() {}, null); - }, "'regtype' must be a string, not null"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, 0, null, function() {}, null); - }, "'regtype' must be a string, not a number"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, service_type, 0, - function() {}, null); - }, "'domain' must be a string, not a number"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, service_type, null, 0, null); - }, "'callback' must be a function, not a number"); - - // coverage: take domain branch - t.doesNotThrow(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, service_type, 'somedomain', - function() {}, null); - }, "DNSServiceBrowse() must not throw"); - - // coverage: take domain undefined branch - t.doesNotThrow(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, service_type, undefined, - function() {}, null); - }, "DNSServiceBrowse() must not throw"); - - // coverage: take domain undefined branch - t.doesNotThrow(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceBrowse(ref, 0, 0, service_type, undefined, - function() {}, undefined); - }, "DNSServiceBrowse() must not throw"); - - t.done(); -} - -//=== DNSServiceRefDeallocate ================================================= - -exports['DNSServiceRefDeallocate()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef(); - - dns_sd.DNSServiceRegister(serviceRef, 0, 0, null, "_node-mdns-test._tcp", - null, null, test_port, null, null, null); - - t.strictEqual(serviceRef.initialized, true, - "'initialized' must be true after inititalization"); - - dns_sd.DNSServiceRefDeallocate(serviceRef); - - t.strictEqual(serviceRef.initialized, false, - "'initialized' must be false after deallocation"); - - t.strictEqual(serviceRef.fd, -1, - "'fd' must be -1 after deallocation"); - - t.throws(function() { dns_sd.DNSServiceRefDeallocate(serviceRef); }, - "serviceRef is already deallocated"); - - t.throws(function() { dns_sd.DNSServiceRefDeallocate(); }, - "not enough arguments"); - - t.throws(function() { dns_sd.DNSServiceRefDeallocate(undefined); }, - "argument must be DNSServiceRef, not undefined"); - - t.throws(function() { dns_sd.DNSServiceRefDeallocate(serviceRef, serviceRef); }, - "to many arguments"); - - t.throws(function() { dns_sd.DNSServiceRefDeallocate({foo: 'bar'}); }, - "call with non serviceRef object must throw"); - - t.done(); -} - -//=== DNSServiceResolve ======================================================= - -exports['DNSServiceResolve()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef(); - - t.doesNotThrow(function() { - dns_sd.DNSServiceResolve(serviceRef, 0, 0, 'hostname', - service_type, 'local.', function() {}, null); - }, 'DNSServiceResolve() must not throw'); - - t.strictEqual(serviceRef.initialized, true, - "'initialized' must be true after inititalization"); - - t.throws(function() { - dns_sd.DNSServiceResolve(serviceRef, 0, 0, undefined, - service_type, 'local.', function() {}, null); - }, 'duplicate initialization must throw'); - - t.throws(function() { - dns_sd.DNSServiceResolve(); - }, "not enough arguments"); - - t.throws(function() { - dns_sd.DNSServiceResolve({not_a_service_re: true}, 0, 0, 'hostname', - service_type, 'local.', function() {}, null); - }, 'serviceRef must be DNSServiceRef object'); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceResolve(ref, "", 0, 'hostname', - service_type, 'local.', function() {}, null); - }, "'flags' must be a number, not a string"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceResolve(ref, 0, null, 'hostname', - service_type, 'local.', function() {}, null); - }, "'interfaceIndex' must be a number, not null"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceResolve(ref, 0, 0, null, - service_type, 'local.', function() {}, null); - }, "'name' must be a string, not null"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceResolve(ref, 0, 0, 'hostname', null, - 'local.', function() {}, null); - }, "'regtype' must be a string, not null"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceResolve(ref, 0, 0, 'hostname', - service_type, null, function() {}, null); - }, "'domain' must be a string, not null"); - - t.throws(function() { - var ref = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceResolve(ref, 0, 0, 'hostname', - service_type, 'local.', null, null); - }, "'callback' must be a function, not null"); - - t.done(); -} - -//=== DNSServiceEnumerateDomains ============================================== - -exports['DNSServiceEnumerateDomains()'] = function(t) { - var serviceRef = new dns_sd.DNSServiceRef(); - - t.doesNotThrow( function() { - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 0, function() {}, null); - }, 'DNSServiceEnumerateDomains() must not throw'); - - t.notEqual(serviceRef.fd, -1, - "'fd' must not be -1 after inititalization"); - t.strictEqual(serviceRef.initialized, true, - "'initialized' must be true after inititalization"); - - t.doesNotThrow( function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 0, function() {}, undefined); - }, 'DNSServiceEnumerateDomains() must not throw'); - - t.doesNotThrow( function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 0, function() {}, {some: 'context'}); - }, 'DNSServiceEnumerateDomains() must not throw'); - - t.throws(function() { - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 0, function() {}, null); - }, 'dupliate inititalization of serviceRef must throw'); - - t.throws(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - 'flags', 0, function() {}, null); - }, "'flags' must be a number, not a string"); - - t.throws(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - 0, 0, function() {}, null); - }, "'flags' must be kDNSServiceFlagsBrowseDomains or " + - "kDNSServiceFlagsRegistrationDomains"); - - t.throws(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 'interfaceIndex', function() {}, null); - }, "'interfaceIndex' must be number, not a string"); - - t.throws(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 0, 'function', null); - }, "'callback' must be function, not a string"); - - t.throws(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(serviceRef, - dns_sd.kDNSServiceFlagsBrowseDomains, 0, null, null); - }, "'callback' must be function, not null"); - - t.throws(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceEnumerateDomains(); - }, "not enough arguments"); - - t.throws(function() { - dns_sd.DNSServiceEnumerateDomains('not a serviceRef', - 0, 0, function() {}, null); - }, "serviceRef must be a DNSServiceRef object"); - - t.done(); -} - -//=== DNSServiceGetAddrInfo =================================================== - -function findInterfaceIndex() { - var serviceRef, i; - for (var i = 0; i < 100; ++i) { - try { - serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceGetAddrInfo(serviceRef, 0, i, 0, 'somehost.local.', - function() {}, null); - return i; - - } catch (ex) {} - } -} - -exports['DNSServiceGetAddrInfo'] = function DNSServiceGetAddrInfo(t) { - - if ( ! dns_sd.DNSServiceGetAddrInfo) { - console.log('[SKIPPED] DNSServiceGetAddrInfo() not available'); - t.done(); - return; - } - - var iface = findInterfaceIndex(); - - t.doesNotThrow(function() { - var serviceRef = new dns_sd.DNSServiceRef(); - dns_sd.DNSServiceGetAddrInfo(serviceRef, 0, iface, 0, 'somehost.local.', - function() {}, null); - }, 'DNSServiceGetAddrInfo() must not throw'); - - // TODO add more tests - - t.done(); -} - -//=== TXTRecordRef ============================================================ - -exports['TXTRecordRef'] = function(t) { - var txtRecord = new dns_sd.TXTRecordRef() - , uninitialized_txt_record = new dns_sd.TXTRecordRef() - ; - dns_sd.TXTRecordCreate(txtRecord, null); - - var txtRecord = new dns_sd.TXTRecordRef(); - var buffer = new Buffer(256); - dns_sd.TXTRecordCreate(txtRecord, buffer); - txtRecord.buffer = buffer; - - dns_sd.TXTRecordSetValue(txtRecord, 'foo', 'bar'); - t.strictEqual(dns_sd.TXTRecordGetLength(txtRecord), 8, - "length must be 8 bytes after adding 'foo=bar'"); - - dns_sd.TXTRecordSetValue(txtRecord, 'foobar', 'foobar'); - t.strictEqual(dns_sd.TXTRecordGetLength(txtRecord), 22, - "length must be 22 bytes after adding 'foobar=foobar'"); - - dns_sd.TXTRecordSetValue(txtRecord, 'buffer', new Buffer('raw')); - t.strictEqual(dns_sd.TXTRecordGetLength(txtRecord), 33, - "length must be 33 bytes after adding 'buffer=raw'"); - - t.throws(function() { dns_sd.TXTRecordCreate() }, - 'TXTRecordCreate() must throw when called without arguments'); - t.throws(function() { dns_sd.TXTRecordCreate('narf') }, - 'TXTRecordCreate() must throw when called with a string'); - t.throws(function() { dns_sd.TXTRecordCreate(txtRecord) }, - 'duplicate call to TXTRecordCreate() must throw'); - t.throws(function() { - var b = new Buffer(256); - dns_sd.TXTRecordCreate({not_a_txt_record: true}, b); - }, 'txtRecord must be a TXTRecordRef object'); - t.throws(function() { - var b = new Buffer(256); - dns_sd.TXTRecordCreate(5, b); - }, 'txtRecord must be a TXTRecordRef object'); - t.doesNotThrow(function() { - var tref = new dns_sd.TXTRecordRef(); - dns_sd.TXTRecordCreate(tref, undefined); - },'TXTRecordCreate() with undefined buffer must succeed'); - t.throws(function() { - var tref = new dns_sd.TXTRecordRef(); - dns_sd.TXTRecordCreate(tref, {not_a_buffer: true}); - }, 'illegal buffer argument must throw'); - t.throws(function() { - var tref = new dns_sd.TXTRecordRef(); - dns_sd.TXTRecordCreate(tref, 5); - }, 'illegal buffer argument must throw'); - - - t.throws(function() { - dns_sd.TXTRecordDeallocate({not_a_txt_record_ref: true}) - }, 'illegal argument must throw'); - - t.throws(function() { - dns_sd.TXTRecordDeallocate(5) - }, 'illegal argument must throw'); - - t.throws(function() { dns_sd.TXTRecordSetValue()}, - 'TXTRecordSetValue() must throw when called without arguments'); - t.throws(function() { dns_sd.TXTRecordSetValue(5, null, null)}, - 'TXTRecordSetValue() must throw when called with non TXTRecordRef object'); - t.throws(function() { dns_sd.TXTRecordSetValue({not_a_txt_record: true}, null, null)}, - 'TXTRecordSetValue() must throw when called with non TXTRecordRef object'); - t.throws(function() { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), {not_a_string: true}, null) - }, 'TXTRecordSetValue() must throw when called with non TXTRecordRef object'); - - // XXX avahi doesn't like these. replace with real tests when txt records are - // implemented in javascript - try { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 'foo', null); - t.doesNotThrow(function() { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 'foo', null) - }, 'TXTRecordSetValue() must not throw when called with null value'); - } catch (ex) { - console.log("[SKIPPED] avahi doesn't support null values"); - } - try { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 'foo', undefined); - t.doesNotThrow(function() { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 'foo', undefined) - }, 'TXTRecordSetValue() must not throw when called with undefined value'); - } catch (ex) { - console.log("[SKIPPED] avahi doesn't support undefined values"); - } - t.throws(function() { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 5, undefined) - }, 'TXTRecordSetValue() must throw when called with non string key'); - t.throws(function() { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 'foo', 5) - }, 'TXTRecordSetValue() must throw when called with strange value'); - t.throws(function() { - dns_sd.TXTRecordSetValue(new dns_sd.TXTRecordRef(), 'illeagal=key', 'bar') - }, 'TXTRecordSetValue() must throw when called with strange value'); - - t.throws(function() { dns_sd.TXTRecordGetLength() }, - 'not enough arguments must throw'); - t.throws(function() { dns_sd.TXTRecordGetLength(5) }, - 'illegal arguments must throw'); - t.throws(function() { dns_sd.TXTRecordGetLength({not_a_buffer: true}) }, - 'illegal arguments must throw'); - - t.doesNotThrow(function() { dns_sd.TXTRecordDeallocate( txtRecord ); }, - 'deallocating a txtRecord must not throw'); - t.throws(function() { dns_sd.TXTRecordDeallocate(); }, - 'TXTRecordDeallocate() must throw when called without arguments'); - t.throws(function() { dns_sd.TXTRecordDeallocate(null, null); }, - 'TXTRecordDeallocate() must throw when called with more than one argument'); - - t.throws(function() { dns_sd.txtRecordBufferToObject(); }, - 'txtRecordBufferToObject() must throw when called with no arguments'); - - t.throws(function() { dns_sd.txtRecordBufferToObject(5); }, - 'txtRecordBufferToObject() must throw when called with a non-object'); - - t.throws(function() { dns_sd.txtRecordBufferToObject({not_a_txt_record_ref: true}); }, - 'txtRecordBufferToObject() must throw when called with strange objects'); - - t.done(); -} - -//=== buildException ========================================================== - -exports['buildException()'] = function(t) { - t.strictEqual(dns_sd.buildException(dns_sd.kDNSServiceErr_NoError), undefined, - 'buildException(kDNSServiceErr_NoError) must return undefined'); - - var ex = dns_sd.buildException(dns_sd.kDNSServiceErr_Unknown); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_Unknwon) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_Unknown); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NoSuchName); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NoSuchName) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NoSuchName); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NoMemory); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NoMemory) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NoMemory); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_BadParam); - t.ok(ex instanceof Error, - 'buildException() must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_BadParam); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_BadReference); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_BadReference) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_BadReference); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_BadState); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_BadState) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_BadState); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_BadFlags); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_BadFlags) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_BadFlags); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_Unsupported); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_Unsupported) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_Unsupported); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NotInitialized); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NotInitialized) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NotInitialized); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_AlreadyRegistered); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_AlreadyRegistered) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_AlreadyRegistered); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NameConflict); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NameConflict) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NameConflict); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_Invalid); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_Invalid) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_Invalid); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_Firewall); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_Firewall) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_Firewall); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_Incompatible); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_Incompatible) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_Incompatible); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_BadInterfaceIndex); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_BadInterfaceIndex) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_BadInterfaceIndex); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_Refused); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_Refused) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_Refused); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NoSuchRecord); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NoSuchRecord) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NoSuchRecord); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NoAuth); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NoAuth) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NoAuth); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NoSuchKey); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NoSuchKey) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NoSuchKey); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_NATTraversal); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_NATTraversal) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_NATTraversal); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_DoubleNAT); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_DoubleNAT) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_DoubleNAT); - - ex = dns_sd.buildException(dns_sd.kDNSServiceErr_BadTime); - t.ok(ex instanceof Error, - 'buildException(kDNSServiceErr_BadTime) must return an Error object'); - t.strictEqual( ex.errorCode, dns_sd.kDNSServiceErr_BadTime); - - t.throws(function() { dns_sd.buildException() }, - 'not enough arguments'); - t.throws(function() { dns_sd.buildException('foobar') }, - 'argument must be a string'); - t.done(); -} - -exports['exportConstants()'] = function(t) { - var o = {} - dns_sd.exportConstants(o); - t.ok(o.kDNSServiceErr_BadParam); - - t.throws(function() { dns_sd.exportConstants() }); - t.throws(function() { dns_sd.exportConstants(5) }); - - t.done(); -} - -// vim: filetype=javascript: diff --git a/lib/jdiscovery/mdns/tests/test_functional.js b/lib/jdiscovery/mdns/tests/test_functional.js deleted file mode 100755 index 49accf54..00000000 --- a/lib/jdiscovery/mdns/tests/test_functional.js +++ /dev/null @@ -1,501 +0,0 @@ -#!/usr/bin/env node - -var mdns_test = require('../utils/lib/mdns_test') - , mdns = mdns_test.require('mdns') - , nif = require('../lib/network_interface.js') - , os = require('os') - ; - -exports['simple browsing'] = function(t) { - var timeout = 5000 - , port = 4321 - , service_type = mdns_test.suffixedServiceType('node-mdns', 'tcp'); - ; - - var timeoutId = setTimeout(function() { - t.fail("test did not finish within " + (timeout / 1000) + " seconds."); - t.done(); - }, timeout) - - var browser = mdns.createBrowser(service_type, {context: {some: 'context'}}); - - function stopBrowserIfDone() { - if (upCount > 0 && - downCount > 0 && - upCount == downCount && - changedCount == upCount + downCount) - { - browser.stop(); - clearTimeout(timeoutId); - t.done(); - } - } - - var changedCount = 0; - browser.on('serviceChanged', function(service, ctx) { - //console.log("changed:", service); - t.strictEqual(typeof service.flags, 'number', - "'flags' must be a number"); - if (changedCount === 0) { - t.ok(service.flags & mdns.kDNSServiceFlagsAdd, - "'flags' must have kDNSServiceFlagsAdd set"); - t.strictEqual(typeof service.fullname, 'string', - "'fullname' must be a string"); - t.strictEqual(typeof service.host, 'string', - "'host' must be a string"); - t.strictEqual(typeof service.port, 'number', - "'port' must be a number"); - t.strictEqual(service.port, port, - "'port' must match the advertisement"); - - t.ok('addresses' in service, - "'service' must have a address property"); - t.ok(Array.isArray(service.addresses), - "'addresses' must be an array"); - t.ok(service.addresses.length > 0, - "addresses must not be empty"); - } - t.strictEqual(typeof service.interfaceIndex, 'number', - "'interfaceIndex' must be a number"); - t.strictEqual(typeof service.name, 'string', - "'name' must be a string"); - t.ok(service.type instanceof mdns.ServiceType, - "'type' must be a service type object"); - t.strictEqual('' + service.type, service_type + '.', - "type must match the target type"); - t.strictEqual(typeof service.replyDomain, 'string', - "'replyDomain' must be a string"); - t.strictEqual(service.replyDomain, 'local.', - "'replyDomain' must match 'local.'"); - - t.strictEqual(typeof service.networkInterface, 'string', - 'must have a networkInterface'); - - t.ok(ctx, 'must have context'); - t.strictEqual(ctx.some, 'context', 'property must match input'); - - changedCount += 1; - stopBrowserIfDone(); - }); - - var upCount = 0; - browser.on('serviceUp', function(service, ctx) { - //console.log("up:", service); - t.strictEqual(typeof service.flags, 'number', - "'flags' must be a number"); - t.strictEqual(typeof service.interfaceIndex, 'number', - "'interfaceIndex' must be a number"); - t.strictEqual(typeof service.name, 'string', - "'name' must be a string"); - t.ok(service.type instanceof mdns.ServiceType, - "'type' must be ServiceType object"); - t.strictEqual('' + service.type, service_type + '.', - "'type' must match target type"); - t.strictEqual(typeof service.replyDomain, 'string', - "'replyDomain' must be a string"); - t.strictEqual(service.replyDomain, 'local.', - "'replyDomain' must match 'local.'"); - - t.strictEqual(typeof service.fullname, 'string', - "'fullname' must be a string"); - t.strictEqual(typeof service.host, 'string', - "'host' must be a string"); - t.strictEqual(typeof service.port, 'number', - "'port' must be a number"); - t.strictEqual(service.port, port, - "'port' must match"); - - t.ok('addresses' in service, - "'service' must have a addresses property"); - t.ok(Array.isArray(service.addresses), - "'addresses' must be a string"); - t.ok(service.addresses.length > 0, - "'addresses' must not be empty"); - - t.ok('rawTxtRecord' in service, - "'service' must have a rawTxtRecord property"); - t.ok(service.rawTxtRecord, - "'rawTxtRecord' must be truthy"); - t.ok(service.txtRecord, - "'txtRecord' must be truthy"); - - t.strictEqual(typeof service.networkInterface, 'string', - 'must have a networkInterface'); - - var p; - for (p in txt_record) { - t.strictEqual('' + txt_record[p], service.txtRecord[p], - "property " + p + " in txtRecord must match"); - } - - t.ok(ctx, 'must have context'); - t.strictEqual(ctx.some, 'context', 'property must match input'); - - upCount += 1; - stopBrowserIfDone(); - }); - - var downCount = 0; - browser.on('serviceDown', function(service, ctx) { - t.strictEqual(typeof service.flags, 'number', - "'flags' must be a number"); - t.strictEqual(typeof service.interfaceIndex, 'number', - "'interfaceIndex' must be a number"); - t.strictEqual(typeof service.name, 'string', - "'name' must be a string"); - t.ok(service.type instanceof mdns.ServiceType, - "'type' must be a ServiceType object"); - t.strictEqual('' + service.type, service_type + '.', - "'type' must match target aervice type"); - t.strictEqual(typeof service.replyDomain, 'string', - "'replyDomain' must be a string"); - t.strictEqual(service.replyDomain, 'local.', - "'replyDomain' must match 'local.'"); - - t.strictEqual(typeof service.networkInterface, 'string', - 'must have a networkInterface'); - - t.ok(ctx, 'must have context'); - t.strictEqual(ctx.some, 'context', 'property must match input'); - - downCount += 1; - stopBrowserIfDone(); - }); - - browser.start(); - - var txt_record = {type: 'bacon', chunky: true, strips: 5, buffer: new Buffer('raw')} - , ad = mdns.createAdvertisement(service_type, port, - {txtRecord: txt_record}, function(err, service, flags) { - if (err) throw err; - setTimeout(function() { ad.stop() }, 500); - }); - - ad.start(); -} - -exports['create ads'] = function(t) { - var timeout = 500 // ms - , counter = 0 - ; - - function stopIfDone() { - if (++counter === 4) { - t.done(); - } - } - var ad1 = mdns.createAdvertisement(['mdns-test1', 'tcp'], 4321); - ad1.start(); - setTimeout(function() { ad1.stop(); stopIfDone(); }, timeout); - - var ad2 = mdns.createAdvertisement(['mdns-test2', 'tcp'], 4322, {}); - ad2.start(); - setTimeout(function() { ad2.stop(); stopIfDone(); }, timeout); - - function checkAd(service, name, proto) { - t.ok('flags' in service, - "service must have a flags property"); - t.strictEqual(typeof service.flags, 'number', - "'flags' must be a number"); - t.ok(service.type instanceof mdns.ServiceType, - "'type' must be a ServiceType object"); - t.strictEqual(service.type.toString(), '_' + name + '._' + proto + '.', - "'type' must be as advertised"); - } - - var ad3 = mdns.createAdvertisement(['mdns-test3', 'tcp'], 4323, {name: 'foobar'}, function(error, service) { - if (error) t.fail(error); - - checkAd(service, 'mdns-test3', 'tcp'); - - var ad = this; - setTimeout(function(){ ad.stop(); stopIfDone(); }, timeout); - }); - ad3.start(); - - var ad4 = mdns.createAdvertisement(['mdns-test4', 'udp'], 4324, {}, function(error, service) { - if (error) t.fail(error); - - checkAd(service, 'mdns-test4', 'udp'); - - var ad = this; - setTimeout(function(){ ad.stop(); stopIfDone(); }, timeout); - }); - ad4.start(); - -} - -exports['update ad record'] = function(t) { - var timeout = 10000 - , port = 4321 - , service_type = mdns_test.suffixedServiceType('test-adu', 'tcp') - , registered = false - , updated = false - ; - - var timeoutId = setTimeout(function() { - t.fail("test did not finish within " + (timeout / 1000) + " seconds."); - browser.stop(); - browser2.stop(); - ad.stop(); - t.done(); - }, timeout) - - var browser = mdns.createBrowser(service_type, {context: {some: 'context'}}); - var browser2 = mdns.createBrowser(service_type, {context: {some: 'context'}}); - - function stopBrowserIfDone() { - if (changedCount == 2 && updated) - { - browser.stop(); - browser2.stop(); - ad.stop(); - clearTimeout(timeoutId); - t.done(); - } - } - - function browserOnServiceChanged(service, ctx) { - t.ok('rawTxtRecord' in service, - "'service' must have a rawTxtRecord property"); - t.ok(service.rawTxtRecord, - "'rawTxtRecord' must be truthy"); - t.ok(service.txtRecord, - "'txtRecord' must be truthy"); - - if (changedCount === 0) { - t.strictEqual(service.txtRecord['value'], '1', - "'txtRecord' doesn\'t match"); - changedCount += 1; - browser.stop(); - } else { - if(updated) { - changedCount += 1; - t.strictEqual(service.txtRecord['value'], '2', - "'txtRecord' doesn\'t match"); - } - } - - stopBrowserIfDone(); - } - - var changedCount = 0; - browser.on('serviceChanged', browserOnServiceChanged); - browser2.on('serviceChanged', browserOnServiceChanged); - - browser.start(); - - var ad = mdns.createAdvertisement(service_type, port, {name: 'foobar', txtRecord: {value: '1'}}, function(error, service) { - if (error) t.fail(error); - if (registered === false) { - registered = true; - setTimeout(function(){ - if (ad.serviceRef !== null) { - ad.updateTXTRecord({value: '2'}); - updated = true; - setTimeout(function(){browser2.start();}, 3000); - } - }, 1000); - } - }); - ad.start(); -} - -exports['browseThemAll()'] = function(t) { - var browser = new mdns.browseThemAll() - , up = 0 - , down = 0 - , changed = 0 - , type = mdns_test.suffixedServiceType('node-mdns', 'udp') - ; - - // XXX - console.log('[SKIPPED] write better test for browseThemAll()'); - t.done(); - return; // XXX - - browser.on('serviceUp', function(service) { - if (type.matches(service.type)) { - ++up; - } - }); - browser.on('serviceDown', function(service) { - if (type.matches(service.type)) { - ++down; - } - }); - browser.on('serviceChanged', function(service) { - if (type.matches(service.type)) { - ++changed; - } - }); - - // it takes forever until the service type disappears - var cooltime = 15000; - var timeoutId = setTimeout(cooltime + 5000, function() { - t.ok(false, "test did not finish"); - t.done(); - }); - var ad = mdns_test.runTestAd(type, 1337, 2000, cooltime, function() { - //t.strictEqual(down, up, 'up count must match down count'); - //t.strictEqual(down + up, changed, 'up plus down must equal changed count'); - console.log('[SKIPPED] write better test for browseThemAll()') - browser.stop(); - clearTimeout(timeoutId); - t.done(); - }); - - browser.start(); -} - -exports['resolver sequence'] = function(t) { - var type = mdns_test.suffixedServiceType('node-mdns', 'tcp') - , browser = new mdns.createBrowser(type, {resolverSequence: []}) - , rst = mdns.rst - ; - - browser.on('serviceUp', function(service) { - t.ok( ! ('host' in service), - "service must not have a 'host' property"); - t.ok( ! ('port' in service), - "service must not have a 'port' property"); - t.ok( ! ('fullname' in service), - "service must not have a 'fullname' property"); - t.ok( ! ('addresses' in service), - "service must not have an 'addresses' property"); - - var result_count = 0; - function done() { - if (++result_count === 3) { - t.done(); - } - } - var s1 = clone(service); - mdns.resolve(s1, function(error, service) { - //console.log('default resolve:', error, service); - if (error) throw error; - t.ok('host' in service, - "service must have a 'host' property"); - t.ok('port' in service, - "service must have a 'port' property"); - t.ok('fullname' in service, - "service must have a 'fullname' property"); - t.ok('addresses' in service, - "service must have an 'addresses' property"); - done(); - }); - - var s2 = clone(service); - var seq2 = [rst.DNSServiceResolve(), rst.getaddrinfo()]; - mdns.resolve(s2, seq2, function(error, service) { - //console.log('getaddrinfo resolve:', error, service); - if (error) throw error; - t.ok('host' in service, - "service must have a 'host' property"); - t.ok('port' in service, - "service must have a 'port' property"); - t.ok('fullname' in service, - "service must have a 'fullname' property"); - t.ok('addresses' in service, - "service must have an 'addresses' property"); - done(); - }); - - var s3 = clone(service); - var seq3 = [rst.DNSServiceResolve()]; - mdns.resolve(s3, seq3, function(error, service) { - //console.log('resolve (no addresses):', error, service); - if (error) throw error; - t.ok('host' in service, - "service must have a 'host' property"); - t.ok('port' in service, - "service must have a 'port' property"); - t.ok('fullname' in service, - "service must have a 'fullname' property"); - t.ok( ! ('addresses' in service), - "service must not have an 'addresses' property"); - done(); - }); - - browser.stop(); - }); - - var ad = mdns_test.runTestAd(type, 1337, 1000, function() {}); - - browser.start(); - - function clone(o) { - var clone = {}, p; - for (p in o) { - clone[p] = o[p]; - } - return clone; - } -} - -exports['local advertisement invisible on external interfaces'] = function(t) { - var st = mdns.tcp('local-ad') - , exif = someExternalInterface() - , avahi = require('../lib/avahi') - ; - if (avahi) { - console.log('[SKIPPED] avahi does not support local only operation'); - t.done(); - return; - } - if ( ! exif) { - console.log('[SKIPPED] failed to find an external network interface'); - t.done(); - return; - } - var ad = mdns.createAdvertisement(st, 4321, - {networkInterface: mdns.loopbackInterface()}) - , externalBrowser = mdns.createBrowser(st, {networkInterface: exif}) - , externalBrowserEvents = 0 - ; - externalBrowser.on('serviceUp', function(service) { - externalBrowserEvents++; - }); - externalBrowser.on('serviceDown', function(service) { - externalBrowserEvents++; - }); - var loopbackBrowser = mdns.createBrowser(st, - {networkInterface: mdns.loopbackInterface()}); - loopbackBrowser.on('serviceUp', function(service) { - t.strictEqual(service.interfaceIndex, mdns.loopbackInterface(), - 'service must have the loopback interface index'); - t.strictEqual(service.networkInterface, nif.loopbackName(), - 'service must have the loopback interface name'); - setTimeout(function() { ad.stop() }, 1000); - }); - loopbackBrowser.on('serviceDown', function(service) { - t.strictEqual(service.interfaceIndex, mdns.loopbackInterface(), - 'service must have the loopback interface index'); - t.strictEqual(service.networkInterface, nif.loopbackName(), - 'service must have the loopback interface name'); - setTimeout(function() { - t.strictEqual(externalBrowserEvents, 0, - 'browser on external interface must not receive events'); - externalBrowser.stop(); - loopbackBrowser.stop(); - t.done(); - }, 1000); - }); - externalBrowser.start(); - loopbackBrowser.start(); - ad.start(); -} - -function someExternalInterface() { - var ifaces = os.networkInterfaces() - , loopback = nif.loopbackName() - ; - for (var name in ifaces) { - if (name !== loopback) { - return name; - } - } - throw new Error('failed to find an external network interface'); -} - -// vim: filetype=javascript : diff --git a/lib/jdiscovery/mdns/tests/test_mdns_service.js b/lib/jdiscovery/mdns/tests/test_mdns_service.js deleted file mode 100644 index 746a5c67..00000000 --- a/lib/jdiscovery/mdns/tests/test_mdns_service.js +++ /dev/null @@ -1,29 +0,0 @@ -var dns_sd = require('../lib/dns_sd') - , proxyquire = require('proxyquire') - ; - -//=== MDNSService =========================================================== - -module.exports["MDNSService"] = { - "DNS errors should propagate": function(test) { - var message = "Panic!" - var mock_dns_sd = { - DNSServiceProcessResult: function() { - throw new Error(message); - } - }; - - var MDNSService = proxyquire("../lib/mdns_service.js", { "./dns_sd": mock_dns_sd }).MDNSService; - - var service = new MDNSService(); - service.on("error", function(error) { - test.equal(message, error.message); - - test.done(); - }); - service.watcher.start = function() { - process.nextTick(this.callback.bind(null)); - } - service.start(); - } -} diff --git a/lib/jdiscovery/mdns/tests/test_network_interface.js b/lib/jdiscovery/mdns/tests/test_network_interface.js deleted file mode 100644 index 5228fc17..00000000 --- a/lib/jdiscovery/mdns/tests/test_network_interface.js +++ /dev/null @@ -1,55 +0,0 @@ -var os = require('os') - , mdns_test = require('../utils/lib/mdns_test') - , dns_sd = require('../lib/dns_sd.js') - , nif = require('../lib/network_interface.js'); - ; - -function loopback() { - var interfaces = os.networkInterfaces(); - for (var name in interfaces) { - for (var i = 0; i < interfaces[name].length; ++i) { - if (interfaces[name][i].address === '127.0.0.1') { - return name; - } - } - } - throw new Error('failed to find loopback interface'); -} - -var have_if_nametoindex = typeof dns_sd.if_nametoindex !== 'undefined'; - -exports['if_nametoindex <-> if_indextoname'] = function(t) { - if (have_if_nametoindex) { - var interfaces = os.networkInterfaces(); - for (var name in interfaces) { - var index = dns_sd.if_nametoindex(name); - t.ok( index > 0); - t.strictEqual( dns_sd.if_indextoname(index), name); - } - } else { - console.log('[SKIPPED] if_nametoindex() not supported on this platform'); - } - t.done(); -} - -exports['interfaceIndex'] = function(t) { - t.strictEqual(nif.interfaceIndex({interfaceIndex: 0}), 0); - t.strictEqual(nif.interfaceIndex({interfaceIndex: 1}), 1); - - t.strictEqual(nif.interfaceIndex({networkInterface: 0}), 0); - - t.strictEqual(nif.interfaceIndex({}), 0); - - if (have_if_nametoindex) { - t.ok(nif.interfaceIndex({networkInterface: loopback()}) > 0); - t.ok(nif.interfaceIndex({networkInterface: '127.0.0.1'}) > 0); - - t.strictEqual(nif.interfaceIndex({networkInterface: loopback()}), - nif.interfaceIndex({networkInterface: '127.0.0.1'})); - } else { - console.log('[SKIPPED] if_nametoindex() not supported on this platform'); - } - - - t.done(); -} diff --git a/lib/jdiscovery/mdns/tests/test_odd_ends.js b/lib/jdiscovery/mdns/tests/test_odd_ends.js deleted file mode 100644 index b8e3e784..00000000 --- a/lib/jdiscovery/mdns/tests/test_odd_ends.js +++ /dev/null @@ -1,27 +0,0 @@ -var mdns_test = require('../utils/lib/mdns_test') - , mdns = mdns_test.require('mdns') - ; - -//=== DNSServiceRef =========================================================== - -exports['DNSServiceEnumerateDomains'] = function(t) { - var enumerator = new mdns.MDNSService(); - var timeout = setTimeout(function() { - console.log('[SKIPPED] probably running on ahavi'); - enumerator.stop(); - t.done() - }, 10000); - function on_enum(sref, flags, iface, error, domain, context) { - t.strictEqual(error, mdns.kDNSServiceErr_NoError, "error must be NoError"); - t.strictEqual(typeof flags, 'number', "'flags' must be of type number"); - t.strictEqual(typeof iface, 'number', "'iface' must be of type number"); - - enumerator.stop(); - clearTimeout(timeout); - t.done(); - } - mdns.dns_sd.DNSServiceEnumerateDomains(enumerator.serviceRef, - mdns.kDNSServiceFlagsBrowseDomains, 0, on_enum, {some: 'context'}); - enumerator.start(); -} - diff --git a/lib/jdiscovery/mdns/tests/test_service_type.js b/lib/jdiscovery/mdns/tests/test_service_type.js deleted file mode 100644 index 69e57152..00000000 --- a/lib/jdiscovery/mdns/tests/test_service_type.js +++ /dev/null @@ -1,101 +0,0 @@ -var mdns_test = require('../utils/lib/mdns_test') - , mdns = mdns_test.require('mdns') - ; - -exports['protocol helpers'] = function(t) { - t.strictEqual( mdns.udp('osc').toString(), '_osc._udp', - 'comparing simple udp service type'); - - t.strictEqual( mdns.tcp('http', 'blogapi').toString(), '_http._tcp,_blogapi', - 'comparing tcp service type with subtype'); - t.strictEqual( mdns.tcp('http', 'blogapi', 'newblogapi').toString(), - '_http._tcp,_blogapi,_newblogapi', - 'comparing tcp service types with two subtypes'); - - t.done(); -} - -function compareServiceType() { - var args = Array.prototype.slice.call(arguments) - , t = args.shift() - , msg = args.pop() - , str = args.pop() - , type = mdns.makeServiceType.apply(this, args) - ; - t.strictEqual(type.toString(), str, msg); -} - -var http_type = '_http._tcp,_foo,_bar'; - -exports['makeServiceType()'] = function(t) { - - compareServiceType(t, http_type, http_type, - 'construct from string form'); - compareServiceType(t, 'http', 'tcp', 'foo', 'bar', http_type, - 'construct from tokens'); - compareServiceType(t, '_http', '_tcp', '_foo', '_bar', http_type, - 'construct from tokens with underscores'); - compareServiceType(t, ['http', 'tcp', 'foo', 'bar'], http_type, - 'construct from array'); - compareServiceType(t, mdns.tcp('http', 'foo', 'bar'), http_type, - 'construct with protocol helper'); - compareServiceType(t, - { name: 'http' - , protocol: 'tcp' - , subtypes: ['foo', 'bar'] - } - , http_type, - 'construct from object (json)'); - - t.done(); -} - - -exports['json round-trip'] = function(t) { - compareServiceType(t, mdns.makeServiceType( - JSON.parse(JSON.stringify(mdns.makeServiceType(http_type)))) - , http_type, - 'construct from result of JSON.parse(JSON.stringify(...))'); - - t.done(); -} - -exports['ServiceType() constructor'] = function(t) { - compareServiceType(t, new mdns.ServiceType('http', 'tcp', 'foo', 'bar'), http_type, - 'construct from tokens'); - compareServiceType(t, new mdns.ServiceType(['http', 'tcp', 'foo', 'bar']), http_type, - 'construct from array'); - compareServiceType(t, new mdns.ServiceType({name: 'http', protocol: 'tcp', subtypes: ['foo', 'bar']}), http_type, - 'construct from object'); - - t.done(); -} - -exports['illegal arguments'] = function(t) { - t.throws(function() { mdns.tcp('abcdefghijklmnopq') }, - 'service type to long'); - t.throws(function() { mdns.tcp('abc%') }, - 'illegal characters in primary type'); - t.throws(function() { mdns.tcp('abc', 'abcdefghijklmnopq') }, - 'subtype to long'); - t.throws(function() { mdns.tcp('abc', '%$@') }, - 'illegal characters in subtype'); - t.throws(function() { mdns.tcp('abc', 'def', 'foo_bar') }, - 'illegal chars in subtype'); - - t.throws(function() { mdns.tcp('abc', 'tcp', 'foo') }, - 'type token already present'); - - t.throws(function() { mdns.makeServiceType({}) }, - 'missing properties'); - t.throws(function() { mdns.makeServiceType({name: 'foo', protocol: 'bar'}) }, - 'illegal protocol'); - t.throws(function() { mdns.makeServiceType(5) }, - 'attempt to construct from number'); - t.throws(function() { mdns.tcp('') }, - 'aatempt to construct with an empty string'); - - t.done(); -} - -// vim: filetype=javascript: diff --git a/lib/jdiscovery/mdns/utils/coverage b/lib/jdiscovery/mdns/utils/coverage deleted file mode 100755 index fc4badf1..00000000 --- a/lib/jdiscovery/mdns/utils/coverage +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env node - -var input = ''; - -process.stdin.on('data', function(chunk) { - input += chunk; -}) - -function p() { return Array.prototype.join.call(arguments, '.') } - -process.stdin.on('end', function() { - input.split('\n').forEach(function(l) { - var match = l.match(/^\s+([^.]+)\.+: ([0-9.]+)% \(([0-9]+) of ([0-9]+) .*$/); - if (match) { - var what = match[1] - , percent = match[2] - , covered = match[3] - , total = match[4] - ; - console.log(p(what, 'percent', 'covered'), '=', percent); - console.log(p(what, 'percent', 'missed'), '=', 100 - percent); - console.log(p(what, 'covered'), '=', covered); - console.log(p(what, 'missed'), '=', total - covered); - console.log(p(what, 'total'), '=', total); - } - }) -}); - -process.stdin.resume(); diff --git a/lib/jdiscovery/mdns/utils/docpack b/lib/jdiscovery/mdns/utils/docpack deleted file mode 100755 index 572d8000..00000000 --- a/lib/jdiscovery/mdns/utils/docpack +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env node - -// docpack - documentation for take-away -// disgusting ... but works for now ... - -var path = require('path') - , fs = require('fs') - , child_process = require('child_process') - , slide = require('slide') - , mkdirp = require('mkdirp') - , glob = require('glob') - , ejs = require('ejs') - , less = require('less') - , ncp = require('ncp').ncp - , view = require('./lib/view') - , obj = require('./lib/obj') - , j = path.join - , chain = slide.chain - , compiler = require('./lib/compiler') - ; - -var rootd = path.resolve(path.dirname(process.argv[1]), '..') - , docd = rootd + '/doc' - , outd = rootd + '/build/pages' - , package = JSON.parse(fs.readFileSync(rootd + '/package.json')) - , layout = fs.readFileSync(docd + '/layout.ejs').toString() - ; - -var ejs2textile = compiler.compilerSync(ejs.render, 'ejs', {package: package}) - , ejs2html = compiler.compiler(render_page, 'redcloth', {dst: compiler.dst, outputDir: outd}) - , less2css = compiler.compiler(less.render, 'less') - ; - -var prepare = [ [ mkdirp, outd ] - ] - , tasks = [ [ ejs2textile, docd + '/README.ejs', rootd + '/README.textile'] - , [ render_pages, docd + '/pages/*.ejs'] - , [ render_build_status_pages ] - , [ render_stylesheets, docd + '/pages/stylesheets/*.less'] - , [ ncp, docd + '/pages/images', outd + '/images'] - , [ ncp, docd + '/pages/scripts', outd + '/scripts'] - , [ ncp, docd + '/pages/jqplot', outd + '/jqplot'] - ] - ; - -chain( [ [ run_all, prepare] - , [ run_all, tasks] - ] - , function(error) { if (error) console.log(error) } - ); - - - -function render_pages(pattern, cb) { - glob(pattern, function(error, files) { - var tasks = files.map(function(f) { - var dst = path.join(outd, path.basename(path.basename(f), '.ejs')) - + '.html'; - return [ejs2html, f, dst] - }); - run_all(tasks, cb); - }); -} - -function render_stylesheets(pattern, cb) { - glob(pattern, function(error, files) { - var tasks = files.map(function(f) { - var dst = outd + '/stylesheets/' - + path.basename(path.basename(f), '.less') + '.css'; - return [less2css, f, dst, {}] - }); - run_all(tasks, cb); - }); -} - -function render_page(source, options, cb) { - var metadata = { scripts: [], stylesheets: ['/stylesheets/mdns.css']}; - function layout_page(error, html) { - metadata.body = html; - cb(error, ejs.render(layout, obj.union(metadata, view.helpers(metadata, options)))) - } - var locals = obj.union({package: package}, view.helpers(metadata, options)); - piped_comand('redcloth', ejs.render(source, locals), layout_page); -} - -function render_build_status_pages(cb) { - cb() -} - -function piped_comand(comand, input, args, cb) { - if ( ! cb ) { - cb = args; - args = undefined; - } - var cmd = child_process.spawn(comand, args) - , out = '' - ; - cmd.stdout.on('data', function(chunk) { out += chunk }) - cmd.stderr.on('data', function(chunk) { console.log(chunk)}) - cmd.on('exit', function(code) { - if (code) { - cb(new Error("command '" + command + "' exited with code " + code)) - } else { - cb(null, out) - } - }); - cmd.stdin.write(input); - cmd.stdin.destroySoon(); - -} - - -function run_all(tasks, cb) { - var done_count = 0, first_error; - function on_done(error) { - if (error) { - first_error = error; - cb(error); - } - if ( ! first_error && ++done_count === tasks.length) cb(); - } - tasks.forEach(function(t) { - var f = t.shift(); - t.push(on_done) - f.apply(null, t); - }); -} - -// vim: filetype=javascript : diff --git a/lib/jdiscovery/mdns/utils/jsf b/lib/jdiscovery/mdns/utils/jsf deleted file mode 100755 index 23088267..00000000 --- a/lib/jdiscovery/mdns/utils/jsf +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env node - -var path = require('path') - , fs = require('fs') - , slide = require('slide') - , mkdirp = require('mkdirp') - , chain = slide.chain - - , outd = process.argv.pop() - , build_type = process.env.BUILDTYPE - ; - -//console.log(process.env); - -function copy(f, cb) { - var target = path.join(outd, path.basename(f)) - , readStream = fs.createReadStream(f) - ; - console.log(' COPY', target); - readStream.pipe(fs.createWriteStream(target)); - readStream.once('end', cb); -} - -function copyFiles(files, cb) { - slide.asyncMap(files, copy, cb); -} - -function jscoverage(files, cb) { - var just_do_it_kthxbye = path.join(outd, 'jscoverage.html') - chain( [ [ fs.writeFile, just_do_it_kthxbye, '' ] - , [ run_jscoverage, files] - , [ fs.unlink, just_do_it_kthxbye] - ] - , cb - ) -} - -function run_jscoverage(files, cb) { - var spawn = require('child_process').spawn - , cmd = process.env.JSCOVERAGE || 'jscoverage' - , src_dir = path.dirname(files[0]) - , jsc = spawn(cmd, [src_dir, outd, '-v', '--no-highlight']) - ; - function log(d) { console.log(d.toString()) } - jsc.stdout.on('data', log); - jsc.stderr.on('data', log); - jsc.on('exit', function(code) { - if (code) { - cb(new Error('jscoverage exited with code ' + code)) - } else { - cb(); - } - }) -} - -var op = build_type === 'Coverage' ? jscoverage : copyFiles - -chain( [ [ mkdirp, outd ] - , [ op, process.argv.slice(2) ] - ] - , function(error) { if (error) { console.log(error); process.exit(1) } } - ) -// vim: set filetype=javascript : diff --git a/lib/jdiscovery/mdns/utils/lib/actors.js b/lib/jdiscovery/mdns/utils/lib/actors.js deleted file mode 100644 index 7b7040dd..00000000 --- a/lib/jdiscovery/mdns/utils/lib/actors.js +++ /dev/null @@ -1,63 +0,0 @@ -var fs = require('fs') - , child_process = require('child_process') - , _glob = require('glob') - , bunch = require('./bunch') - ; - -exports.loadEnv = function loadEnv(env, cb) { - var loaders = [] - function load(name, cb) { - fs.readFile(env[name], function(error, data) { - env[name] = env[name].match(/.*\.json$/) ? JSON.parse(data) : data; - cb(error, data) - }) - } - for (var name in env) { - loaders.push([load, name]) - } - bunch(loaders, cb) -} - -exports.commandActor = function command(executable) { - return function command(args, opts, cb) { - if (!cb) { - cb = opts; - opts = {} - } - var cmd = child_process.spawn(executable, args, opts); - function log(b) { console.log(b.toString()) } - cmd.stdout.on('data', log); - cmd.stderr.on('data', log); - cmd.on('exit', function(code) { - if (code) { - cb(new Error(executable + ' exited with status ' + code)); - } else { - cb(); - } - }); - return cmd; - } -} - -exports.jsonParse = function(str, cb) { - try { - cb(null, JSON.parse(str)); - } catch (ex) { - cb(ex); - } -} - -exports.jsonStringify = function(obj, cb) { - try { - cb(null, JSON.stringify(obj)); - } catch (ex) { - cb(ex); - } -} -exports.glob = function glob(pattern, cb) { - console.log('pattern', pattern); - _glob(pattern, function(error, files) { - cb(error, [files]); - }); -} - diff --git a/lib/jdiscovery/mdns/utils/lib/bunch.js b/lib/jdiscovery/mdns/utils/lib/bunch.js deleted file mode 100644 index d155bc46..00000000 --- a/lib/jdiscovery/mdns/utils/lib/bunch.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = function bunch(tasks, cb) { - var count = 0, has_error; - function done(error) { - if (error) { - has_error = error; - cb(error); - } - if (++count === tasks.length && ! has_error) cb(); - } - tasks.forEach(function(t) { t[0].apply(null, t.slice(1).concat([done])) }); -} - diff --git a/lib/jdiscovery/mdns/utils/lib/compiler.js b/lib/jdiscovery/mdns/utils/lib/compiler.js deleted file mode 100644 index 7a1f3742..00000000 --- a/lib/jdiscovery/mdns/utils/lib/compiler.js +++ /dev/null @@ -1,70 +0,0 @@ - -var fs = require('fs') - , path = require('path') - , mkdirp = require('mkdirp') - , obj = require('./obj') - ; - -exports.compiler = function compiler(f, name, options) { - options = options || {}; - return function(src, dst, dynamic_options, cb) { - if ( ! cb ) { - cb = dynamic_options; - dynamic_options = {}; - } - var all_options = resolve_options(src, dst, options, dynamic_options) - fs.readFile(src, function(error, data) { - if (error) return cb(error); - f(data.toString(), all_options, function(error, result) { - if (error) { - cb(error); - } else { - mkdir_and_write_file(dst, result, cb); - } - }); - }); - } -} - -exports.compilerSync = function compilerSync(f, name, options) { - options = options || {}; - return function(src, dst, dynamic_options, cb) { - if ( ! cb ) { - cb = dynamic_options; - dynamic_options = {}; - } - console.log('[' + name + ']', dst) - var all_options = resolve_options(src, dst, options, dynamic_options) - fs.readFile(src, function(error, data) { - if (error) return cb(error); - var result = f(data.toString(), all_options); - mkdir_and_write_file(dst, result, cb); - }); - } -} - -exports.src = {}; -exports.dst = {}; - -function resolve_options(src, dst /*, options, ... */) { - var option_objects = Array.prototype.slice.call(arguments, 2) - , options = obj.union.apply(null, option_objects); - for (var opt in options) { - if (options[opt] === exports.src) { - options[opt] = src; - } else if (options[opt] === exports.dst) { - options[opt] = dst; - } - } - return options; -} - -function mkdir_and_write_file(file, content, cb) { - mkdirp(path.dirname(file), function(error) { - if (error) { - cb(error) - } else { - fs.writeFile(file, content, cb) - } - }); -} diff --git a/lib/jdiscovery/mdns/utils/lib/lcov.js b/lib/jdiscovery/mdns/utils/lib/lcov.js deleted file mode 100644 index 9e7b5b92..00000000 --- a/lib/jdiscovery/mdns/utils/lib/lcov.js +++ /dev/null @@ -1,127 +0,0 @@ - -var fs = require('fs') - ; -exports.infoFileToJson = function infoFileToJson(filename, filefilter, cb) { - var input = fs.createReadStream(filename) - var parser = new LcovLoader(filefilter) - function process_lcov_chunk(chunk) { parser.consume(chunk); } - input.on('data', process_lcov_chunk); - input.on('end', function() { - //process.stdout.write(JSON.stringify(parser.result, null, 2)); - cb(null, parser.result) - }); -} - - - -var LcovLoader = exports.LcovLoader = function LcovLoader(filefilter) { - this.tail = '' - this.result = { - files: {} - , tests: {} - , functionCount: {} - } - this.testname = ''; - this.filename = ''; - this.filefilter = filefilter || function() { return true }; -} -LcovLoader.prototype = -{ tail: '' -, result: {} -, testname: '' -, filename: '' -, filefilter: null -} - -LcovLoader.prototype.consume = function consume(chunk) { - var self = this - , lines = chunk.toString().split('\n') - ; - if (this.tail) { lines[0] = this.tail + lines[0]; } - this.tail = lines.pop() - - var testname = self.testname - , filename = self.filename - , result = self.result - , functionCount = result.functionCount - , file = result.files[filename] - , test = result.tests[filename] - , count = 0 - , warn_negative = false - ; - function consumeLine(line) { - if (line.match(/^TN:([^,]*)(,diff)?/)) { - testname = (RegExp.$1 || '') + (RegExp.$2 || ''); - if (testname) result.tests[testname] = {functionCount: {} }; - } else if (line.match(/^[SK]F:(.*)/)) { - filename = RegExp.$1; - if (self.filefilter(filename)) { - if (!result.files[filename]) result.files[filename] = {}; - file = result.files[filename]; - //console.log('file:', filename, file) - if (testname) { - if (!result.tests[testname]) result.tests[testname] = {}; - test = result.tests[testname]; - } else { - test = null; - } - } else { - file = null - } - } else if (line.match(/^DA:(\d+),(-?\d+)(,[^,\s]+)?/)) { - if (!file) { - return - } - count = parseInt(RegExp.$2) - if (count < 0) { - count = 0; - warn_negative = true; - } - if (!file.lines) file.lines = {}; - if (!file.lines[RegExp.$1]) file.lines[RegExp.$1] = 0 - file.lines[RegExp.$1] += count; - if (test) { - if (!test.lines) test.lines = {}; - if (!test.lines[RegExp.$1]) test.lines[RegExp.$1] = 0; - test.lines[RegExp.$1] += count; - } - } else if (line.match(/^FN:(\d+),([^,]+)/)) { - if (!file) { - return - } - if (!file.functions) file.functions = {}; - file.functions[RegExp.$2] = {}; - file.functions[RegExp.$2].line = parseInt(RegExp.$1); - functionCount[RegExp.$2] = 0; - if (test && ! test.functionCount[RegExp.$2]) test.functionCount[RegExp.$2] = 0 - } else if (line.match(/^FNDA:(\d+),([^,]+)/)) { - if (!file) { - return - } - functionCount[RegExp.$2] += parseInt(RegExp.$1); - } else if (line.match(/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/)) { - if (!file) { - return - } - if (!file.branches) { file.branches = {} } - var line = RegExp.$1 - , block = RegExp.$2 - , branch = RegExp.$3 - , taken = RegExp.$4 - ; - if(!file.branches[block]) {file.branches[block] = {}}; - if(!file.branches[block][branch]) {file.branches[block][branch] = 0}; - file.branches[block][branch] += parseInt(taken); - //console.log('line:', line, 'block:', block, 'branch:', branch, 'taken:', taken) - } else if (line.match(/^end_of_record/)) { - } else { - //console.log('unhandled:', line) - } - } - - lines.forEach(consumeLine); - - self.filename = filename; - self.testname = testname; -} - diff --git a/lib/jdiscovery/mdns/utils/lib/mdns_test.js b/lib/jdiscovery/mdns/utils/lib/mdns_test.js deleted file mode 100644 index 0ed156c4..00000000 --- a/lib/jdiscovery/mdns/utils/lib/mdns_test.js +++ /dev/null @@ -1,55 +0,0 @@ - -var path = require('path') - ; - - -exports.require = function _require(what) { - if (process.env.npm_config_coverage || process.env.BUILDTYPE === 'Coverage') { - return require(path.join('../../build/Coverage/lib/' + what)) - } - return require('../../lib/' + what) -} - -var mdns = exports.require('mdns'); - -var legal_chars = "abcefghijklmnopqrstuvwxyz0123456789" - -exports.suffixedServiceType = function suffixedServiceType(serviceName, protocol) { - serviceName += '-'; - while (serviceName.length < 14) { - serviceName += legal_chars[Math.floor(Math.random() * legal_chars.length)]; - } - return mdns.makeServiceType.apply(this, arguments) -} - -exports.runTestAd = function runTestAd(type, port, uptime, cooltime, cb) { - if ( ! cb ) { - cb = cooltime; - cooltime = uptime; - } - if ( ! cb) { - cb = cooltime; - uptime = cooltime = 2000; - } - var ad = new mdns.createAdvertisement(type, port, function(error, service) { - if (error) throw error; - setTimeout(function() { ad.stop(); setTimeout(cb, cooltime); }, uptime); - }); - ad.start(); - return ad; -} - -if (0) { -exports.lifeExpectancy = 5000; - -var lifeTimer; - -process.nextTick(function() { - lifeTimer = setTimeout(function() { - throw new Error("test did not finish within " + (exports.lifeExpectancy / 1000) + " seconds."); - process.exit(-1); - }, exports.lifeExpectancy); -}); - -exports.done = function done() { clearTimeout( lifeTimer ); } -} diff --git a/lib/jdiscovery/mdns/utils/lib/ncov.js b/lib/jdiscovery/mdns/utils/lib/ncov.js deleted file mode 100755 index ce7acec9..00000000 --- a/lib/jdiscovery/mdns/utils/lib/ncov.js +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env node - -var fs = require('fs') - , path = require('path') - , nopt = require('nopt') - , mm = require('minimatch') - , lcov = require('./lcov') - , slide = require('slide') - , ejs = require('ejs') - , mkdirp = require('mkdirp') - , view = require('./view') - , obj = require('./obj') - - , knownOptions = - { match : String - , template : path - } - , parsedOptions = nopt(knownOptions) - , rootd = path.resolve(__dirname, '..', '..') - ; - -var filefilter = mm.Minimatch(parsedOptions.match || rootd + '/**'); -filter = function(f) { return filefilter.match(f) }; - -var chain = slide.chain - , meta = {} - , outd = path.join(rootd, 'build') - , pagedir = path.join(outd, 'pages') - , docd = path.join(rootd, 'doc') - , lcov_info_file = path.join(outd, 'reports', 'coverage', 'cpp', 'testrun_all.info') - , json_report = path.join(outd, 'reports', 'coverage', 'testrun_coverage-cpp.json') - , prerequisites = - { layout: path.join(docd, 'layout.ejs') - , source_template: path.join(docd, 'build', 'source.ejs') - } - ; - -chain( [ [ load_prerequisites, meta, prerequisites] - , [ lcov.infoFileToJson, lcov_info_file, filter] - , [ save_json, chain.last, json_report] - , [ render_pages, chain.last] - ] - , function(error) { - console.log('done', error); - if (error) { process.exit(1) } - } - ); - -function save_json(report, file, cb) { - fs.writeFile(file, JSON.stringify(report, null, 2), function(err) { - console.log('================================================================================'); - console.log('testrun c++ coverage report saved to', file.replace(/.*\/(build\/.*)/, "$1")); - console.log('================================================================================'); - cb(err, report); - }); -} - -function render_pages(coverage, cb) { - var pages = Object.keys(coverage.files) - , stripped_names = strip_common_path(pages, 1) - , funcs = pages.map(function(p,i) { - return [render_source_page, p, stripped_names[i], coverage.files[p], coverage.functionCount, meta] - }) - ; - bunch(funcs, cb); -} - -function render_source_page(file, stripped_name, coverage, functions, meta, cb) { - var outfile = path.join(pagedir, 'coverage', stripped_name) + '.html'; - chain( [ [ fs.readFile, file ] - , [ render_source_view, chain.last, stripped_name, coverage, functions, outfile, meta ] - , [ mkdirp, path.dirname(outfile) ] - , [ fs.writeFile, outfile, chain.last ] - ] - , cb - ) -} - -function pad(n, len) { - var str = '' + n; - while (str.length < len) { str = ' ' + str } - return str -} - -function hit_counts(coverage, line_count) { - var hit_lines = []; - for (var i = 1; i <= line_count; ++i) { - if (coverage.lines[i]) { - hit_lines.push(coverage.lines[i]) - } else { - hit_lines.push(0) - } - } - var num_digits = number_of_digits( Math.max.apply(null, hit_lines)) - ; - return hit_lines.map(function(lc) { return lc ? pad(lc, num_digits) : ' ' }).join('\n') -} - -function number_of_digits(n) { return Math.ceil(Math.log(n)/Math.LN10) } - -function render_source_view(source, name, coverage, functions, dst, meta, cb) { - var lines = source.toString().split('\n') - ; - if (lines[lines.length - 1] === '') { - lines.pop() - } - - var metadata = - { stylesheets: - [ '/stylesheets/mdns.css' - , '/stylesheets/build_status.css' - ] - , scripts: [] - , title: 'Test Coverage of ' + name - }; - var locals = { lines: lines - , coverage: coverage - , path: name.split('/') - , escape: require('ejs/lib/utils').escape - , counts: found_and_hit(coverage, functions) - }; - locals = obj.union(locals, view.helpers(metadata, {outputDir: pagedir, dst: dst})); - metadata.body = ejs.render(meta.source_template.toString(), locals); - metadata.path = view.getPathHelper({outputDir: pagedir, dst: dst}); - var html = ejs.render(meta.layout.toString(), metadata); - cb(null, html); -} - -function found_and_hit(coverage, function_calls) { - var result = { lines: {found: 0, hit: 0} - , functions: {found: 0, hit: 0} - , branches: {found: 0, hit: 0} - }; - function fnh(things, out) { - for (var p in things) { - out.found += 1; - if (things[p] > 0) { - out.hit += 1; - } - } - } - fnh(coverage.lines, result.lines); - for (var f in coverage.functions) { - result.functions.found += 1; - if (function_calls[f] > 0) { - result.functions.hit += 1; - } - } - return result; -} - -function load(file, data, name, cb) { - fs.readFile(file, function(error, content) { - if (error) { cb(error); return } - data[name] = content; - cb() - }); -} - -function load_prerequisites(data, things, cb) { - var funcs = []; - for (var p in things) { - funcs.push([load, things[p], data, p]); - } - - bunch(funcs, cb); -} - - -function strip_common_path(names, keep_common) { - var paths = names.map(function(n) {return n.split('/')}) - , common_elements = 0 - , first - , all_equal = true; - ; - while (all_equal) { - first = paths[0][common_elements]; - all_equal = paths.every(function(p) { return p[common_elements] === first}); - if (all_equal) common_elements += 1; - } - common_elements -= 1; - common_elements -= keep_common; - if (common_elements < 0) { - return - } - - return paths.map(function(p) { return p.slice(common_elements).join('/') }) - -} - -function bunch(things, cb) { - var count = 0, has_error; - function done(error) { - count += 1; - if (error && ! has_error) { - has_error = error; - cb(error); - } - if ( ! has_error && count == things.length) { - cb(); - } - } - things.forEach(function(t) { t[0].apply(null, t.slice(1).concat([done])) }); -} - -// vim: filetype=javascript : diff --git a/lib/jdiscovery/mdns/utils/lib/obj.js b/lib/jdiscovery/mdns/utils/lib/obj.js deleted file mode 100644 index 8c4313ae..00000000 --- a/lib/jdiscovery/mdns/utils/lib/obj.js +++ /dev/null @@ -1,12 +0,0 @@ -exports.union = function union(/* object, object, ... */) { - if (arguments.length < 2) { - throw new Error('union() requires at least two arguments'); - } - var result = {}; - for (var i in arguments) { - for (var p in arguments[i]) { - result[p] = arguments[i][p]; - } - } - return result; -} diff --git a/lib/jdiscovery/mdns/utils/lib/view.js b/lib/jdiscovery/mdns/utils/lib/view.js deleted file mode 100644 index e070efe9..00000000 --- a/lib/jdiscovery/mdns/utils/lib/view.js +++ /dev/null @@ -1,53 +0,0 @@ - -var path = require('path') - , ejs = require('ejs') - , obj = require('./obj') - ; - -exports.make_relative = function make_relative(paths, dst, root) { - var result = []; - var r = dst.substr(0, root.length); - if ( r !== root) { - console.log('KAPUTT'); - } - dst = dst.substr(root.length) - return paths.map(function(p) { return path.relative(path.dirname(dst), p) }); -} - -var helpers = exports.helpers = function helpers(ctx, options) { - options = options || {}; - var helpers = {}; - helpers.title = function title(t) { if(t) {ctx.title = t} return ctx.title } - helpers.script = function script(s) { ctx.scripts.push(s) } - helpers.stylesheet = function stylesheet(s) { ctx.stylesheets.push(s) } - helpers.path = exports.getPathHelper(options) - return helpers; -} - -function passthrough(p) { return p } - -exports.getPathHelper = function getPathHelper(options) { - if (options.outputDir) { - return function _path(p) { - var r = options.dst.substr(0, options.outputDir.length); - if ( r !== options.outputDir) { throw new Error('KAPUTT') } - var dst = options.dst.substr(options.outputDir.length); - var relpath = path.relative(path.dirname(dst), p); - return relpath; - } - } else { - return function _path(p) { return p } - } -} - - -exports.render = function render(source, options, cb) { - var metadata = { stylesheets: [], scripts: []} - , locals = helpers(metadata, options) - ; - locals = obj.union(options.locals || {}, locals); - metadata.body = ejs.render(source, locals); - metadata.path = exports.getPathHelper(options); - var html = ejs.render(options.layout.toString(), metadata); - cb(null, html); -} diff --git a/lib/jdiscovery/mdns/utils/render_report b/lib/jdiscovery/mdns/utils/render_report deleted file mode 100755 index 97251393..00000000 --- a/lib/jdiscovery/mdns/utils/render_report +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env node - -var fs = require('fs') - , path = require('path') - , view = require('./lib/view') - , obj = require('./lib/obj') - , actors = require('./lib/actors') - , compiler = require('./lib/compiler') - , slide = require('slide') - , chain = slide.chain - , asyncMap = slide.asyncMap - ; - -var rootd = path.resolve(__dirname, '..') - , env = - { layout: rootd + '/doc/layout.ejs' - , apple_logo: rootd + '/doc/pages/images/apple_logo.svg' - , ubuntu_logo: rootd + '/doc/pages/images/ubuntu_logo.svg' - , freebsd_logo: rootd + '/doc/pages/images/freebsd_logo.svg' - , windows_logo: rootd + '/doc/pages/images/windows_logo.svg' - } - -function done() { - console.log('============= DONE ==============='); - console.log(arguments); - console.log(env); - console.log('=================================='); -} - -var render = compiler.compiler(view.render, 'ejs', env) - ; - -function configure(cb) { - env.src = compiler.src; - env.dst = compiler.dst; - env.outputDir = rootd + '/out/pages'; - cb() -}; - -var git = actors.commandActor('git'); - -console.log('rootd', rootd); - -chain( [ [ actors.loadEnv, env ] - , [ configure ] - //, [ git, ['clone', '-b', 'ci-build', 'git://github.com/agnat/node_mdns.git' - // , rootd + '/out/ci-build'] ] - , [ actors.glob, rootd + '/out/ci-build/builds/*.json' ] - , [ load_builds, chain.last ] - , [ render_status_page, chain.last] - ] - , done - ); - -function load_builds(files, cb) { - asyncMap(files, load_build, function(error, builds) { - var result = {} - builds.forEach(function(b) { result[b.id] = b; b.timestamp = parseInt(b.timestamp) }); - cb(error, result); - }); -} - -function render_status_page(builds, cb) { - var ids = Object.keys(builds).sort(function(a, b) { return b - a }) - , latest = builds[ids[0]] - , history = [] - , latest_stages = [] - , versions = {} - , os = {} - ; - for (var i = 1; i < ids.length; ++i) { - history.push(builds[ids[i]]); - } - for (var stage in latest.stages) { - var tokens = stage.split('-') - , node = tokens[0] - , build_system = tokens[2] - ; - node = node.replace(/(\d+)_(\d+)/, "$1.$2").replace(/_/, ' '); - var version = node.split(' ')[1]; - latest.stages[stage].node_version = version; - version += '-' + build_system; - latest.stages[stage].key = version; - versions[version] = {name: latest.stages[stage].node_version, sub: build_system}; - os[latest.stages[stage].os] = {name: latest.stages[stage].os}; - } - Object.keys(versions).forEach(function(v, i) { versions[v].idx = i}); - Object.keys(os).forEach(function(o, i) { os[o].idx = i; }); - var version_count = Object.keys(versions).length; - Object.keys(os).forEach(function(o,i) { - latest_stages[i] = new Array(version_count); - }); - for (var stage in latest.stages) { - var s = latest.stages[stage]; - latest_stages[versions[s.key].idx][os[s.os].idx] = s; - } - - console.log('versions:', versions, 'os:', os); - - render( rootd + '/doc/build/status.ejs' - , rootd + '/out/pages/build/status.html' - , { locals: - { latest: latest - , history: history - , latestStages: latest_stages - , versions: versions - , os: os - , logos: - { macosx: env.apple_logo - , linux: env.ubuntu_logo - , freebsd: env.freebsd_logo - , win32: env.windows_logo - } - } - } - , cb - ) -} - -function load_build(f, cb) { - fs.readFile(f, function loaded(error, buffer) { - cb(error, buffer ? JSON.parse(buffer) : buffer) - }) -} - -// vim: filetype=javascript : diff --git a/lib/jdiscovery/mdns/utils/testrun b/lib/jdiscovery/mdns/utils/testrun deleted file mode 100755 index 5f2cff98..00000000 --- a/lib/jdiscovery/mdns/utils/testrun +++ /dev/null @@ -1,301 +0,0 @@ -#!/usr/bin/env node - -process.env.AVAHI_COMPAT_NOWARN = 1 - -try { - var path = require('path') - , fs = require('fs') - , assert = require('assert') - , events = require('events') - , nopt = require('nopt') - , chain = require('slide').chain - , glob = require('glob') - , mkdirp = require('mkdirp') - ; -} catch(e) { - console.error("Failed to load dependencies. Run 'npm link' to install them."); - console.error(e); - process.exit(1); -} - -if (process.env.BUILDTYPE === 'Coverage') { - process.once('exit', function(code) { - var fs = require('fs') - , path = require('path') - , executable = path.basename(require.main.filename) - , file = path.join(process.env.NCOV_OUT, executable + '_coverage-js.json') - , dir = path.dirname(file) - , existsSync = fs.existsSync || path.existsSync - ; - if( ! existsSync(dir)) { - fs.mkdirSync(dir); - } - fs.writeFileSync(file, JSON.stringify(_$jscoverage, null, 2)); - console.log('================================================================================'); - console.log(executable, ' js coverage report saved to', file); - console.log('================================================================================'); - }) -} - -function padding(l) { - var p = '', i = 0; - for (i = 0; i < l; ++i) { p += ' ' } - return p; -} - -var DefaultFormater = function(options) { - var self = this - , max_length = 0 - ; - self.ok = options.ascii ? '[OK]' : '\u2714'; - self.failed = options.ascii ? '[FAILED]' : '\u2718'; - self.tcase_bullet = '*' - - self.groupStart = function groupStart(name, members) { - console.log(); - if (options.ascii) { - console.log('===', name); - } else { - console.log(bold(name)); - } - max_length = 0; - members.forEach(function(m) { - if (m.length > max_length) { max_length = m.length } - }); - } - this.testcaseEnd = function testcaseEnd(name, assertions, failures) { - var pad = padding(max_length - name.length); - if (options.verbose) { - console.log( self.tcase_bullet - , name - , '[' + (assertions.length - failures.length) + '/' + assertions.length + ']' - ); - - assertions.forEach(function(a) { - console.log((options.ascii ? '' : ' ') + (a.error ? self.failed : self.ok), a.message || 'MESSAGE MISSING'); - }); - } else { - console.log( failures.length === 0 ? self.ok : self.failed - , name, pad - , '[' + (assertions.length - failures.length) + '/' + assertions.length + ']' - ); - - } - failures.forEach(function(f) { - console.log(f.error.toString()); - console.log(f.error); - }); - } - this.done = function done(total, failed) { - console.log() - if (failed) { - console.log('FAILURES:', failed + '/' + total, 'assertions failed', - options.bark ? String.fromCharCode(7) : ''); - } else { - console.log('OK:', total, 'assertions'); - } - } -} - -var knownOptions = { 'bark' : Boolean - , 'format' : ['default'] - , 'ascii' : Boolean - , 'verbose' : Boolean - , 'help' : Boolean - } - , parsed = nopt(knownOptions) - , test_dir = path.join(__dirname, '..', 'tests') - ; - -if ( ! ('bark' in parsed)) { parsed.bark = true; } -var formats = { default: new DefaultFormater(parsed) }; - -process.title = path.basename(__filename); -if (parsed.help) { printHelp(); process.exit(); } - -function run_tests(files, cb) { - var reporter = new AssertRecorder() - , format = formats[parsed.format || 'default'] - ; - Object.keys(format).forEach(function(ev) { - if (typeof format[ev] === 'function') { - reporter.on(ev, format[ev]); - } - }); - - chain( [ //[glob_list, path.join(test_dir, 'test_*.js')] - , [test_list] - , [run_modules, chain.last, reporter] - , [save_reports, reporter] - ] - , function() { reporter.allDone(); cb(undefined, reporter.failedCount) } - ) -} - -function test_list(cb) { - fs.readdir(test_dir, function(error, files) { - var r = [] - , pattern = /^test_.*\.js$/ - ; - r = files . filter(function(f) { return pattern.test(f) }) - . map(function(f) { return path.join('tests', f)}) - ; - cb(error, [r]); - }) -} - - - -function glob_list(pattern, cb) { - glob(pattern, function(error, files) { - cb(error, [files]) - }); -} - -function run_modules(files, reporter, cb) { - var module_chain = files.map(function(f) { - var name = path.basename(path.basename(f), '.js'); - return [run_group, require(path.join('..', f)), name, reporter]; - }); - chain(module_chain, cb); -} - -function run_group(group, name, reporter, cb) { - var names = Object.keys(group) - , group_chain = names.map(function(test) { - return [ typeof group[test] === 'function' ? run_testcase : run_group - , group[test], test, reporter]; - }); - ; - reporter.group_start(name, names); - chain(group_chain, function(error) { - reporter.group_end(name); - cb(error); - }); -} - -var maybe_gc; -try { - maybe_gc = gc; -} catch (ex) { - maybe_gc = function() {} -} - -function run_testcase(f, name, reporter, cb) { - reporter.testcase_start(name); - reporter.done = function done() { - maybe_gc(); - reporter.testcase_end(name); - cb(); - }; - f(reporter); -} - -function save_reports(reporter, cb) { - var dir = path.join(__dirname, '..', 'out', 'reports'); - chain( [ [mkdirp, dir] - , [fs.writeFile, path.join(dir, 'tests.json'), JSON.stringify(reporter.results, null, 2)] - ] - , cb - ); -} - -var msg_indices = -{ ok: 1 -, equal: 2 -, notEqual: 2 -, deepEqual: 2 -, notDeepEqual: 2 -, strictEqual: 2 -, notStrictEqual: 2 -, throws: 1 -, doesNotThrow: 1 -}; - -function wrap_assert(name) { - var msg_idx = msg_indices[name]; - return function() { - var assertion = {test: name, message: arguments[msg_idx], error: undefined}; - try { - assert[name].apply(null, arguments); - } catch (error) { - assertion.error = error; - } - this.back().push(assertion); - } -} - -function add_assert_wrappers(t) { - var p, msg_idx; - for (p in assert) { - if (assert[p] !== assert.AssertionError) { - t[p] = wrap_assert(p); - } - } -} - -var AssertRecorder = function AssertRecorder() { - events.EventEmitter.call(this); - this.results = {}; - this.stack = [this.results]; - this.assertionCount = 0; - this.failedCount = 0; -} -AssertRecorder.prototype = new events.EventEmitter(); -add_assert_wrappers(AssertRecorder.prototype); - -AssertRecorder.prototype.group_start = function group_start(name, members) { - var group = this.back()[name] = {}; - this.stack.push(group); - this.emit('groupStart', name, members); -} -AssertRecorder.prototype.group_end = function group_end(name) { - this.stack.pop(); - this.emit('groupEnd', name); -} -AssertRecorder.prototype.testcase_start = function testcase_start(name) { - var testcase = this.back()[name] = []; - this.stack.push(testcase); - this.emit('testcaseStart', name); -} -AssertRecorder.prototype.testcase_end = function testcase_end(name) { - var assertions = this.stack.pop() - , failures = assertions.filter(function(a) { return a.error }) || [] - ; - this.emit('testcaseEnd', name, assertions, failures); - this.assertionCount += assertions.length; - this.failedCount += failures.length; -} -AssertRecorder.prototype.back = function back() { - return this.stack[this.stack.length - 1]; -} -AssertRecorder.prototype.allDone = function() { - this.emit('done', this.assertionCount, this.failedCount); -} - -run_tests(parsed.argv.remain, function(error, failed_count) { - process.exit(failed_count); -}); - -function printUsage() { - console.log('Usage:', process.title, - Object.keys(knownOptions).map(function(o) { - return '[--' + o + ']' - }).join(' ')); -} - -function printHelp() { - printUsage(); console.log( -"Options:\n\ - --format= Use formatter \n\ - --no-bark Don't bark on test failures\n\ - --help Print this help and exit\n\ -\n\ -Formats:\n\ - " + Object.keys(formats).join(', ') + "\n\ -"); - -} - -function bold(s) { return '\033[1m' + s + '\033[22m' }; -// vim: filetype=javascript : diff --git a/lib/jdiscovery/mdns/wscript b/lib/jdiscovery/mdns/wscript deleted file mode 100644 index a7feca70..00000000 --- a/lib/jdiscovery/mdns/wscript +++ /dev/null @@ -1,101 +0,0 @@ -import os, shutil, subprocess, Scripting, Options - -out = 'build' -name = 'dns_sd_bindings' - -def set_options(opt): - opt.tool_options('compiler_cxx') - opt.tool_options('node_addon') - -def configure(conf): - conf.check_tool('compiler_cxx') - conf.check_tool('node_addon') - - # HACK: The current node master builds a i386 binary while older releases used - # the compilers default x86_64. node-waf still targets x86_64 resulting in an - # incompatible binary. Building the add-on as a universal binary for both - # architectures solves this for now ... - if conf.env.DEST_OS == 'darwin': - universal_flags = ['-arch', 'i386', '-arch', 'x86_64'] - conf.env.append_value('CXXFLAGS', universal_flags) - conf.env.append_value('LINKFLAGS_MACBUNDLE', universal_flags) - - includes = ['/usr/local/include'] # help freebsd - libpath = ['/usr/local/lib'] # help freebsd - if conf.check( header_name='dns_sd.h' - , includes=includes - , uselib_store='DNS_SD' - , mandatory=True): - conf.check(lib='dns_sd', libpath=libpath, uselib_store='DNS_SD') - - conf.check(function_name='DNSServiceGetAddrInfo', - header_name="dns_sd.h", - uselib='DNS_SD') - - -def build(bld): - obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') - obj.target = name - obj.uselib = 'DNS_SD' - if bld.env.HAVE_DNSSERVICEGETADDRINFO: - obj.defines = ['HAVE_DNSSERVICEGETADDRINFO'] - obj.includes = ['..'] - obj.cxxflags = ['-Wall'] - obj.source = [ 'src/dns_sd.cpp' - , 'src/dns_service_browse.cpp' - , 'src/dns_service_enumerate_domains.cpp' - , 'src/dns_service_process_result.cpp' - , 'src/dns_service_ref.cpp' - , 'src/dns_service_ref_deallocate.cpp' - , 'src/dns_service_ref_sock_fd.cpp' - , 'src/dns_service_register.cpp' - , 'src/dns_service_resolve.cpp' - , 'src/dns_service_get_addr_info.cpp' - , 'src/dns_service_update_record.cpp' - , 'src/mdns_utils.cpp' - , 'src/network_interface.cpp' - , 'src/txt_record_ref.cpp' - , 'src/txt_record_create.cpp' - , 'src/txt_record_deallocate.cpp' - , 'src/txt_record_set_value.cpp' - , 'src/txt_record_get_length.cpp' - , 'src/txt_record_buffer_to_object.cpp' - ] - - obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') - obj.target = 'demangle' - obj.cxxflags = ['-Wall'] - obj.source = [ 'src/demangle.cpp' ] - - #bld.add_post_fun(post_build) - - -def update_addon_symlink(ctx, directory, target): - symlink_path = os.path.join(directory, target) - remove_symlink(symlink_path) - path_to_addon = os.path.join('..', 'out', ctx.path.bld_dir(ctx.env), target) - os.symlink(path_to_addon, symlink_path) - -def post_build(ctx): - update_addon_symlink(ctx, 'lib', name + '.node') - update_addon_symlink(ctx, 'utils/lib', 'demangle.node') - - -def remove_symlink(symlink): - if os.path.lexists(symlink): - os.unlink(symlink) - -def distclean(ctx): - Scripting.distclean(ctx) - - remove_symlink(os.path.join('lib', name + '.node')) - remove_symlink(os.path.join('utils/lib', 'demangle.node')) - - if os.path.exists('node_modules'): - shutil.rmtree('node_modules') - -def test(ctx): - subprocess.call(['utils/testrun']) - - -# vim: set filetype=python shiftwidth=2 softtabstop=2 : diff --git a/lib/jdiscovery/mdnsregistry.js b/lib/jdiscovery/mdnsregistry.js index d79f996d..c882d350 100644 --- a/lib/jdiscovery/mdnsregistry.js +++ b/lib/jdiscovery/mdnsregistry.js @@ -1,366 +1,381 @@ -//============================================================================== -// Registers a node on the local network using mDNS -//============================================================================== - -var mdns = require('./mdns/lib/mdns'), +var bonjour = require('bonjour')(), constants = require('../jamserver/constants'), - logger = require('../jamserver/jerrlog'), - Registry = require('./registry'); + Registry = require('./registry'), + dgram = require('dgram'); + +function MDNSRegistry(app, type, id, port) { -var sequence = [ - mdns.rst.DNSServiceResolve(), - 'DNSServiceGetAddrInfo' in mdns.dns_sd ? - mdns.rst.DNSServiceGetAddrInfo() : mdns.rst.getaddrinfo({families:[0]}), - mdns.rst.makeAddressesUnique() -]; + Registry.call(this, app, type, id, port); + this.protocol = constants.globals.Protocol.MDNS; -function MDNSRegistry(app, machType, id, port) { - Registry.call(this, app, machType, id, port); this.ads = {}; + this.attrsToAdvertise = {}; + this.browsers = { device: {}, fog: {}, cloud: {} }; - this.started = false; - this.attrs = {}; - this.attrsToDiscover = { + this.attrsToBrowse = { device: {}, fog: {}, cloud: {} } -} - -/* MDNSRegistry inherits from Registry */ -MDNSRegistry.prototype = Object.create(Registry.prototype); -MDNSRegistry.prototype.constructor = MDNSRegistry; -MDNSRegistry.prototype.registerAndDiscover = function() { - this.started = true; - - // start any ads and browsers created before this function was called - for (var attr in this.attrs) { - const attrObj = {}; - attrObj[attr] = this.attrs[attr].payload; - this._createAdvertisements(attrObj, this.attrs[attr].dedupeId); - } - this.discoverAttributes(this.attrsToDiscover); -} + this.attrRemovalAd = null; + this.attrRemovalBrowsers = {}; -//------------------------------------------------------------------------------ -// Advertisement creation -//------------------------------------------------------------------------------ + /** + * HeartBeat + */ + this.hbPort = constants.mdns.heartBeatPort; + this.hbMulticastAddress = constants.mdns.heartBeatMulticastAddress; + this.hbTTL = constants.mdns.heartBeatTTL; + this.hbSocket = null; + this.upTable = {}; -/** - * Creates advertisements for the provided attributes - */ -MDNSRegistry.prototype._createAdvertisements = function(attrs, dedupeId) { - for (var attr in attrs) { - // stop advertisement of existing attr (we'll just replace it) - if (this.ads[attr]) { - this.ads[attr].stop(); - delete this.ads[attr]; - } - var adName = this.app + '-' + this.machType[0] + '-' + attr; - var txtRecord; - if (attrs[attr] instanceof Function) { - txtRecord = { - msg: JSON.stringify({ - payload: attrs[attr](), - id: dedupeId - }) - }; - } else { - txtRecord = { - msg: JSON.stringify({ - payload: attrs[attr], - id: dedupeId - }) - }; - } - this._createAdvertisementWithRetries(this, attr, adName, txtRecord, constants.mdns.retries); - } + this.started = false; } -/** - * Helper - */ -MDNSRegistry.prototype._createAdvertisementWithRetries = function(self, attr, adName, txtRecord, retries) { - var ad = mdns.createAdvertisement(mdns.tcp(adName), self.port, {name: this.id, txtRecord: txtRecord}, function(err, service) { - if (err) { - self._handleError(self, err, ad, attr, adName, txtRecord, retries); - } else { - self.ads[attr] = ad; - } - }); - ad.start(); -} +/* MDNSRegistry inherits from Registry */ +MDNSRegistry.prototype = Object.create(Registry.prototype); +MDNSRegistry.prototype.constructor = MDNSRegistry; /** - * helper function for handling advertisement errors + * REGISTRY INTERFACE METHODS */ -MDNSRegistry.prototype._handleError = function(self, err, ad, attr, adName, txtRecord, retries) { - switch (err.errorCode) { - // if the error is unknown, then the mdns daemon may currently be down, - // so try again after some time - case mdns.kDNSServiceErr_Unknown: - logger.log.error('Unknown service error: ' + err); - if (retries === 0) { - logger.log.warning('Exhaused all advertisement retries.'); - // make sure the ad is stopped - ad.stop(); - // emit the ad info, so the registrar can decide if it wants to retry later - self.emit('ad-error', attr, addName, txtRecord); - } else { - setTimeout(self._createAdvertisementWithRetries, constants.mdns.retryInterval, self, attr, adName, txtRecord, retries - 1); - } - break; - default: - logger.log.error('Unhandled service error: ' + err); - // make sure the ad is stopped - ad.stop(); - self.emit('ad-error', attr, addName, txtRecord); - } -} - -//------------------------------------------------------------------------------ -// Service browsing -//------------------------------------------------------------------------------ /** - * Browses for services + * Start mDNS registry */ -MDNSRegistry.prototype._browseForAttributes = function(dattrs) { - - for (var attr in dattrs.device) { - if (!this.browsers.device[attr]) { - if (attr === 'status') { - this._browseForStatus(this, constants.globals.NodeType.DEVICE, dattrs.device.status); - } else { - this._browse(this, attr, constants.globals.NodeType.DEVICE, dattrs.device[attr]); - } - } else { - this.browsers.device[attr].start(); - } - } - - for (var attr in dattrs.fog) { - if (!this.browsers.fog[attr]) { - if (attr === 'status') { - this._browseForStatus(this, constants.globals.NodeType.FOG, dattrs.fog.status); - } else { - this._browse(this, attr, constants.globals.NodeType.FOG, dattrs.fog[attr]); - } - } else { - this.browsers.fog[attr].start(); - } - } - - for (var attr in dattrs.cloud) { - if (!this.browsers.cloud[attr]) { - if (attr === 'status') { - this._browseForStatus(this, constants.globals.NodeType.CLOUD, dattrs.cloud.status); - } else { - this._browse(this, attr, constants.globals.NodeType.CLOUD, dattrs.cloud[attr]); - } - } else { - this.browsers.cloud[attr].start(); - } - } -} +MDNSRegistry.prototype.registerAndDiscover = function() { -/** - * Prep a browser to browse for any attibute except for status - */ -MDNSRegistry.prototype._browse = function(self, attr, machType, events) { - var browser = mdns.createBrowser(mdns.tcp(self.app + '-' + machType[0] + '-' + attr), - {resolverSequence: sequence}); + if(this.started) + return; - self.browsers[machType][attr] = browser; + var self = this; - browser.on('serviceUp', function(service) { - // ignore our own services - if (service.name == self.id) { + // Setup socket to send own hb and receive hb from others + this.hbSocket = dgram.createSocket({ type: 'udp4', reuseAddr: true }); + // ... handle incoming heartbeats: if entry in upTable, renew entry TTL + this.hbSocket.on('message', function (message, remote) { + let o = JSON.parse(message.toString()); + // check if the message is for the same app + if(o.app !== self.app) return; + let id = o.id; + // remote has properties: address, port + if(self.upTable.hasOwnProperty(id)) { + clearTimeout(self.upTable[id].timer); + self.upTable[id].timer = setTimeout( + () => { + // remove node entry from upTable + let type = self.upTable[id].type; + delete self.upTable[id]; + // propagate node down to jreg + self.emit('discovery', 'status', + self.attrsToBrowse[type]['status'].offline, + id, 'offline', undefined); + }, + self.hbTTL + ); } - - // emit a discovery event! - const parsedMsg = JSON.parse(service.txtRecord.msg); - self.emit('discovery', attr, events.onAdd, service.name, parsedMsg.payload, parsedMsg.id); }); - - browser.on('serviceDown', function(service) { - self.emit('attr-removed', attr, events.onRemove, service.name); + // ... bind and finalize socket setup + this.hbSocket.bind(this.hbPort, function() { + self.hbSocket.setBroadcast(true); + self.hbSocket.setMulticastTTL(128); + self.hbSocket.addMembership(self.hbMulticastAddress); }); - - browser.on('error', function(err) { - browser.stop(); - self.emit('browser-error', attr, machType, events); - }); - - browser.start(); -} - -/** - * Prep a browser to browse for the status attribute - */ -MDNSRegistry.prototype._browseForStatus = function(self, machType, events) { - var browser = mdns.createBrowser(mdns.tcp(self.app + '-' + machType[0] + '-status'), - {resolverSequence: sequence}); - - self.browsers[machType].status = browser; - - browser.on('serviceUp', function(service) { - // ignore our own services - if (service.name == self.id) { - return; + // ... start periodic hb emission for local node + setInterval( + () => { + let m = new Buffer.from(JSON.stringify({app: self.app, id: self.id})); + self.hbSocket.send(m, 0, m.length, self.hbPort, self.hbMulticastAddress); + }, + Math.floor(self.hbTTL/3) + ); + + // Setup attribute removal browsers + ['device', 'fog', 'cloud'].map( + (x) => { + this.attrRemovalBrowsers[x] = + bonjour.find({type : this.app + '-' + (x) + '-attrrem'}); + this.attrRemovalBrowsers[x].on('up', function(service) { + // DEBUG + // console.log('DEBUG: MDNSRegistry.attrRemovalBrowser[' + x + ']'); + // console.log(JSON.stringify(service)); + // console.log(JSON.stringify(self.attrsToBrowse)); + + // ignore our own services + if (service.name === self.id) { + return; + } + // notify jregistrar of lost attributes/disconnections + let attrs = JSON.parse(service.txt.data); + let seqval = service.txt.seqval; + attrs.filter( + (attr) => { + return self.attrsToBrowse[x][attr]; + } + ).map( + (attr) => { + // DEBUG + // console.log('TYPE: ' + x + ' ATTR: ' + attr); + + // propagate advertised attribute removals + if(attr === 'status') { + // clear upTable entry to avoid extra notif + if(self.upTable.hasOwnProperty(service.name)) { + clearTimeout(self.upTable[service.name].timer); + delete self.upTable[service.name]; + } + self.emit('discovery', attr, + self.attrsToBrowse[x][attr].offline, + service.name, 'offline', undefined); + } else { + self.emit('attr-removed', attr, + self.attrsToBrowse[x][attr].onRemove, + service.name, seqval); + } + } + ); + }); + this.attrRemovalBrowsers[x].on('down', function(service) { + // do nothing! + }); + this.attrRemovalBrowsers[x].start(); } - - // emit a discovery event! - const parsedMsg = JSON.parse(service.txtRecord.msg); - self.emit('discovery', 'status', events.online, service.name, parsedMsg.payload, parsedMsg.id); - }); - - browser.on('serviceDown', function(service) { - // pass a dedupeId of zero for node down events - self.emit('discovery', 'status', events.offline, service.name, 'offline', 0); - }); - - browser.on('error', function(err) { - browser.stop(); - self.emit('browser-error', 'status', machType, events); - }); - - browser.start(); + ); + this.started = true; } - -//============================================================================== -// Add and discover attributes -//============================================================================== - /** - * Adds attributes by starting ads. + * Sets attributes by starting ads or modifying them. * attrs - an object of attributes - * dedupeId - the ID to publish with the attributes for deduplication purposes - * on the receiving node + * seqval - the ID to publish with the attributes for deduplication purposes + * on the receiving node */ -MDNSRegistry.prototype.addAttributes = function(attrs, dedupeId) { +MDNSRegistry.prototype.setAttributes = function(attrs, seqval) { + // DEBUG + // console.log('DEBUG: MDNSRegistry.setAttributes'); + if (this.started) { - this._createAdvertisements(attrs, dedupeId); + this._createAdvertisements(attrs, seqval); } else { - for (var attr in attrs) { - this.attrs[attr] = { payload: attrs[attr], dedupeId: dedupeId }; - } + let self = this; + setTimeout(self.setAttributes.bind(self), + constants.mdns.retryInterval, + attrs, seqval); } } - /** * Removes attributes by stopping the advertisements */ -MDNSRegistry.prototype.removeAttributes = function(attrs) { - if (this.started) { - for (var i = 0; i < attrs.length; i++) { - // stop and remove the advertisement - if (this.ads[attrs[i]]) { - this.ads[attrs[i]].stop(); - // we delete the ad object because even if we start advertising with the - // same service name in the future, the value we advertise may be different - delete this.ads[attrs[i]]; - } - } - } else { - for (var i = 0; i < attrs.length; i++) { - delete this.attrs[attrs[i]]; - } +MDNSRegistry.prototype.removeAttributes = function(attrs, seqval) { + // DEBUG + // console.log('DEBUG: MDNSRegistry.removeAttributes'); + + // clean & create attrrem advertisement + if (this.attrRemovalAd) { + this.attrRemovalAd.stop(); + this.attrRemovalAd = null; } + this.attrRemovalAd = bonjour.publish( + { + name : this.id, + port : this.port, + type : this.app + '-' + this.type + '-attrrem', + txt : { + data : JSON.stringify(Object.keys(attrs)), + seqval : seqval + } + } + ); + this.attrRemovalAd.start(); + + setTimeout( + () => { + for (var attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + if (this.attrsToAdvertise[attr] && this.ads[attr]) { + this.ads[attr].stop(); + delete this.attrsToAdvertise[attr]; + delete this.ads[attr]; + } + } + } + if (this.attrRemovalAd) { + this.attrRemovalAd.stop(); + this.attrRemovalAd = null; + } + }, + 5000 + ); } - /** - * Alias for _browseForAttributes, i.e. discovers attributes by starting browsers + * Discovers attributes by starting browsers */ MDNSRegistry.prototype.discoverAttributes = function(dattrs) { if (this.started) { - this._browseForAttributes(dattrs); + ['device', 'fog', 'cloud'].map( + (x) => { + for (var attr in dattrs[x]) { + if(dattrs[x].hasOwnProperty(attr)) { + if (!this.browsers[x][attr]) { + this.attrsToBrowse[x][attr] = dattrs[x][attr]; + this._createBrowser(attr, + constants.globals.NodeType[x.toUpperCase()]); + } + } + } + } + ); } else { - for (var attr in dattrs.device) { - this.attrsToDiscover.device[attr] = dattrs.device[attr]; - } - for (var attr in dattrs.fog) { - this.attrsToDiscover.fog[attr] = dattrs.fog[attr]; - } - for (var attr in dattrs.cloud) { - this.attrsToDiscover.cloud[attr] = dattrs.cloud[attr]; - } + let self = this; + setTimeout(self.discoverAttributes.bind(self), + constants.mdns.retryInterval, + dattrs); } } - /** * Stops making discoveries by stopping browsers */ MDNSRegistry.prototype.stopDiscoveringAttributes = function(dattrs) { - if (dattrs.device) { - for (var i = 0; i < dattrs.device.length; i++) { - if (this.started) { - // stop the browser - if (this.browsers.device[dattrs.device[i]]) { - this.browsers.device[dattrs.device[i]].stop(); + ['device', 'fog', 'cloud'].map( + x => { + if (dattrs[x]) { + for(var attr in dattrs[x]) { + if (dattrs[x].hasOwnProperty(attr)) { + if (this.attrsToBrowse[x][attr] && this.browsers[x][attr]) { + this.browsers[x][attr].stop(); + delete this.attrsToBrowse[x][attr]; + delete this.browsers[x][attr]; + } + } } - } else { - delete this.attrsToDiscover.device[dattrs.device[i]]; } } - } - - if (dattrs.fog) { - for (var i = 0; i < dattrs.fog.length; i++) { - if (this.started) { - if (this.browsers.fog[dattrs.fog[i]]) { - this.browsers.fog[dattrs.fog[i]].stop(); - } - } else { - delete this.attrsToDiscover.fog[dattrs.fog[i]]; + ); +} +/** + * mDNS cleanup + * Stop all advertising and browsing + */ +MDNSRegistry.prototype.quit = function(seqval) { + + // stop advertising all attrs + this.removeAttributes(this.attrsToAdvertise , seqval); + // stop discovering all attrs + this.stopDiscoveringAttributes(this.attrsToBrowse); + // stop removal browsers + ['device', 'fog', 'cloud'].map( + (x) => { + this.attrRemovalBrowsers[x].stop(); } - } - } + ); +} - if (dattrs.cloud) { - for (var i = 0; i < dattrs.cloud.length; i++) { - if (this.started) { - if (this.browsers.cloud[dattrs.cloud[i]]) { - this.browsers.cloud[dattrs.cloud[i]].stop(); - } - } else { - delete this.attrsToDiscover.cloud[dattrs.cloud[i]]; +/** + * _PRIVATE HELPERS + */ + +/** + * Creates advertisements for the provided attributes + */ +MDNSRegistry.prototype._createAdvertisements = function(attrs, seqval) { + + // DEBUG + // console.log('DEBUG: MDNSRegistry._createAdvertisements'); + + // stop old advertisements and create new ones for updated attrs + for (var attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + // Update data structures + this.attrsToAdvertise[attr] = attrs[attr]; + if (this.ads[attr]) { + this.ads[attr].stop(); + delete this.ads[attr]; } + this.ads[attr] = bonjour.publish( + { + name : this.id, + port : this.port, + type : this.app + '-' + this.type + '-' + attr, + txt : { + data : JSON.stringify(attrs[attr]), + seqval : seqval + } + } + ); + // if we get a service already on network error, wait a little, then retry + // .. it seems like it takes a little time for the mdns server to clear its entry + this.ads[attr].on('error', + () => { + setTimeout( + () => { this.ads[attr].start(); }, + 2000 + ); + } + ); + // attempt start :) + this.ads[attr].start(); } } } - /** - * mDNS cleanup - * stops all advertising and browsing + * Prep a browser to browse for an attibute */ -/* -MDNSRegistry.prototype.quit = function() { - // stop ads - for (var attr in this.ads) { - this.ads[attr].stop(); - } +MDNSRegistry.prototype._createBrowser = function(attr, type) { - // stop browsers - for (var attr in this.browsers.device) { - this.browsers.device[attr].stop(); - } + let browser = bonjour.find({ type : this.app + '-' + type + '-' + attr }); + this.browsers[type][attr] = browser; - for (var attr in this.browsers.fog) { - this.browsers.fog[attr].stop(); - } + var self = this; + browser.on('up', function(service) { + // DEBUG + // console.log("DEBUG: MDNSRegistry: |" + type + "/" + attr + "| browser: service up"); - for (var attr in this.browsers.cloud) { - this.browsers.cloud[attr].stop(); - } + // ignore our own services + if (service.name === self.id) { + return; + } + + // initiate heartbeat upon discovering a new node + if(attr === 'status') { + if(self.upTable.hasOwnProperty(service.name)) { + clearTimeout(self.upTable[service.name].timer); + } + self.upTable[service.name] = { + type : type, + timer : setTimeout( + () => { + // remove node entry from upTable + delete self.upTable[service.name]; + // propagate node down to jreg + self.emit('discovery', 'status', + self.attrsToBrowse[type]['status'].offline, + service.name, 'offline', undefined); + }, + self.hbTTL + ) + } + } + + // emit a discovery event! + self.emit('discovery', attr, + (attr === 'status') + ? self.attrsToBrowse[type][attr].online + : self.attrsToBrowse[type][attr].onAdd, + service.name, + JSON.parse(service.txt.data), + service.txt.seqval + ); + }); + browser.on('down', function(service) { + // do nothing! + }); + browser.start(); } -*/ /* exports */ module.exports = MDNSRegistry; diff --git a/lib/jdiscovery/mqttregistry.js b/lib/jdiscovery/mqttregistry.js index 7ab40e94..0cb32dcc 100644 --- a/lib/jdiscovery/mqttregistry.js +++ b/lib/jdiscovery/mqttregistry.js @@ -1,14 +1,15 @@ -//============================================================================== -// Registers a node on the network using MQTT -//============================================================================== - var mqtt = require('mqtt'), - logger = require('../jamserver/jerrlog.js'), constants = require('../jamserver/constants'), Registry = require('./registry'); -function MQTTRegistry(app, machType, id, port, subQos, pubQos) { - Registry.call(this, app, machType, id, port); +function MQTTRegistry(app, type, id, port, subQos, pubQos) { + + Registry.call(this, app, type, id, port); + this.protocol = constants.globals.Protocol.MQTT; + + // client will hold the mqtt client, initialized in registerAndDiscover + this.client = null; + // the quality of service to use for subscriptions this.subQos = subQos; // the quality of service to use for publications @@ -25,398 +26,129 @@ function MQTTRegistry(app, machType, id, port, subQos, pubQos) { fog: {}, cloud: {} }; - /** - * Attributes to be published on (re)connection. A map from attribute name - * to { payload: attribute_value, dedupeId: deduplication_id } objects. - */ - this.attrsToPublish = {}; - // attributes to remove when reconnecting - this.attrsToRemove = {}; - // attributes to subscribe to on (re)connection - this.attrsToSubTo = { - device: {}, - fog: {}, - cloud: {} - }; - // attributes to unsubscribe from on reconnection - this.attrsToUnsubFrom = { - device: {}, - fog: {}, - cloud: {} - }; + + // has this registry already been started w registerAndDiscover()? + this.started = false; } /* MQTTRegistry inherits from Registry */ MQTTRegistry.prototype = Object.create(Registry.prototype); MQTTRegistry.prototype.constructor = MQTTRegistry; +/** + * REGISTRY INTERFACE METHODS + */ + /** * Performs basic registration and discovery */ MQTTRegistry.prototype.registerAndDiscover = function() { + + if(this.started) + return; + // create an mqtt client + // in case of disconnection, client __automatically__ reconnects this.client = mqtt.connect(constants.mqtt.brokerUrl, this._getConnectionOptions()); - // set up event listeners for the client - this._prepareForEvents(); -} - -/** - * A general helper for listening for events from the MQTT client - */ -MQTTRegistry.prototype._prepareForEvents = function() { var self = this; /* connect event emitted on successful connection or reconnection */ this.client.on('connect', function (connack) { - if (!connack.sessionPresent) { - /* - * session is not present - subscriptions start from scratch but - * old publications could still be persisted on the broker - */ - // reset attrsToUnsubFrom - self.attrsToUnsubFrom = { - device: {}, - fog: {}, - cloud: {} - }; - // subscribe - // combine subscribedAttrs and attrsToSubTo so that we can subscribe to all of them - for (var attr in self.subscribedAttrs.device) { - self.attrsToSubTo.device[attr] = self.subscribedAttrs.device[attr]; - } - for (var attr in self.subscribedAttrs.fog) { - self.attrsToSubTo.fog[attr] = self.subscribedAttrs.fog[attr]; - } - for (var attr in self.subscribedAttrs.cloud) { - self.attrsToSubTo.cloud[attr] = self.subscribedAttrs.cloud[attr]; - } - self.subscribedAttrs = { - device: {}, - fog: {}, - cloud: {} - }; - self._subscribeWithRetries(self, JSON.parse(JSON.stringify(self.attrsToSubTo)), constants.mqtt.retries); - } else { - /* - * session is present - old subscriptions are still there so we only need to subscribe to new ones - * but we also need to unsubscribe from attrsToUnsubFrom - * we make no assumptions about the state of publications - */ - // subscribe - self._subscribeWithRetries(self, JSON.parse(JSON.stringify(self.attrsToSubTo)), constants.mqtt.retries); - // unsubscribe - self._unsubscribeWithRetries(self, JSON.parse(JSON.stringify(self.attrsToRemove)), constants.mqtt.retries); - } - - // publish - for (var attr in self.publishedAttrs) { - self.attrsToPublish[attr] = self.publishedAttrs[attr]; - } - self.publishedAttrs = {}; - for (var attr in self.attrsToPublish) { - self._publishWithRetries(self, attr, self.attrsToPublish[attr].payload, self.attrsToPublish[attr].dedupeId, constants.mqtt.retries); - } - // unpublish - for (var attr in self.attrsToRemove) { - self._unpublishWithRetries(self, attr, constants.mqtt.retries); - } + /* + * session is not present - subscriptions start from scratch + * publications persist across connections on the broker (retain flag) + */ + self._subscribeWithRetries.call(self, self.subscribedAttrs, constants.mqtt.retries); }); - /* message event received when client receives a published packet */ this.client.on('message', function (topic, message, packet) { - // parse the mach type, the mach id, and the attribute out of the topic - var components = topic.split('/'); - var machType = components[1]; - var machId = components[2]; - var attr = components[3]; + // parse the machine type, the machine id, and the attribute out of the topic + var [app, type, id, attr] = topic.split('/'); - // if the message is an empty string, then this is the result of an "unpublish". - // i.e. another node unpublished an attribute and we are now being notified. - if (message.toString() === '') { - var eventName; - if (self.subscribedAttrs[machType].hasOwnProperty(attr)) { - eventName = self.subscribedAttrs[machType][attr].onRemove; - } - - if (eventName !== undefined) { - self.emit('attr-removed', attr, eventName, machId); - } else { - console.log('Message received yet we are not subscribed to this message, or shouldn\'t be... This should not be because we are still awaiting a subscription confirmation for this message, as this issue has been fixed. If you ever see this message, then something is probably wrong.'); - } - return; - } - - const parsedMsg = JSON.parse(message.toString()); - self._handleMessage(self, machType, machId, attr, parsedMsg.payload, parsedMsg.id); + const parsed = JSON.parse(message.toString()); + self._handleMessage.call(self, type, id, attr, parsed.data, parsed.seqval); }); - this.client.on('offline', function () { console.log('WARNING: mqtt client is offline'); }); - this.client.on('error', function (error) { console.log('WARNING: mqtt client received an error'); }); -} - -/** - * Handles receipt of a message from the MQTT broker. Finds the subscription that - * the message corresponds to and executes the appropriate action. - */ -MQTTRegistry.prototype._handleMessage = function(self, machType, machId, attr, payload, dedupeId) { - var eventName; - if (self.subscribedAttrs[machType].hasOwnProperty(attr)) { - if (attr === 'status') { - if (payload === 'offline') { - eventName = self.subscribedAttrs[machType].status.offline; - // pass a dedupeId of zero for node down events - dedupeId = 0; - } else { - eventName = self.subscribedAttrs[machType].status.online; - } - } else { - eventName = self.subscribedAttrs[machType][attr].onAdd; - } - } - if (eventName !== undefined) { - self.emit('discovery', attr, eventName, machId, payload, dedupeId); - } else { - console.log('Message received yet we are not subscribed to this message channel, or shouldn\'t be... This should not be because we are still awaiting a subscription confirmation for this message, as this issue has been fixed. If you ever see this message, then something is probably wrong.'); - } + this.started = true; } - /** - * Helper for setting up subscriptions to the broker with retries + * set/unset attributes discovered by this node */ -MQTTRegistry.prototype._subscribeWithRetries = function(self, dattrs, retries) { - // format subscriptions to be sent to the broker - var subs = {}; - - for (var attr in dattrs.device) { - subs[self.app + '/device/+/' + attr] = self.subQos; - } - - for (var attr in dattrs.fog) { - subs[self.app + '/fog/+/' + attr] = self.subQos; - } - - for (var attr in dattrs.cloud) { - subs[self.app + '/cloud/+/' + attr] = self.subQos; - } - - if (Object.keys(subs).length === 0) { - return; - } - - // optimistically move these subscriptions from attrsToSubTo to subscribedAttrs - for (var attr in dattrs.device) { - delete self.attrsToSubTo.device[attr]; - self.subscribedAttrs.device[attr] = dattrs.device[attr]; - } - - for (var attr in dattrs.fog) { - delete self.attrsToSubTo.fog[attr]; - self.subscribedAttrs.fog[attr] = dattrs.fog[attr]; - } - - for (var attr in dattrs.cloud) { - delete self.attrsToSubTo.cloud[attr]; - self.subscribedAttrs.cloud[attr] = dattrs.cloud[attr]; +MQTTRegistry.prototype.discoverAttributes = function(dattrs) { + if (this.client && this.client.connected) { + this._subscribeWithRetries(dattrs, constants.mqtt.retries); + } else { + var self = this; + setTimeout(self.discoverAttributes.bind(self), + constants.mqtt.retryInterval, dattrs); } - - // perform subscriptions - self.client.subscribe(subs, function (err, granted) { - if (err) { - if (retries !== 0) { - setTimeout(self._subscribeWithRetries, constants.mqtt.retryInterval, self, dattrs, retries - 1); - } else { - // move all attributes back to attrsToSubTo and emit an error - for (var attr in dattrs.device) { - delete self.subscribedAttrs.device[attr]; - self.attrsToSubTo.device[attr] = dattrs.device[attr]; - } - - for (var attr in dattrs.fog) { - delete self.subscribedAttrs.fog[attr]; - self.attrsToSubTo.fog[attr] = dattrs.fog[attr]; - } - - for (var attr in dattrs.cloud) { - delete self.subscribedAttrs.cloud[attr]; - self.attrsToSubTo.cloud[attr] = dattrs.cloud[attr]; - } - self.emit('sub-error', dattrs); - } - } else { - // move any attrs that were denied from subscribedAttrs to attrsToSubTo and - // emit an event indicating the attributes that were denied - var components, machType, attr; - for (var i = 0; i < granted.length; i++) { - components = granted[i].topic.split('/'); - machType = components[1]; - attr = components[3]; - delete dattrs[machType][attr]; - } - - for (var attr in dattrs.device) { - delete self.subscribedAttrs.device[attr]; - self.attrsToSubTo.device[attr] = dattrs.device[attr]; - } - - for (var attr in dattrs.fog) { - delete self.subscribedAttrs.fog[attr]; - self.attrsToSubTo.fog[attr] = dattrs.fog[attr]; - } - - for (var attr in dattrs.cloud) { - delete self.subscribedAttrs.cloud[attr]; - self.attrsToSubTo.cloud[attr] = dattrs.cloud[attr]; - } - - // report any subscriptions that weren't granted - if (Object.keys(dattrs.device).length !== 0 || - Object.keys(dattrs.fog).length !== 0 || - Object.keys(dattrs.cloud).length !== 0) { - self.emit('subs-denied', dattrs); - } - } - }); } - -MQTTRegistry.prototype.subscribe = function(self, dattrs) { - if (self.client && self.client.connected) { - self._subscribeWithRetries(self, dattrs, constants.mqtt.retries); +MQTTRegistry.prototype.stopDiscoveringAttributes = function(dattrs) { + if (this.client && this.client.connected) { + this._unsubscribeWithRetries(dattrs, constants.mqtt.retries); + } else { + var self = this; + setTimeout(self.stopDiscoveringAttributes.bind(self), + constants.mqtt.retryInterval, dattrs); } - // if we're disconnected, then we'll automatically try to subscribe to the attributes when we connect } - /** - * Unsubscribe from a series of topics + * set/unset discoverable attributes for this node */ -MQTTRegistry.prototype._unsubscribeWithRetries = function(self, dattrs, retries) { - var topics = []; - for (var attr in dattrs.device) { - topics.push(self.app + '/device/+/' + dattrs.device[attr]); - } - - for (var attr in dattrs.fog) { - topics.push(self.app + '/fog/+/' + dattrs.fog[attr]); - } - - for (var attr in dattrs.cloud) { - topics.push(self.app + '/cloud/+/' + dattrs.cloud[attr]); - } - - if (topics.length === 0) { - return; +MQTTRegistry.prototype.setAttributes = function(attrs, seqval) { + for (var attr in attrs) { + this._publish(attr, attrs[attr], seqval); } - - self.client.unsubscribe(topics, function(err) { - if (err) { - if (retries > 0) { - setTimeout(self._unsubscribeWithRetries, constants.mqtt.retryInterval, self, topics, retries - 1); - } else { - self.emit('unsub-error', dattrs); - } - } else { - for (var attr in dattrs.device) { - delete self.subscribedAttrs.device[attr]; - delete self.attrsToUnsubFrom.device[attr]; - } - for (var attr in dattrs.fog) { - delete self.subscribedAttrs.fog[attr]; - delete self.attrsToUnsubFrom.fog[attr]; - } - for (var attr in dattrs.cloud) { - delete self.subscribedAttrs.cloud[attr]; - delete self.attrsToUnsubFrom.cloud[attr]; - } - } - }); } - -MQTTRegistry.prototype.unsubscribe = function(self, dattrs) { - if (self.client && self.client.connected) { - self._unsubscribeWithRetries(self, dattrs, constants.mqtt.retries); +MQTTRegistry.prototype.removeAttributes = function(attrs, seqval) { + for (var attr in attrs) { + this._unpublish(attr, seqval); } - // if we're disconnected, then we'll automatically try to unsubscribe from the attributes when we connect } - /** - * Helper for publishing an attribute with retries. - * attr - the name of the attribute - * value - the value of the attribute - * dedupeId - the ID to publish with the attributes for deduplication purposes on - * on the receiving node - * retries - the number of retries, if publishing fails + * Closes the mqtt registry + * --> Cleans up all publications on mqtt broker + * --> Kills connection to broker */ -MQTTRegistry.prototype._publishWithRetries = function(self, attr, value, dedupeId, retries) { - var msg; - if (value instanceof Function) { - msg = JSON.stringify({ payload: value(), id: dedupeId }); +MQTTRegistry.prototype.quit = function(seqval) { + if (this.client && this.client.connected) { + // unpublish on all attributes + this.removeAttributes(this.publishedAttrs, seqval); + // end connection + this.client.end(false); } else { - msg = JSON.stringify({ payload: value, id: dedupeId }); - } - self.client.publish(self.app + '/' + self.machType + '/' + self.id + '/' + attr, msg, {qos: self.pubQos, retain: true}, function (err) { - if (err) { - if (retries === 0) { - setTimeout(self._publishWithRetries, constants.mqtt.retryInterval, self, attr, value, dedupeId, retries - 1); - } else { - self.emit('pub-error', attr, value); - } - } else { - // move the attribute from attrsToPublish to publishedAttrs - self.publishedAttrs[attr] = { payload: value, dedupeId: dedupeId }; - delete self.attrsToPublish[attr]; - } - }); -} - -MQTTRegistry.prototype.publish = function(self, attr, value) { - if (self.client && self.client.connected) { - self._publishWithRetries(self, attr, value, constants.mqtt.retries); + var self = this; + setTimeout(self.quit.bind(self), + constants.mqtt.retryInterval); } - // if we're disconnected, then we'll automatically try to publish the attributes when we connect + this.client = null; } /** - * Helper for "un"-publishing an attribute + * _PRIVATE HELPERS */ -MQTTRegistry.prototype._unpublishWithRetries = function(self, attr, retries) { - self.client.publish(self.app + '/' + self.machType + '/' + self.id + '/' + attr, null, {qos: self.pubQos, retain: true}, function (err) { - if (err) { - if (retries > 0) { - setTimeout(self._unpublishWithRetries, constants.mqtt.retryInterval, self, attr, retries - 1); - } else { - self.emit('unpub-error', attr); - } - } else { - // remove the attribute from attrsToRemove and publishedAttrs - delete self.attrsToRemove[attr]; - delete self.publishedAttrs[attr]; - } - }); -} - -MQTTRegistry.prototype.unpublish = function(self, attr) { - if (self.client && self.client.connected) { - self._unpublishWithRetries(self, attr, constants.mqtt.retries); - } - // if we're disconnected, then we'll automatically try to publish the attributes when we connect -} /** * Returns connection options to the mqtt broker contingent upon the connecting node * takes as arguments the name of the application, the type of the machine, and the * id of the machine + * CleanSession: true + * Last Will (LWT): (retain: true) */ MQTTRegistry.prototype._getConnectionOptions = function() { + // create the will var will = { - topic: this.app + '/' + this.machType + '/' + this.id + '/status', - payload: JSON.stringify({ payload: 'offline' }), + topic: this.app + '/' + this.type + '/' + this.id + '/status', + // n.b. will pub will not have a seqval due to its nature + payload: JSON.stringify({ data: 'offline' }), qos: this.pubQos, retain: true } @@ -425,180 +157,185 @@ MQTTRegistry.prototype._getConnectionOptions = function() { return { clientId: this.id, keepalive: constants.mqtt.keepAlive, - clean: false, + clean: true, connectTimeout: constants.mqtt.connectionTimeout, will: will }; } -//============================================================================== -// Custom attribute publication/discovery -//============================================================================== - /** - * Add and publish attributes for this node + * Handles receipt of a message from the MQTT broker. Finds the subscription that + * the message corresponds to and executes the appropriate action. */ -MQTTRegistry.prototype.addAttributes = function(attrs, dedupeId) { - for (var attr in attrs) { - // just in case this is in the queue for removal... - delete this.attrsToRemove[attr]; - // check that it's not already published - if (!this.publishedAttrs.hasOwnProperty(attr)) { - this.attrsToPublish[attr] = { payload: attrs[attr], dedupeId: dedupeId }; - if (this.client && this.client.connected) { - // try to publish the attribute - this._publishWithRetries(this, attr, attrs[attr], dedupeId, constants.mqtt.retries); +MQTTRegistry.prototype._handleMessage = function(type, id, attr, data, seqval) { + + var event; + + // data empty <=> unpublish on attr + if (data === undefined) + { + if (this.subscribedAttrs[type].hasOwnProperty(attr)) { + event = this.subscribedAttrs[type][attr].onRemove; + } + if (event !== undefined) + this.emit('attr-removed', attr, event, id, seqval); + } + else if (this.subscribedAttrs[type].hasOwnProperty(attr)) + { + if (attr === 'status') { + if (data === 'offline') { + event = this.subscribedAttrs[type].status.offline; + } else { + event = this.subscribedAttrs[type].status.online; } + } else { + event = this.subscribedAttrs[type][attr].onAdd; } + if (event !== undefined) + this.emit('discovery', attr, event, id, data, seqval); } } /** - * Unpublishes the given attributes. - * attrs - an array of the names (strings) of the attributes to remove. + * Helper for setting up subscriptions to the broker with retries */ -MQTTRegistry.prototype.removeAttributes = function(attrs) { - for (var i = 0; i < attrs.length; i++) { - // remove it from attrsToPublish, if need be - delete this.attrsToPublish[attrs[i]]; - if (this.publishedAttrs.hasOwnProperty(attrs[i])) { - this.attrsToRemove[attrs[i]] = null; - if (this.client && this.client.connected) { - // try to remove it - this._unpublishWithRetries(this, attrs[i], constants.mqtt.retries); - } - } - } -} +MQTTRegistry.prototype._subscribeWithRetries = function(dattrs, retries) { -MQTTRegistry.prototype.discoverAttributes = function(dattrs) { - var subs = null; - - for (var attr in dattrs.device) { - // in case this attr is queued up to be unsubscribed from - delete this.attrsToUnsubFrom.device[attr]; - if (!this.subscribedAttrs.device.hasOwnProperty(attr)) { - // try to subscribe to it - if (subs === null) { - subs = { - device: {}, - fog: {}, - cloud: {} - }; - } - subs.device[attr] = dattrs.device[attr]; - this.attrsToSubTo.device[attr] = dattrs.device[attr]; - } - } - - for (var attr in dattrs.fog) { - // in case this attr is queued up to be unsubscribed from - delete this.attrsToUnsubFrom.fog[attr]; - if (!this.subscribedAttrs.fog.hasOwnProperty(attr)) { - // try to subscribe to it - if (subs === null) { - subs = { - device: {}, - fog: {}, - cloud: {} - }; - } - subs.fog[attr] = dattrs.fog[attr]; - this.attrsToSubTo.fog[attr] = dattrs.fog[attr]; + // create topic strings to be sent to the broker for subscription + var topics = []; + ['device', 'fog', 'cloud'].map( + (x) => { + for (var attr in dattrs[x]) + if(dattrs[x].hasOwnProperty(attr)) + topics.push(this.app + '/' + x + '/+/' + attr); } - } + ); + if (topics.length === 0) + return; - for (var attr in dattrs.cloud) { - // in case this attr is queued up to be unsubscribed from - delete this.attrsToUnsubFrom.cloud[attr]; - if (!this.subscribedAttrs.cloud.hasOwnProperty(attr)) { - // try to subscribe to it - if (subs === null) { - subs = { - device: {}, - fog: {}, - cloud: {} - }; + // perform subscriptions + var self = this; + this.client.subscribe( + topics, + { qos : this.subQos }, + function (err, granted) { + if (err) { + // Let -1 signify infinite retries + if (retries > 0 || retries == -1) + setTimeout(self._subscribeWithRetries.bind(self), + constants.mqtt.retryInterval, dattrs, + (retries === -1) ? -1 : (retries-1)); + } else { + // add new subscriptions to subscribedAttrs + granted.map( + x => { + let [ , type, , attr] = x.topic.split('/'); + self.subscribedAttrs[type][attr] = dattrs[type][attr]; + } + ); } - subs.cloud[attr] = dattrs.cloud[attr]; - this.attrsToSubTo.cloud[attr] = dattrs.cloud[attr]; } - } - - if (subs !== null && this.client && this.client.connected) { - this._subscribeWithRetries(this, subs, constants.mqtt.retries); - } + ); } +/** + * Unsubscribe from a series of topics + */ +MQTTRegistry.prototype._unsubscribeWithRetries = function(dattrs, retries) { -MQTTRegistry.prototype.stopDiscoveringAttributes = function(dattrs) { - var unsubs = null; - - if (dattrs.device) { - for (var i = 0; i < dattrs.device.length; i++) { - delete this.attrsToSubTo.device[dattrs.device[i]]; - if (this.subscribedAttrs.hasOwnProperty(dattrs.device[i])) { - this.attrsToUnsubFrom.device[dattrs.device[i]] = null; - if (unsubs === null) { - unsubs = { - device: {}, - fog: {}, - cloud: {} - } - } - unsubs.device[dattrs.device[i]] = null; + var topics = []; + ['device', 'fog', 'cloud'].map( + x => { + for (var attr in dattrs[x]) { + topics.push(this.app + '/' + x + '/+/' + attr); } } - } + ); + if (topics.length === 0) + return; - if (dattrs.fog) { - for (var i = 0; i < dattrs.fog.length; i++) { - delete this.attrsToSubTo.fog[dattrs.fog[i]]; - if (this.subscribedAttrs.hasOwnProperty(dattrs.fog[i])) { - this.attrsToUnsubFrom.fog[dattrs.fog[i]] = null; - if (unsubs === null) { - unsubs = { - device: {}, - fog: {}, - cloud: {} + var self = this; + this.client.unsubscribe( + topics, + function(err) { + if (err) { + // Let -1 signify infinite retries + if (retries > 0 || retries == -1) + setTimeout(self._unsubscribeWithRetries.bind(self), + constants.mqtt.retryInterval, dattrs, + (retries === -1) ? -1 : (retries-1)); + } else { + ['device', 'fog', 'cloud'].map( + x => { + for (var attr in dattrs[x]) + if (dattrs[x].hasOwnProperty(attr)) + delete self.subscribedAttrs[x][attr]; } - } - unsubs.fog[dattrs.fog[i]] = null; + ); } - } - } + }); +} +MQTTRegistry.prototype._publishWithRetries = function(attr, data, seqval, retries) { - if (dattrs.cloud) { - for (var i = 0; i < dattrs.cloud.length; i++) { - delete this.attrsToSubTo.cloud[dattrs.cloud[i]]; - if (this.subscribedAttrs.hasOwnProperty(dattrs.cloud[i])) { - this.attrsToUnsubFrom.cloud[dattrs.cloud[i]] = null; - if (unsubs === null) { - unsubs = { - device: {}, - fog: {}, - cloud: {} - } - } - unsubs.cloud[dattrs.cloud[i]] = null; + /** + * When data === undefined, the receivers will interpret this as an attr removal + * Data is set to _null_ on publishing attrs with no data to avoid this + */ + if(data === undefined) + data = null; + + var self = this; + this.client.publish( + (this.app + '/' + this.type + '/' + this.id + '/' + attr), + JSON.stringify({ data: data, seqval: seqval }), + {qos: this.pubQos, retain: true}, + function (err) { + if (err) { + if (retries > 0 || retries === -1) + setTimeout(self._publishWithRetries.bind(self), + constants.mqtt.retryInterval, attr, data, seqval, + (retries === -1) ? -1 : (retries-1)); + } else { + self.publishedAttrs[attr] = { data : data , seqval : seqval }; } - } - } + }); +} +MQTTRegistry.prototype._unpublishWithRetries = function(attr, seqval, retries) { - if (unsubs !== null && this.client && this.client.connected) { - this._unsubscribeWithRetries(this, unsubs, constants.mqtt.retries); + var self = this; + this.client.publish( + (this.app + '/' + this.type + '/' + this.id + '/' + attr), + // n.b. 'data' property must be __undefined__ + JSON.stringify({ seqval : seqval }), + {qos: this.pubQos, retain: true}, + function (err) { + if (err) { + if (retries > 0 || retries === -1) + setTimeout(self._unpublishWithRetries.bind(self), + constants.mqtt.retryInterval, attr, seqval, + (retries === -1) ? -1 : (retries-1)); + } else { + delete self.publishedAttrs[attr]; + } + }); +} +MQTTRegistry.prototype._publish = function(attr, data, seqval) { + if (this.client && this.client.connected) { + this._publishWithRetries(attr, data, seqval, constants.mqtt.retries); + } else { + var self = this; + setTimeout(self._publish.bind(self), + constants.mqtt.retryInterval, attr, data, seqval); } } - -/** - * Closes the client, executing the callback upon completion - */ -/* -MQTTRegistry.prototype.quit = function(cb) { - if (this.client) { - this.client.end(false, cb); +MQTTRegistry.prototype._unpublish = function(attr, seqval) { + if (this.client && this.client.connected) { + this._unpublishWithRetries(attr, seqval, constants.mqtt.retries); + } else { + var self = this; + setTimeout(self._unpublish.bind(self), + constants.mqtt.retryInterval, attr, seqval); } } -*/ /* exports */ module.exports = MQTTRegistry; diff --git a/lib/jdiscovery/package-lock.json b/lib/jdiscovery/package-lock.json index 7bec6d84..d0dd2278 100644 --- a/lib/jdiscovery/package-lock.json +++ b/lib/jdiscovery/package-lock.json @@ -1,46 +1,64 @@ { "name": "jdiscovery", - "version": "0.0.7", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { + "array-flatten": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", + "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "bindings": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", - "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" - }, "bl": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", - "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "2.3.6", + "safe-buffer": "5.1.2" + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "requires": { - "readable-stream": "2.2.11" + "array-flatten": "2.1.1", + "deep-equal": "1.0.1", + "dns-equal": "1.0.0", + "dns-txt": "2.0.2", + "multicast-dns": "6.2.3", + "multicast-dns-service-types": "1.1.0" } }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, - "bunyan": { - "version": "1.8.10", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.10.tgz", - "integrity": "sha1-IB/t0mxwgLYy9BYHL1OpC5pSmBw=", - "requires": { - "dtrace-provider": "0.8.3", - "moment": "2.18.1", - "mv": "2.1.1", - "safe-json-stringify": "1.0.4" - } + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" }, "callback-stream": { "version": "1.1.0", @@ -48,7 +66,7 @@ "integrity": "sha1-RwGlEmbwbgbqpx/BcjOCLYdfSQg=", "requires": { "inherits": "2.0.3", - "readable-stream": "2.2.11" + "readable-stream": "2.3.6" } }, "commist": { @@ -58,13 +76,6 @@ "requires": { "leven": "1.0.2", "minimist": "1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } } }, "concat-map": { @@ -73,12 +84,13 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { + "buffer-from": "1.1.0", "inherits": "2.0.3", - "readable-stream": "2.2.11", + "readable-stream": "2.3.6", "typedarray": "0.0.6" } }, @@ -87,48 +99,48 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "dtrace-provider": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.3.tgz", - "integrity": "sha1-uhv8ZJMoXM/PxqtpzVxh10wqQ78=", - "optional": true, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "requires": { + "ip": "1.1.5", + "safe-buffer": "5.1.2" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "requires": { - "nan": "2.6.2" + "buffer-indexof": "1.1.1" } }, "duplexify": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz", - "integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", + "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", "requires": { - "end-of-stream": "1.0.0", + "end-of-stream": "1.4.1", "inherits": "2.0.3", - "readable-stream": "2.2.11", + "readable-stream": "2.3.6", "stream-shift": "1.0.0" - }, - "dependencies": { - "end-of-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", - "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=", - "requires": { - "once": "1.3.3" - } - }, - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "requires": { - "wrappy": "1.0.2" - } - } } }, "end-of-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", - "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { "once": "1.4.0" } @@ -138,25 +150,17 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "0.1.1" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "optional": true, + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { + "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.3", "minimatch": "3.0.4", @@ -183,33 +187,13 @@ "glob-parent": "3.1.0", "is-negated-glob": "1.0.0", "ordered-read-streams": "1.0.1", - "pumpify": "1.3.5", - "readable-stream": "2.2.11", - "remove-trailing-separator": "1.0.2", - "to-absolute-glob": "2.0.1", + "pumpify": "1.5.1", + "readable-stream": "2.3.6", + "remove-trailing-separator": "1.1.0", + "to-absolute-glob": "2.0.2", "unique-stream": "2.2.1" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - } } }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, "help-me": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz", @@ -221,11 +205,6 @@ "xtend": "4.0.1" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -240,20 +219,20 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "is-absolute": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz", - "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "requires": { - "is-relative": "0.2.1", - "is-windows": "0.2.0" + "is-relative": "1.0.0", + "is-windows": "1.0.2" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -273,25 +252,25 @@ "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" }, "is-relative": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz", - "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "requires": { - "is-unc-path": "0.1.2" + "is-unc-path": "1.0.0" } }, "is-unc-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.2.tgz", - "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "requires": { "unc-path-regex": "0.1.2" } }, "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, "isarray": { "version": "1.0.0", @@ -316,122 +295,63 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz", "integrity": "sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=" }, - "lockfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.3.tgz", - "integrity": "sha1-Jjj8OaAzHpysGgS3F5mTHJxQ33k=" - }, - "mdns": { - "version": "file:https:/registry.npmjs.org/mdns/-/mdns-2.3.4.tgz", - "integrity": "sha512-Z4WTKeTukCtJG53SS3BGNnsGkHdIXNZa9nwGMYeoohU1AjEBPS3c/1vIx95SEfeQKYduuOMTo1E4RfXDUt2ZYg==", - "requires": { - "bindings": "1.2.1", - "nan": "2.3.5" - }, - "dependencies": { - "nan": { - "version": "2.3.5", - "bundled": true - } - } - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "1.1.11" } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=", - "optional": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mqtt": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-2.8.2.tgz", - "integrity": "sha512-UBkIR9ZyLvKcC/nWGzPm4qee8TjqZfZK8wVs5SCKxkn9ta81WYjlr4O3/2ayft67O5F+Kx/qLJoC3ovTJR3GSg==", + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-2.18.1.tgz", + "integrity": "sha512-p+RIMFsNb5z65/dy5beKgTnycd3+N8gQ+E2Jnx+0g0OoRza/LCXtUp/vEb3mgWJdljTU+5n4Lc3h0ya994zmVg==", "requires": { "commist": "1.0.0", - "concat-stream": "1.6.0", - "end-of-stream": "1.4.0", + "concat-stream": "1.6.2", + "end-of-stream": "1.4.1", "help-me": "1.1.0", "inherits": "2.0.3", "minimist": "1.2.0", - "mqtt-packet": "5.3.0", - "pump": "1.0.2", - "readable-stream": "2.2.11", + "mqtt-packet": "5.6.0", + "pump": "3.0.0", + "readable-stream": "2.3.6", "reinterval": "1.1.0", - "split2": "2.1.1", - "websocket-stream": "5.0.0", + "split2": "2.2.0", + "websocket-stream": "5.1.2", "xtend": "4.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } } }, "mqtt-packet": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-5.3.0.tgz", - "integrity": "sha1-B47VmuTAb+vzs+rKkLUOl+Jp8gY=", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-5.6.0.tgz", + "integrity": "sha512-QECe2ivqcR1LRsPobRsjenEKAC3i1a5gmm+jNKJLrsiq9PaSQ18LlKFuxvhGxWkvGEPadWv6rKd31O4ICqS1Xw==", "requires": { - "bl": "1.2.1", + "bl": "1.2.2", "inherits": "2.0.3", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.0.1" + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2" } }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "optional": true, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "requires": { - "mkdirp": "0.5.1", - "ncp": "2.0.0", - "rimraf": "2.4.5" + "dns-packet": "1.3.1", + "thunky": "1.0.2" } }, - "nan": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", - "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", - "optional": true - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "optional": true - }, - "node-localstorage": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.3.0.tgz", - "integrity": "sha1-LkNqro3Mms6XtDxlwWwNV3vgpVw=", - "requires": { - "write-file-atomic": "1.3.4" - } + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, "once": { "version": "1.4.0", @@ -446,7 +366,7 @@ "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", "requires": { - "readable-stream": "2.2.11" + "readable-stream": "2.3.6" } }, "path-dirname": { @@ -460,40 +380,51 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "pump": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz", - "integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { - "end-of-stream": "1.4.0", + "end-of-stream": "1.4.1", "once": "1.4.0" } }, "pumpify": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.3.5.tgz", - "integrity": "sha1-G2ccYZlAq8rqwK0OOjwWS+dgmTs=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { - "duplexify": "3.5.0", + "duplexify": "3.6.0", "inherits": "2.0.3", - "pump": "1.0.2" + "pump": "2.0.1" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "1.4.1", + "once": "1.4.0" + } + } } }, "readable-stream": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.11.tgz", - "integrity": "sha512-h+8+r3MKEhkiVrwdKL8aWs1oc1VvBu33ueshOvS26RsZQ3Amhx/oO3TKe4lApSV9ueY6as8EAh7mtuFjdlhg9Q==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.0.1", - "string_decoder": "1.0.2", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", "util-deprecate": "1.0.2" } }, @@ -503,39 +434,19 @@ "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" }, "remove-trailing-separator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", - "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=" - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", - "optional": true, - "requires": { - "glob": "6.0.4" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "safe-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", - "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" - }, - "safe-json-stringify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.4.tgz", - "integrity": "sha1-gaCY9Efku8P/MxKiQ1IbwGDvWRE=", - "optional": true - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "split2": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/split2/-/split2-2.1.1.tgz", - "integrity": "sha1-eh9VHhdqkOzTNF9yRqDP4XXvT9A=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", "requires": { "through2": "2.0.3" } @@ -546,11 +457,11 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, "string_decoder": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", - "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.0.1" + "safe-buffer": "5.1.2" } }, "through2": { @@ -558,7 +469,7 @@ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "requires": { - "readable-stream": "2.2.11", + "readable-stream": "2.3.6", "xtend": "4.0.1" } }, @@ -571,13 +482,17 @@ "xtend": "4.0.1" } }, + "thunky": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", + "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=" + }, "to-absolute-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.1.tgz", - "integrity": "sha1-cMN1gFueMQXome6NvdapqhCPQHs=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "requires": { - "extend-shallow": "2.0.1", - "is-absolute": "0.2.6", + "is-absolute": "1.0.0", "is-negated-glob": "1.0.0" } }, @@ -587,9 +502,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "ultron": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", - "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" }, "unc-path-regex": { "version": "0.1.2", @@ -611,15 +526,15 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "websocket-stream": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.0.0.tgz", - "integrity": "sha1-HRMY8Fds4goSVVNyEIrpQYpANjQ=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.1.2.tgz", + "integrity": "sha512-lchLOk435iDWs0jNuL+hiU14i3ERSrMA0IKSiJh7z6X/i4XNsutBZrtqu2CPOZuA4G/zabiqVAos0vW+S7GEVw==", "requires": { - "duplexify": "3.5.0", + "duplexify": "3.6.0", "inherits": "2.0.3", - "readable-stream": "2.2.11", - "safe-buffer": "5.0.1", - "ws": "3.0.0", + "readable-stream": "2.3.6", + "safe-buffer": "5.1.2", + "ws": "3.3.3", "xtend": "4.0.1" } }, @@ -628,23 +543,14 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "slide": "1.1.6" - } - }, "ws": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.0.0.tgz", - "integrity": "sha1-mN2wAFbIOQy3Ued4h4hJf5kQO2w=", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "requires": { - "safe-buffer": "5.0.1", - "ultron": "1.1.0" + "async-limiter": "1.0.0", + "safe-buffer": "5.1.2", + "ultron": "1.1.1" } }, "xtend": { diff --git a/lib/jdiscovery/package.json b/lib/jdiscovery/package.json index d41366f7..44996959 100644 --- a/lib/jdiscovery/package.json +++ b/lib/jdiscovery/package.json @@ -1,31 +1,18 @@ { "name": "jdiscovery", - "version": "0.0.7", - "description": "For testing registration/discovery in JAM", - "main": "jregistrar.js", - "author": "Keith Strickling", - "license": "MIT", - "dependencies": { - "bunyan": "^1.8.10", - "lockfile": "^1.0.3", - "mdns": "file:mdns", - "mqtt": "^2.4.0", - "node-localstorage": "^1.3.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/anrl/JAMScript-beta/lib/jdiscovery" + "version": "1.0.0", + "description": "Discovery service for JAMScript", + "main": "jregistrar-head.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ - "JAMScript", - "Registry", - "Device Discovery Framework" + "discovery" ], - "preferGlobal": true, - "files": [ - "*.js", - "mdns", - "build", - "errlog" - ] + "author": "Keith Strickling, Michael Saraga", + "license": "MIT", + "dependencies": { + "bonjour": "^3.5.0", + "mqtt": "^2.18.1" + } } diff --git a/lib/jdiscovery/registry.js b/lib/jdiscovery/registry.js index 2cf9b31c..57eabebc 100644 --- a/lib/jdiscovery/registry.js +++ b/lib/jdiscovery/registry.js @@ -5,9 +5,9 @@ var EventEmitter = require('events').EventEmitter, constants = require('../jamserver/constants'); -function Registry(app, machType, id, port) { +function Registry(app, type, id, port) { this.app = app; - this.machType = machType; + this.type = type; this.id = id; this.port = port; } diff --git a/samples b/samples index 1f2ac379..69f6d869 160000 --- a/samples +++ b/samples @@ -1 +1 @@ -Subproject commit 1f2ac3796064f2d3f7da62d89f88fae2fe733dce +Subproject commit 69f6d869e07cd48af53c732b0c4932846cacd723 diff --git a/tools b/tools index 0a7e6738..44c53172 160000 --- a/tools +++ b/tools @@ -1 +1 @@ -Subproject commit 0a7e6738f9ce43f8903b2da8294e8535eefc9452 +Subproject commit 44c53172052d4125deda5346f1dc2f4fbfa80ba3