Move configuration to API class
This commit is contained in:
parent
e08a5df88b
commit
6bc1e9d944
56
lib/api.js
56
lib/api.js
|
@ -8,12 +8,14 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs'),
|
||||||
|
path = require('path');
|
||||||
|
|
||||||
var express = require('express'),
|
var express = require('express'),
|
||||||
bodyParser = require('body-parser');
|
bodyParser = require('body-parser');
|
||||||
|
|
||||||
var Logger = require('./logger');
|
var Cylon = require('./cylon'),
|
||||||
|
Logger = require('./logger');
|
||||||
|
|
||||||
var API = module.exports = function API(opts) {
|
var API = module.exports = function API(opts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -22,11 +24,10 @@ var API = module.exports = function API(opts) {
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.opts = opts;
|
for (var d in this.defaults) {
|
||||||
this.host = opts.host || "127.0.0.1";
|
this[d] = opts.hasOwnProperty(d) ? opts[d] : this.defaults[d];
|
||||||
this.port = opts.port || "3000";
|
}
|
||||||
this.ssl = opts.ssl;
|
|
||||||
this.master = opts.master;
|
|
||||||
this.server = express();
|
this.server = express();
|
||||||
|
|
||||||
//configure ssl if requested
|
//configure ssl if requested
|
||||||
|
@ -34,8 +35,8 @@ var API = module.exports = function API(opts) {
|
||||||
var https = require('https');
|
var https = require('https');
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
key: fs.readFileSync(this.ssl.key || __dirname + "/ssl/server.key"),
|
key: fs.readFileSync(this.ssl.key),
|
||||||
cert: fs.readFileSync(this.ssl.cert || __dirname + "/ssl/server.crt")
|
cert: fs.readFileSync(this.ssl.cert)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.server.node = https.createServer(options, this.server);
|
this.server.node = https.createServer(options, this.server);
|
||||||
|
@ -59,6 +60,17 @@ var API = module.exports = function API(opts) {
|
||||||
this.server.use(express["static"](__dirname + "/../node_modules/robeaux/"));
|
this.server.use(express["static"](__dirname + "/../node_modules/robeaux/"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
API.prototype.defaults = {
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '3000',
|
||||||
|
auth: false,
|
||||||
|
CORS: '',
|
||||||
|
ssl: {
|
||||||
|
key: path.normalize(__dirname + "/ssl/server.key"),
|
||||||
|
cert: path.normalize(__dirname + "/ssl/server.crt")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
API.prototype.listen = function() {
|
API.prototype.listen = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
@ -93,8 +105,6 @@ API.prototype.parseCommandParams = function(req) {
|
||||||
API.prototype.configureRoutes = function() {
|
API.prototype.configureRoutes = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var master = this.master;
|
|
||||||
|
|
||||||
this.server.all("/*", function(req, res, next) {
|
this.server.all("/*", function(req, res, next) {
|
||||||
res.set("Access-Control-Allow-Origin", self.opts.CORS || "*");
|
res.set("Access-Control-Allow-Origin", self.opts.CORS || "*");
|
||||||
res.set("Access-Control-Allow-Headers", "Content-Type");
|
res.set("Access-Control-Allow-Headers", "Content-Type");
|
||||||
|
@ -105,8 +115,8 @@ API.prototype.configureRoutes = function() {
|
||||||
this.server.get("/robots", function(req, res) {
|
this.server.get("/robots", function(req, res) {
|
||||||
var data = [];
|
var data = [];
|
||||||
|
|
||||||
for (var i = 0; i < master.robots.length; i++) {
|
for (var i = 0; i < Cylon.robots.length; i++) {
|
||||||
var robot = master.robots[i];
|
var robot = Cylon.robots[i];
|
||||||
data.push(robot.data());
|
data.push(robot.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,13 +124,13 @@ API.prototype.configureRoutes = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server.get("/robots/:robot", function(req, res) {
|
this.server.get("/robots/:robot", function(req, res) {
|
||||||
master.findRobot(req.params.robot, function(err, robot) {
|
Cylon.findRobot(req.params.robot, function(err, robot) {
|
||||||
res.json(err ? err : robot.data());
|
res.json(err ? err : robot.data());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server.get("/robots/:robot/commands", function(req, res) {
|
this.server.get("/robots/:robot/commands", function(req, res) {
|
||||||
master.findRobot(req.params.robot, function(err, robot) {
|
Cylon.findRobot(req.params.robot, function(err, robot) {
|
||||||
res.json(err ? err : robot.data().commands);
|
res.json(err ? err : robot.data().commands);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -128,7 +138,7 @@ API.prototype.configureRoutes = function() {
|
||||||
this.server.all("/robots/:robot/commands/:command", function(req, res) {
|
this.server.all("/robots/:robot/commands/:command", function(req, res) {
|
||||||
var params = self.parseCommandParams(req);
|
var params = self.parseCommandParams(req);
|
||||||
|
|
||||||
master.findRobot(req.params.robot, function(err, robot) {
|
Cylon.findRobot(req.params.robot, function(err, robot) {
|
||||||
if (err) { return res.json(err); }
|
if (err) { return res.json(err); }
|
||||||
|
|
||||||
var result = robot[req.params.command].apply(robot, params);
|
var result = robot[req.params.command].apply(robot, params);
|
||||||
|
@ -137,7 +147,7 @@ API.prototype.configureRoutes = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server.get("/robots/:robot/devices", function(req, res) {
|
this.server.get("/robots/:robot/devices", function(req, res) {
|
||||||
master.findRobot(req.params.robot, function(err, robot) {
|
Cylon.findRobot(req.params.robot, function(err, robot) {
|
||||||
res.json(err ? err : robot.data().devices);
|
res.json(err ? err : robot.data().devices);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -146,7 +156,7 @@ API.prototype.configureRoutes = function() {
|
||||||
var robot = req.params.robot,
|
var robot = req.params.robot,
|
||||||
device = req.params.device;
|
device = req.params.device;
|
||||||
|
|
||||||
master.findRobotDevice(robot, device, function(err, device) {
|
Cylon.findRobotDevice(robot, device, function(err, device) {
|
||||||
res.json(err ? err : device.data());
|
res.json(err ? err : device.data());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -156,7 +166,7 @@ API.prototype.configureRoutes = function() {
|
||||||
device = req.params.device,
|
device = req.params.device,
|
||||||
event = req.params.event;
|
event = req.params.event;
|
||||||
|
|
||||||
master.findRobotDevice(robot, device, function(err, device) {
|
Cylon.findRobotDevice(robot, device, function(err, device) {
|
||||||
if (err) { res.json(err); }
|
if (err) { res.json(err); }
|
||||||
|
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
|
@ -181,7 +191,7 @@ API.prototype.configureRoutes = function() {
|
||||||
var robot = req.params.robot,
|
var robot = req.params.robot,
|
||||||
device = req.params.device;
|
device = req.params.device;
|
||||||
|
|
||||||
master.findRobotDevice(robot, device, function(err, device) {
|
Cylon.findRobotDevice(robot, device, function(err, device) {
|
||||||
res.json(err ? err : device.data().commands);
|
res.json(err ? err : device.data().commands);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -193,7 +203,7 @@ API.prototype.configureRoutes = function() {
|
||||||
|
|
||||||
var params = self.parseCommandParams(req);
|
var params = self.parseCommandParams(req);
|
||||||
|
|
||||||
master.findRobotDevice(robot, device, function(err, device) {
|
Cylon.findRobotDevice(robot, device, function(err, device) {
|
||||||
if (err) { return res.json(err); }
|
if (err) { return res.json(err); }
|
||||||
|
|
||||||
var result = device[command].apply(device, params);
|
var result = device[command].apply(device, params);
|
||||||
|
@ -202,7 +212,7 @@ API.prototype.configureRoutes = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server.get("/robots/:robot/connections", function(req, res) {
|
this.server.get("/robots/:robot/connections", function(req, res) {
|
||||||
master.findRobot(req.params.robot, function(err, robot) {
|
Cylon.findRobot(req.params.robot, function(err, robot) {
|
||||||
res.json(err ? err : robot.data().connections);
|
res.json(err ? err : robot.data().connections);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -211,7 +221,7 @@ API.prototype.configureRoutes = function() {
|
||||||
var robot = req.params.robot,
|
var robot = req.params.robot,
|
||||||
connection = req.params.connection;
|
connection = req.params.connection;
|
||||||
|
|
||||||
master.findRobotConnection(robot, connection, function(err, connection) {
|
Cylon.findRobotConnection(robot, connection, function(err, connection) {
|
||||||
res.json(err ? err : connection.data());
|
res.json(err ? err : connection.data());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
50
lib/cylon.js
50
lib/cylon.js
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Logger = require('./logger'),
|
var API = require('./api'),
|
||||||
|
Logger = require('./logger'),
|
||||||
Robot = require('./robot'),
|
Robot = require('./robot'),
|
||||||
Utils = require('./utils');
|
Utils = require('./utils');
|
||||||
|
|
||||||
|
@ -25,15 +26,7 @@ var Cylon = module.exports = {
|
||||||
|
|
||||||
api_instance: null,
|
api_instance: null,
|
||||||
|
|
||||||
robots: [],
|
robots: []
|
||||||
|
|
||||||
api_config: {
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '3000',
|
|
||||||
auth: {},
|
|
||||||
CORS: null,
|
|
||||||
ssl: {}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public: Creates a new Robot
|
// Public: Creates a new Robot
|
||||||
|
@ -55,28 +48,18 @@ Cylon.robot = function robot(opts) {
|
||||||
return robot;
|
return robot;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public: Configures the API host and port based on passed options
|
// Public: Creates a new API based on passed options
|
||||||
//
|
//
|
||||||
// opts - object containing API options
|
// opts - object containing API options
|
||||||
// host - host address API should serve from
|
|
||||||
// port - port API should listen for requests on
|
|
||||||
//
|
//
|
||||||
// Returns the API configuration
|
// Returns nothing
|
||||||
Cylon.api = function api(opts) {
|
Cylon.api = function api(opts) {
|
||||||
if (opts == null) {
|
if (opts == null) {
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys = ['host', 'port', 'auth', 'CORS', 'ssl'];
|
this.api_instance = new API(opts);
|
||||||
|
this.api_instance.listen();
|
||||||
for (var i = 0; i < keys.length; i++) {
|
|
||||||
var key = keys[i];
|
|
||||||
if (typeof opts[key] !== "undefined") {
|
|
||||||
this.api_config[key] = opts[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.api_config;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public: Finds a particular robot by name
|
// Public: Finds a particular robot by name
|
||||||
|
@ -153,8 +136,6 @@ Cylon.findRobotConnection = function findRobotConnection(robotid, connid, callba
|
||||||
//
|
//
|
||||||
// Returns nothing
|
// Returns nothing
|
||||||
Cylon.start = function start() {
|
Cylon.start = function start() {
|
||||||
this.startAPI();
|
|
||||||
|
|
||||||
for (var i = 0; i < this.robots.length; i++) {
|
for (var i = 0; i < this.robots.length; i++) {
|
||||||
var robot = this.robots[i];
|
var robot = this.robots[i];
|
||||||
robot.start();
|
robot.start();
|
||||||
|
@ -171,23 +152,6 @@ Cylon.halt = function halt() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Creates a new instance of the Cylon API server, or returns the
|
|
||||||
// already-existing one.
|
|
||||||
//
|
|
||||||
// Returns an Cylon.ApiServer instance
|
|
||||||
Cylon.startAPI = function startAPI() {
|
|
||||||
var API = require('./api');
|
|
||||||
this.api_config.master = this;
|
|
||||||
|
|
||||||
if (this.api_instance === null) {
|
|
||||||
this.api_instance = new API(this.api_config);
|
|
||||||
this.api_instance.configureRoutes();
|
|
||||||
this.api_instance.listen();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.api_instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
var readline = require("readline"),
|
var readline = require("readline"),
|
||||||
io = { input: process.stdin, output: process.stdout };
|
io = { input: process.stdin, output: process.stdout };
|
||||||
|
|
|
@ -14,8 +14,6 @@ describe("API", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
stub(https, 'createServer').returns({ listen: spy() });
|
stub(https, 'createServer').returns({ listen: spy() });
|
||||||
|
|
||||||
opts = { master: { name: 'master' }, ssl: {} }
|
|
||||||
|
|
||||||
api = new API(opts);
|
api = new API(opts);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -35,10 +33,6 @@ describe("API", function() {
|
||||||
expect(api.port).to.be.eql("3000")
|
expect(api.port).to.be.eql("3000")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets @master to the passed master", function() {
|
|
||||||
expect(api.master).to.be.eql(opts.master)
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @server to an Express server instance", function() {
|
it("sets @server to an Express server instance", function() {
|
||||||
expect(api.server).to.be.a('function');
|
expect(api.server).to.be.a('function');
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
var Cylon = source("cylon");
|
var Cylon = source("cylon");
|
||||||
|
|
||||||
var Logger = source('logger'),
|
var API = source('api'),
|
||||||
|
Logger = source('logger'),
|
||||||
Adaptor = source('adaptor'),
|
Adaptor = source('adaptor'),
|
||||||
Driver = source('driver');
|
Driver = source('driver');
|
||||||
|
|
||||||
|
@ -25,14 +26,6 @@ describe("Cylon", function() {
|
||||||
expect(Cylon.api_instance).to.be.eql(null);
|
expect(Cylon.api_instance).to.be.eql(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets @api_config to an object containing host/port info", function() {
|
|
||||||
var config = Cylon.api_config;
|
|
||||||
|
|
||||||
expect(config).to.be.an('object');
|
|
||||||
expect(config.host).to.be.eql('127.0.0.1');
|
|
||||||
expect(config.port).to.be.eql('3000');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @robots to an empty array by default", function() {
|
it("sets @robots to an empty array by default", function() {
|
||||||
expect(Cylon.robots).to.be.eql([]);
|
expect(Cylon.robots).to.be.eql([]);
|
||||||
});
|
});
|
||||||
|
@ -52,94 +45,23 @@ describe("Cylon", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#api", function() {
|
describe("#api", function() {
|
||||||
var expectedConfig;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
expectedConfig = {
|
stub(API.prototype, 'listen');
|
||||||
host: '127.0.0.1',
|
});
|
||||||
port: '3000',
|
|
||||||
auth: {},
|
|
||||||
CORS: null,
|
|
||||||
ssl: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is the shortest, cheapest way to dup an object in JS.
|
afterEach(function() {
|
||||||
// I don't like it either.
|
API.prototype.listen.restore();
|
||||||
Cylon.api_config = JSON.parse(JSON.stringify(expectedConfig));
|
});
|
||||||
|
|
||||||
|
it('creates a new API instance', function() {
|
||||||
|
Cylon.api();
|
||||||
|
expect(Cylon.api_instance).to.be.an.instanceOf(API);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes arguments to the API constructor', function() {
|
||||||
|
Cylon.api({ port: '1234' });
|
||||||
|
expect(Cylon.api_instance.port).to.be.eql('1234');
|
||||||
})
|
})
|
||||||
|
|
||||||
context("without arguments", function() {
|
|
||||||
it("returns the current API configuration", function() {
|
|
||||||
Cylon.api();
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("only specifying port", function() {
|
|
||||||
it("changes the port, but not the host", function() {
|
|
||||||
expectedConfig.port = "4000";
|
|
||||||
|
|
||||||
Cylon.api({ port: "4000" });
|
|
||||||
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("only specifying host", function() {
|
|
||||||
it("changes the host, but not the port", function() {
|
|
||||||
expectedConfig.host = "0.0.0.0";
|
|
||||||
Cylon.api({ host: "0.0.0.0" });
|
|
||||||
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("specifying new host and port", function() {
|
|
||||||
it("changes both the host and port", function() {
|
|
||||||
expectedConfig.host = "0.0.0.0";
|
|
||||||
expectedConfig.port = "4000";
|
|
||||||
|
|
||||||
Cylon.api({ host: "0.0.0.0", port: "4000" });
|
|
||||||
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("specifiying SSL key and cert", function() {
|
|
||||||
it("changes the SSL key and cert", function() {
|
|
||||||
expectedConfig.ssl.cert = "/path/to/cert/file";
|
|
||||||
expectedConfig.ssl.key = "/path/to/key/file";
|
|
||||||
|
|
||||||
Cylon.api({
|
|
||||||
ssl: {
|
|
||||||
cert: "/path/to/cert/file",
|
|
||||||
key: "/path/to/key/file"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("specifying an auth strategy", function() {
|
|
||||||
it("changes the auth strategy", function() {
|
|
||||||
var auth = { type: 'basic', user: 'user', pass: 'pass'}
|
|
||||||
expectedConfig.auth = auth;
|
|
||||||
Cylon.api({ auth: auth })
|
|
||||||
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("specifying CORS restrictions", function() {
|
|
||||||
it("changes the CORS restrictions", function() {
|
|
||||||
var CORS = "https://localhost:4000";
|
|
||||||
expectedConfig.CORS = CORS;
|
|
||||||
Cylon.api({ CORS: CORS })
|
|
||||||
|
|
||||||
expect(Cylon.api_config).to.be.eql(expectedConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#findRobot", function() {
|
describe("#findRobot", function() {
|
||||||
|
@ -308,16 +230,6 @@ describe("Cylon", function() {
|
||||||
describe("#start", function() {
|
describe("#start", function() {
|
||||||
before(function() {
|
before(function() {
|
||||||
Cylon.robots = [];
|
Cylon.robots = [];
|
||||||
stub(Cylon, 'startAPI').returns(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
after(function() {
|
|
||||||
Cylon.startAPI.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("starts the API", function() {
|
|
||||||
Cylon.start();
|
|
||||||
expect(Cylon.startAPI).to.be.called;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls #start() on all robots", function() {
|
it("calls #start() on all robots", function() {
|
||||||
|
|
Loading…
Reference in New Issue