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";
|
||||
|
||||
var fs = require('fs');
|
||||
var fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
var express = require('express'),
|
||||
bodyParser = require('body-parser');
|
||||
|
||||
var Logger = require('./logger');
|
||||
var Cylon = require('./cylon'),
|
||||
Logger = require('./logger');
|
||||
|
||||
var API = module.exports = function API(opts) {
|
||||
var self = this;
|
||||
|
@ -22,11 +24,10 @@ var API = module.exports = function API(opts) {
|
|||
opts = {};
|
||||
}
|
||||
|
||||
this.opts = opts;
|
||||
this.host = opts.host || "127.0.0.1";
|
||||
this.port = opts.port || "3000";
|
||||
this.ssl = opts.ssl;
|
||||
this.master = opts.master;
|
||||
for (var d in this.defaults) {
|
||||
this[d] = opts.hasOwnProperty(d) ? opts[d] : this.defaults[d];
|
||||
}
|
||||
|
||||
this.server = express();
|
||||
|
||||
//configure ssl if requested
|
||||
|
@ -34,8 +35,8 @@ var API = module.exports = function API(opts) {
|
|||
var https = require('https');
|
||||
|
||||
var options = {
|
||||
key: fs.readFileSync(this.ssl.key || __dirname + "/ssl/server.key"),
|
||||
cert: fs.readFileSync(this.ssl.cert || __dirname + "/ssl/server.crt")
|
||||
key: fs.readFileSync(this.ssl.key),
|
||||
cert: fs.readFileSync(this.ssl.cert)
|
||||
};
|
||||
|
||||
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/"));
|
||||
};
|
||||
|
||||
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() {
|
||||
var self = this;
|
||||
|
||||
|
@ -93,8 +105,6 @@ API.prototype.parseCommandParams = function(req) {
|
|||
API.prototype.configureRoutes = function() {
|
||||
var self = this;
|
||||
|
||||
var master = this.master;
|
||||
|
||||
this.server.all("/*", function(req, res, next) {
|
||||
res.set("Access-Control-Allow-Origin", self.opts.CORS || "*");
|
||||
res.set("Access-Control-Allow-Headers", "Content-Type");
|
||||
|
@ -105,8 +115,8 @@ API.prototype.configureRoutes = function() {
|
|||
this.server.get("/robots", function(req, res) {
|
||||
var data = [];
|
||||
|
||||
for (var i = 0; i < master.robots.length; i++) {
|
||||
var robot = master.robots[i];
|
||||
for (var i = 0; i < Cylon.robots.length; i++) {
|
||||
var robot = Cylon.robots[i];
|
||||
data.push(robot.data());
|
||||
}
|
||||
|
||||
|
@ -114,13 +124,13 @@ API.prototype.configureRoutes = function() {
|
|||
});
|
||||
|
||||
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());
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
@ -128,7 +138,7 @@ API.prototype.configureRoutes = function() {
|
|||
this.server.all("/robots/:robot/commands/:command", function(req, res) {
|
||||
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); }
|
||||
|
||||
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) {
|
||||
master.findRobot(req.params.robot, function(err, robot) {
|
||||
Cylon.findRobot(req.params.robot, function(err, robot) {
|
||||
res.json(err ? err : robot.data().devices);
|
||||
});
|
||||
});
|
||||
|
@ -146,7 +156,7 @@ API.prototype.configureRoutes = function() {
|
|||
var robot = req.params.robot,
|
||||
device = req.params.device;
|
||||
|
||||
master.findRobotDevice(robot, device, function(err, device) {
|
||||
Cylon.findRobotDevice(robot, device, function(err, device) {
|
||||
res.json(err ? err : device.data());
|
||||
});
|
||||
});
|
||||
|
@ -156,7 +166,7 @@ API.prototype.configureRoutes = function() {
|
|||
device = req.params.device,
|
||||
event = req.params.event;
|
||||
|
||||
master.findRobotDevice(robot, device, function(err, device) {
|
||||
Cylon.findRobotDevice(robot, device, function(err, device) {
|
||||
if (err) { res.json(err); }
|
||||
|
||||
res.writeHead(200, {
|
||||
|
@ -181,7 +191,7 @@ API.prototype.configureRoutes = function() {
|
|||
var robot = req.params.robot,
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
@ -193,7 +203,7 @@ API.prototype.configureRoutes = function() {
|
|||
|
||||
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); }
|
||||
|
||||
var result = device[command].apply(device, params);
|
||||
|
@ -202,7 +212,7 @@ API.prototype.configureRoutes = function() {
|
|||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
@ -211,7 +221,7 @@ API.prototype.configureRoutes = function() {
|
|||
var robot = req.params.robot,
|
||||
connection = req.params.connection;
|
||||
|
||||
master.findRobotConnection(robot, connection, function(err, connection) {
|
||||
Cylon.findRobotConnection(robot, connection, function(err, connection) {
|
||||
res.json(err ? err : connection.data());
|
||||
});
|
||||
});
|
||||
|
|
50
lib/cylon.js
50
lib/cylon.js
|
@ -8,7 +8,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var Logger = require('./logger'),
|
||||
var API = require('./api'),
|
||||
Logger = require('./logger'),
|
||||
Robot = require('./robot'),
|
||||
Utils = require('./utils');
|
||||
|
||||
|
@ -25,15 +26,7 @@ var Cylon = module.exports = {
|
|||
|
||||
api_instance: null,
|
||||
|
||||
robots: [],
|
||||
|
||||
api_config: {
|
||||
host: '127.0.0.1',
|
||||
port: '3000',
|
||||
auth: {},
|
||||
CORS: null,
|
||||
ssl: {}
|
||||
}
|
||||
robots: []
|
||||
};
|
||||
|
||||
// Public: Creates a new Robot
|
||||
|
@ -55,28 +48,18 @@ Cylon.robot = function robot(opts) {
|
|||
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
|
||||
// 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) {
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
|
||||
var keys = ['host', 'port', 'auth', 'CORS', 'ssl'];
|
||||
|
||||
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;
|
||||
this.api_instance = new API(opts);
|
||||
this.api_instance.listen();
|
||||
};
|
||||
|
||||
// Public: Finds a particular robot by name
|
||||
|
@ -153,8 +136,6 @@ Cylon.findRobotConnection = function findRobotConnection(robotid, connid, callba
|
|||
//
|
||||
// Returns nothing
|
||||
Cylon.start = function start() {
|
||||
this.startAPI();
|
||||
|
||||
for (var i = 0; i < this.robots.length; i++) {
|
||||
var robot = this.robots[i];
|
||||
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") {
|
||||
var readline = require("readline"),
|
||||
io = { input: process.stdin, output: process.stdout };
|
||||
|
|
|
@ -14,8 +14,6 @@ describe("API", function() {
|
|||
beforeEach(function() {
|
||||
stub(https, 'createServer').returns({ listen: spy() });
|
||||
|
||||
opts = { master: { name: 'master' }, ssl: {} }
|
||||
|
||||
api = new API(opts);
|
||||
});
|
||||
|
||||
|
@ -35,10 +33,6 @@ describe("API", function() {
|
|||
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() {
|
||||
expect(api.server).to.be.a('function');
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
var Cylon = source("cylon");
|
||||
|
||||
var Logger = source('logger'),
|
||||
var API = source('api'),
|
||||
Logger = source('logger'),
|
||||
Adaptor = source('adaptor'),
|
||||
Driver = source('driver');
|
||||
|
||||
|
@ -25,14 +26,6 @@ describe("Cylon", function() {
|
|||
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() {
|
||||
expect(Cylon.robots).to.be.eql([]);
|
||||
});
|
||||
|
@ -52,94 +45,23 @@ describe("Cylon", function() {
|
|||
});
|
||||
|
||||
describe("#api", function() {
|
||||
var expectedConfig;
|
||||
|
||||
beforeEach(function() {
|
||||
expectedConfig = {
|
||||
host: '127.0.0.1',
|
||||
port: '3000',
|
||||
auth: {},
|
||||
CORS: null,
|
||||
ssl: {}
|
||||
};
|
||||
stub(API.prototype, 'listen');
|
||||
});
|
||||
|
||||
// this is the shortest, cheapest way to dup an object in JS.
|
||||
// I don't like it either.
|
||||
Cylon.api_config = JSON.parse(JSON.stringify(expectedConfig));
|
||||
afterEach(function() {
|
||||
API.prototype.listen.restore();
|
||||
});
|
||||
|
||||
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() {
|
||||
|
@ -308,16 +230,6 @@ describe("Cylon", function() {
|
|||
describe("#start", function() {
|
||||
before(function() {
|
||||
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() {
|
||||
|
|
Loading…
Reference in New Issue