'use strict';
var request = require('request');
var rp = require('request-promise');
var Q = require('q');
var xml2js = require('xml2js');
/**
* Foscam Client SDK
* @class
* @param {object} config
* @param {string} config.username Username of a valid Foscam user.
* @param {string} config.password Password of the Foscam user.
* @param {string} config.host Host or IP address of the Foscam
* @param {string} [config.port] Optional port to use. Defaults to 88.
* @param {string} [config.protocol] Optional protocol to use. Defaults to http.
* @constructor
*/
function Foscam(config) {
if (!config) {
throw new Error('no config was supplied');
}
this.username = config.username;
this.password = config.password;
this.address = config.host;
this.port = config.port || 88;
this.protocol = config.protocol || 'http';
this.rejectUnauthorizedCerts = 'rejectUnauthorizedCerts' in config ? config.rejectUnauthorizedCerts : true;
this.baseUrl = this.protocol + '://' + this.address + ':' + this.port;
this.url = this.baseUrl + '/cgi-bin/CGIProxy.fcgi';
this.streamUrl = this.baseUrl + '/cgi-bin/CGIStream.cgi';
this.rpClient = rp.defaults({
rejectUnauthorized: this.rejectUnauthorizedCerts,
qs: {
usr: this.username,
pwd: this.password
}
});
}
/**
* get
* @desc Sends an API request to the camera and parses the response.
* @param {string} command CGI command to send
* @param {object} [params] Params to include with the request
* @returns {Promise<object>} A promise to the response.
*/
Foscam.prototype.get = function(command, params) {
return this.getRaw(command, params)
.then(function(response) {
return Foscam.parseResponse(response);
});
};
/**
* getRaw
* @desc Sends an API request to the camera and returns the raw response.
* @param {string} command CGI command to send.
* @param {object} [params] Params to include with the request.
* @param {object} [options] Additional options to pass to request-promise
* @returns {Promise<object>} A promise to the response.
*/
Foscam.prototype.getRaw = function(command, params, options) {
params = params ? params : {};
params.cmd = command;
options = options || {};
options.qs = params;
return this.rpClient.get(this.url, options);
};
Foscam.prototype.stream = function(command) {
var options = {
uri: this.streamUrl
};
options.qs = {
cmd: command,
usr: this.username,
pwd: this.password
};
return request.get(options);
};
/**
* notImplemented
* @desc Generic method to throw an error for API methods that haven't been implemented yet
* @private
*/
Foscam.prototype.notImplemented = function() {
throw new Error('That method has not been implemented yet');
};
/**
* parseResponse
* @desc Parses the response from the camera API request
* @param {string} xml XML response
* @returns {Promise<object>} A promise to the response.
*/
Foscam.parseResponse = function(xml) {
var deferred = Q.defer();
var options = {
valueProcessors: [this.parseNumbers],
explicitArray: false
};
if (xml) {
xml2js.parseString(xml, options, function(err, parsed) {
if (!err && parsed) {
if (parsed && parsed.CGI_Result) {
deferred.resolve(parsed.CGI_Result);
} else {
deferred.resolve(parsed);
}
} else {
deferred.resolve(xml);
}
});
} else {
deferred.resolve(xml);
}
return deferred.promise;
};
Foscam.numberToBoolean = function(object, property) {
// Don't set the property if is doesn't already exist
if (object && property && object.hasOwnProperty(property)) {
// Only convert 1 and 0 - ignore other numbers.
if (object[property] === 1) {
object[property] = true;
} else if (object[property] === 0) {
object[property] = false;
}
}
};
Foscam.booleanToNumber = function(bool, defaultValue) {
if (bool === true || bool === false) {
bool = bool === true ? 1 : 0;
} else if (arguments.length > 1) {
bool = defaultValue;
}
return bool;
};
Foscam.parseNumbers = function(str) {
if (str && !isNaN(str) && str.toUpperCase().indexOf('E') < 0) {
str = str % 1 === 0 ? parseInt(str, 10) : parseFloat(str);
}
return str;
};
module.exports = Foscam;