Merge pull request #253 from hybridgroup/feature/cppp-io-updates

Add event listings to API
This commit is contained in:
Ron Evans 2015-01-06 14:17:48 -08:00
commit fe4c899f7f
9 changed files with 137 additions and 22 deletions

View File

@ -35,7 +35,7 @@ var Adaptor = module.exports = function Adaptor(opts) {
this.details = {};
_.forEach(opts, function(opt, name) {
if (_.include(["robot", "name", "adaptor"], name)) {
if (_.include(["robot", "name", "adaptor", "events"], name)) {
return;
}

View File

@ -14,6 +14,12 @@ var Cylon = require("../cylon");
var router = module.exports = require("express").Router();
var eventHeaders = {
"Content-Type": "text/event-stream",
"Connection": "keep-alive",
"Cache-Control": "no-cache"
};
// Loads up the appropriate Robot/Device/Connection instances, if they are
// present in the route params.
var load = function load(req, res, next) {
@ -55,6 +61,26 @@ router.get("/", function(req, res) {
res.json({ MCP: Cylon.toJSON() });
});
router.get("/events", function(req, res) {
res.json({ events: Cylon.events });
});
router.get("/events/:event", function(req, res) {
var event = req.params.event;
res.writeHead(200, eventHeaders);
var writeData = function(data) {
res.write("data: " + JSON.stringify(data) + "\n\n");
};
Cylon.on(event, writeData);
res.on("close", function() {
Cylon.removeListener(event, writeData);
});
});
router.get("/commands", function(req, res) {
res.json({ commands: Object.keys(Cylon.commands) });
});
@ -81,6 +107,26 @@ router.all("/robots/:robot/commands/:command", load, function(req, res) {
router.runCommand(req, res, req.robot, command);
});
router.get("/robots/:robot/events", load, function(req, res) {
res.json({ events: req.robot.events });
});
router.all("/robots/:robot/events/:event", load, function(req, res) {
var event = req.params.event;
res.writeHead(200, eventHeaders);
var writeData = function(data) {
res.write("data: " + JSON.stringify(data) + "\n\n");
};
req.robot.on(event, writeData);
res.on("close", function() {
req.robot.removeListener(event, writeData);
});
});
router.get("/robots/:robot/devices", load, function(req, res) {
res.json({ devices: req.robot.toJSON().devices });
});
@ -89,14 +135,14 @@ router.get("/robots/:robot/devices/:device", load, function(req, res) {
res.json({ device: req.device });
});
router.get("/robots/:robot/devices/:device/events", load, function(req, res) {
res.json({ events: req.device.events });
});
router.get("/robots/:robot/devices/:device/events/:event", load, function(req, res) {
var event = req.params.event;
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Connection": "keep-alive",
"Cache-Control": "no-cache"
});
res.writeHead(200, eventHeaders);
var writeData = function(data) {
res.write("data: " + JSON.stringify(data) + "\n\n");

View File

@ -16,23 +16,27 @@ var Logger = require("./logger"),
Utils = require("./utils"),
_ = require("./lodash");
var Cylon = module.exports = {
Logger: Logger,
Driver: require("./driver"),
Adaptor: require("./adaptor"),
Utils: Utils,
var EventEmitter = require("events").EventEmitter;
IO: {
var Cylon = module.exports = new EventEmitter();
Cylon.Logger = Logger;
Cylon.Driver = require("./driver");
Cylon.Adaptor = require("./adaptor");
Cylon.Utils = Utils;
Cylon.IO = {
DigitalPin: require("./io/digital-pin"),
Utils: require("./io/utils")
},
api_instance: null,
robots: {},
commands: {}
};
Cylon.api_instance = null;
Cylon.robots = {};
Cylon.commands = {};
Cylon.events = [ "robot_added", "robot_removed" ];
// Public: Creates a new Robot
//
// opts - hash of Robot attributes
@ -61,6 +65,8 @@ Cylon.robot = function robot(opts) {
var bot = new Robot(opts);
this.robots[bot.name] = bot;
this.emit("robot_added", bot.name);
return bot;
};
@ -134,7 +140,8 @@ Cylon.halt = function halt(callback) {
Cylon.toJSON = function() {
return {
robots: _.invoke(this.robots, "toJSON"),
commands: _.keys(this.commands)
commands: _.keys(this.commands),
events: this.events
};
};

View File

@ -28,6 +28,7 @@ var Driver = module.exports = function Driver(opts) {
this.connection = opts.connection;
this.commands = {};
this.events = [];
// some default options
this.pin = opts.pin;
@ -36,7 +37,7 @@ var Driver = module.exports = function Driver(opts) {
this.details = {};
_.forEach(opts, function(opt, name) {
if (_.include(["robot", "name", "connection", "driver"], name)) {
if (_.include(["robot", "name", "connection", "driver", "events"], name)) {
return;
}
@ -74,6 +75,7 @@ Driver.prototype.toJSON = function() {
driver: this.constructor.name || this.name,
connection: this.connection.name,
commands: _.keys(this.commands),
events: this.events,
details: this.details
};
};

View File

@ -120,7 +120,8 @@ Robot.prototype.toJSON = function() {
name: this.name,
connections: _.invoke(this.connections, "toJSON"),
devices: _.invoke(this.devices, "toJSON"),
commands: _.keys(this.commands)
commands: _.keys(this.commands),
events: _.isArray(this.events) ? this.events : []
};
};

View File

@ -17,6 +17,8 @@ var Ping = module.exports = function Ping() {
this.commands = {
ping: this.ping
};
this.events = ["ping"];
};
Utils.subclass(Ping, Driver);

View File

@ -181,5 +181,9 @@ describe("Cylon", function() {
it("contains an array of MCP commands", function() {
expect(json.commands).to.be.eql(["echo"]);
});
it("contains an array of MCP events", function() {
expect(json.events).to.be.eql(["robot_added", "robot_removed"]);
});
});
});

View File

@ -30,6 +30,10 @@ describe("Driver", function() {
expect(driver.commands).to.be.eql({});
});
it("sets @events to an empty array by default", function() {
expect(driver.events).to.be.eql([]);
});
it("sets @interval to 10ms by default, or the provided value", function() {
expect(driver.interval).to.be.eql(10);
@ -43,6 +47,46 @@ describe("Driver", function() {
});
});
describe("#toJSON", function() {
var driver, json;
beforeEach(function() {
driver = new Driver({
connection: { name: "conn" },
name: "name",
port: "3000"
});
json = driver.toJSON();
});
it("returns an object", function() {
expect(json).to.be.a("object");
});
it("contains the driver's name", function() {
expect(json.name).to.eql("name");
});
it("contains the driver's constructor name", function() {
expect(json.driver).to.eql("Driver");
});
it("contains the driver's connection name", function() {
expect(json.connection).to.eql("conn");
});
it("contains the driver's commands", function() {
expect(json.commands).to.eql(Object.keys(driver.commands));
});
it("contains the driver's events, or an empty array", function() {
expect(json.events).to.eql([]);
driver.events = ["hello", "world"];
expect(driver.toJSON().events).to.be.eql(["hello", "world"]);
});
});
describe("#setupCommands", function() {
beforeEach(function() {
driver.proxyMethods = spy();

View File

@ -215,7 +215,9 @@ describe("Robot", function() {
devices: {
ping: { driver: "ping" }
}
},
events: ["hello", "world"]
});
var json = bot.toJSON();
@ -239,6 +241,13 @@ describe("Robot", function() {
it("contains the robot's connections", function() {
expect(json.connections).to.eql([bot.connections.loopback.toJSON()]);
});
it("contains the robot's events, or an empty array", function() {
expect(json.events).to.eql(["hello", "world"]);
var bot = new Robot();
expect(bot.toJSON().events).to.be.eql([]);
});
});
describe("#connection", function() {