thali
Version:
152 lines (135 loc) • 4.43 kB
JavaScript
'use strict';
var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
var Promise = require('lie');
var nodessdp = require('node-ssdp');
var ip = require('ip');
var crypto = require('crypto');
var THALI_USN = 'urn:schemas-upnp-org:service:Thali';
function ThaliWifiInfrastructure (deviceName, port) {
EventEmitter.call(this);
this.thaliUsn = THALI_USN;
this.deviceName = deviceName || crypto.randomBytes(16).toString('base64');
this.port = port || 0;
this.listening = null;
this.advertising = null;
// A variable to hold information about known peer availability states
// and used to avoid emitting peer availability changes in case the
// availability hasn't changed from the previous known value.
this.peerAvailabilities = {};
this._init(deviceName);
}
inherits(ThaliWifiInfrastructure, EventEmitter);
ThaliWifiInfrastructure.prototype._init = function () {
var serverOptions = {
adInterval: 500,
allowWildcards: true,
logJSON: false,
logLevel: 'trace',
udn: this.deviceName
};
this._server = new nodessdp.Server(serverOptions);
this._setLocation();
this._client = new nodessdp.Client({
allowWildcards: true,
logJSON: false,
logLevel: 'trace'
});
this._client.on('advertise-alive', function (data) {
this._handleMessage(data, true);
}.bind(this));
this._client.on('advertise-bye', function (data) {
this._handleMessage(data, false);
}.bind(this));
};
ThaliWifiInfrastructure.prototype._setLocation = function (address, port, path) {
address = address || ip.address();
port = port || this.port;
path = path || 'NotificationBeacons';
this._server._location = 'http://' + address + ':' + port + '/' + path;
};
ThaliWifiInfrastructure.prototype._handleMessage = function (data, available) {
if (this.shouldBeIgnored(data)) {
return;
}
var peer = {
peerIdentifier: data.USN,
peerLocation: data.LOCATION,
peerAvailable: available
};
if (this.peerAvailabilities[peer.peerIdentifier] === available) {
return;
}
this.peerAvailabilities[peer.peerIdentifier] = available;
this.emit('wifiPeerAvailabilityChanged', [peer]);
};
ThaliWifiInfrastructure.prototype.startListeningForAdvertisements = function () {
var self = this;
if (this.listening) {
return Promise.resolve();
}
this.listening = true;
return new Promise(function(resolve, reject) {
self._client.start(function () {
resolve();
});
});
};
ThaliWifiInfrastructure.prototype.stopListeningForAdvertisements = function () {
var self = this;
if (!this.listening) {
return Promise.resolve();
}
this.listening = false;
return new Promise(function(resolve, reject) {
self._client.stop(function () {
resolve();
});
});
};
ThaliWifiInfrastructure.prototype.startUpdateAdvertisingAndListenForIncomingConnections = function () {
var self = this;
// TODO: USN should be regenerated every time this method is called, because
// according to the specification, that happens when the beacon string is changed.
// Is below enough or should we use some uuid library or something else?
var randomString = crypto.randomBytes(16).toString('base64');
// TODO: Appends to USN list, but does not remove.
this._server.addUSN(this.thaliUsn + '::' + randomString);
if (this.advertising) {
return Promise.resolve();
}
this.advertising = true;
return new Promise(function(resolve, reject) {
self._server.start(function () {
resolve();
});
});
};
ThaliWifiInfrastructure.prototype.stopAdvertisingAndListeningForIncomingConnections = function () {
var self = this;
if (!this.advertising) {
return Promise.resolve();
}
this.advertising = false;
return new Promise(function(resolve, reject) {
self._server.stop(function () {
resolve();
});
});
};
// Function used to filter out SSDP messages that are not
// relevant for Thali.
ThaliWifiInfrastructure.prototype.shouldBeIgnored = function (data) {
// First check if the data contains the Thali-specific USN.
if (data.USN.indexOf(this.thaliUsn) >= 0) {
// We also discover ourself via SSDP to need to filter
// out the messages that are originating from this device.
if (data.USN.indexOf(this.deviceName) === 0) {
return true;
} else {
return false;
}
}
return true;
};
module.exports = ThaliWifiInfrastructure;