Merge pull request #221 from hybridgroup/add/commands
Add New Command Structure
This commit is contained in:
commit
bde6132377
|
@ -1,12 +1,16 @@
|
|||
var Cylon = require('../..');
|
||||
|
||||
Cylon.api();
|
||||
|
||||
Cylon.robot({
|
||||
name: 'test',
|
||||
connection: { name: 'loopback', adaptor: 'loopback' },
|
||||
device: { name: 'ping', driver: 'ping' },
|
||||
|
||||
work: function() {
|
||||
work: function(my) {
|
||||
every((1).seconds(), function(){
|
||||
console.log("Hello, human!")
|
||||
console.log(my.ping.ping());
|
||||
});
|
||||
|
||||
after((5).seconds(), function(){
|
||||
|
|
|
@ -1,29 +1,25 @@
|
|||
var Cylon = require('../..');
|
||||
|
||||
Cylon.api({ host: '0.0.0.0', port: '8080' });
|
||||
Cylon.api();
|
||||
|
||||
var MyRobot = (function() {
|
||||
function MyRobot() {}
|
||||
Cylon.robot({
|
||||
name: 'Frankie',
|
||||
|
||||
MyRobot.prototype.commands = ["relax"];
|
||||
sayRelax: function() {
|
||||
return this.name + " says relax";
|
||||
},
|
||||
|
||||
MyRobot.prototype.relax = function() {
|
||||
return "" + this.name + " says relax";
|
||||
};
|
||||
|
||||
MyRobot.prototype.work = function(me) {
|
||||
every((1).seconds(), function() {
|
||||
console.log(me.name);
|
||||
work: function(my) {
|
||||
every((5).seconds(), function() {
|
||||
console.log(my.sayRelax());
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
return MyRobot;
|
||||
|
||||
})();
|
||||
|
||||
var robot = new MyRobot;
|
||||
robot.name = "frankie";
|
||||
|
||||
Cylon.robot(robot);
|
||||
commands: function() {
|
||||
return {
|
||||
say_relax: this.sayRelax
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
Cylon.start();
|
||||
|
|
|
@ -14,48 +14,40 @@ First, let's make sure to load up Cylon:
|
|||
|
||||
var Cylon = require('../..');
|
||||
|
||||
Now that we've got that, let's set up a custom API port:
|
||||
Now that we've got that, let's set up the api:
|
||||
|
||||
Cylon.api({ host: '0.0.0.0', port: '8080' });
|
||||
Cylon.api();
|
||||
|
||||
And with that done let's define our robot. We'll make a class to contain this
|
||||
robot's logic:
|
||||
And with that done let's define our robot:
|
||||
|
||||
var MyRobot = (function() {
|
||||
function MyRobot() {}
|
||||
Cylon.robot({
|
||||
name: 'Frankie',
|
||||
|
||||
To let the API know what commands this robot has, we need to provide a `commands` array.
|
||||
The result of this method will be returned to the HTTP client as part of a JSON
|
||||
object.
|
||||
|
||||
MyRobot.prototype.commands = ["relax"];
|
||||
|
||||
And with that done, we can now define the method. The result of this method will
|
||||
be returned to the HTTP client as part of a JSON object.
|
||||
|
||||
MyRobot.prototype.relax = function() {
|
||||
return "" + this.name + " says relax";
|
||||
};
|
||||
sayRelax: function() {
|
||||
return this.name + " says relax");
|
||||
},
|
||||
|
||||
Since we don't really care what actual work this robot does, but need to keep it
|
||||
busy, we'll just tell it to print it's name every second.
|
||||
busy, we'll just tell it to print it's name every five seconds.
|
||||
|
||||
MyRobot.prototype.work = function(me) {
|
||||
every((1).seconds(), function() {
|
||||
console.log(me.name);
|
||||
work: function(my) {
|
||||
every((5).seconds(), function() {
|
||||
console.log(my.sayRelax());
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
return MyRobot;
|
||||
We'll then set up the `commands` object, which tells the API which commands the
|
||||
Robot has should be publically accessible:
|
||||
|
||||
})();
|
||||
|
||||
And with that all done, we can now instantiate our robot:
|
||||
|
||||
var robot = new MyRobot;
|
||||
|
||||
Now we can just give it a name and send it off to Cylon.
|
||||
|
||||
robot.name = "frankie";
|
||||
Cylon.robot(robot);
|
||||
commands: function() {
|
||||
return {
|
||||
say_relax: this.sayRelax
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
And now that all the pieces are in place, we can start up Cylon:
|
||||
|
||||
|
|
|
@ -64,12 +64,12 @@ router.get("/robots/:robot", load, function(req, res) {
|
|||
});
|
||||
|
||||
router.get("/robots/:robot/commands", load, function(req, res) {
|
||||
res.json({ commands: req.robot.commands });
|
||||
res.json({ commands: Object.keys(req.robot.commands) });
|
||||
});
|
||||
|
||||
router.all("/robots/:robot/commands/:command", load, function(req, res) {
|
||||
var command = req.params.command;
|
||||
var result = req.robot[command].apply(req.robot, req.commandParams);
|
||||
var command = req.robot.commands[req.params.command];
|
||||
var result = command.apply(req.robot, req.commandParams);
|
||||
res.json({ result: result });
|
||||
});
|
||||
|
||||
|
@ -102,13 +102,12 @@ router.get("/robots/:robot/devices/:device/events/:event", load, function(req, r
|
|||
});
|
||||
|
||||
router.get("/robots/:robot/devices/:device/commands", load, function(req, res) {
|
||||
res.json({ commands: req.device.toJSON().commands });
|
||||
res.json({ commands: Object.keys(req.device.commands) });
|
||||
});
|
||||
|
||||
router.all("/robots/:robot/devices/:device/commands/:command", load, function(req, res) {
|
||||
var command = req.params.command;
|
||||
|
||||
var result = req.device[command].apply(req.device, req.commandParams);
|
||||
var command = req.device.driver.commands[req.params.command];
|
||||
var result = command.apply(req.device, req.commandParams);
|
||||
res.json({ result: result });
|
||||
});
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ var Device = module.exports = function Device(opts) {
|
|||
}
|
||||
}
|
||||
|
||||
Utils.proxyFunctionsToObject(this.driver.commands, this.driver, this);
|
||||
Utils.proxyFunctionsToObject(Object.keys(this.driver.commands), this.driver, this);
|
||||
};
|
||||
|
||||
Utils.subclass(Device, EventEmitter);
|
||||
|
@ -86,7 +86,7 @@ Device.prototype.toJSON = function() {
|
|||
name: this.name,
|
||||
driver: this.driver.constructor.name || this.driver.name,
|
||||
connection: this.connection.name,
|
||||
commands: this.driver.commands,
|
||||
commands: Object.keys(this.driver.commands),
|
||||
details: this.details
|
||||
};
|
||||
};
|
||||
|
|
|
@ -25,12 +25,12 @@ var Driver = module.exports = function Driver(opts) {
|
|||
this.name = opts.name;
|
||||
this.device = opts.device;
|
||||
this.connection = this.device.connection;
|
||||
|
||||
this.commands = {};
|
||||
};
|
||||
|
||||
Utils.subclass(Driver, Basestar);
|
||||
|
||||
Driver.prototype.commands = [];
|
||||
|
||||
// Public: Starts up the driver, and triggers the provided callback when done.
|
||||
//
|
||||
// callback - function to run when the driver is started
|
||||
|
|
28
lib/robot.js
28
lib/robot.js
|
@ -74,7 +74,7 @@ var Robot = module.exports = function Robot(opts) {
|
|||
this.devices = {};
|
||||
this.adaptors = {};
|
||||
this.drivers = {};
|
||||
this.commands = [];
|
||||
this.commands = {};
|
||||
this.running = false;
|
||||
this.work = opts.work || opts.play;
|
||||
|
||||
|
@ -95,13 +95,31 @@ var Robot = module.exports = function Robot(opts) {
|
|||
}
|
||||
|
||||
for (var n in opts) {
|
||||
var func = opts[n],
|
||||
reserved = ['connection', 'connections', 'device', 'devices', 'work'];
|
||||
var opt = opts[n],
|
||||
reserved = ['connection', 'connections', 'device', 'devices', 'work', 'commands'];
|
||||
|
||||
if (reserved.indexOf(n) < 0) {
|
||||
this[n] = func;
|
||||
this[n] = opt;
|
||||
|
||||
if (opts.commands == null && typeof(opt) === 'function') {
|
||||
this.commands[n] = opt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof opts.commands === 'function') {
|
||||
var result = opts.commands.call(this, this);
|
||||
if (typeof result === 'object' && !Array.isArray(result)) {
|
||||
this.commands = result;
|
||||
} else {
|
||||
throw new Error("commands must be an object or a function that returns an object");
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof opts.commands === 'object') {
|
||||
this.commands = opts.commands;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Utils.subclass(Robot, EventEmitter);
|
||||
|
@ -143,7 +161,7 @@ Robot.prototype.toJSON = function() {
|
|||
name: this.name,
|
||||
connections: connections,
|
||||
devices: devices,
|
||||
commands: this.commands
|
||||
commands: Object.keys(this.commands)
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
var Driver = require('../driver'),
|
||||
Utils = require('../utils');
|
||||
|
||||
var Ping;
|
||||
|
||||
module.exports = Ping = function Ping() {
|
||||
var Ping = module.exports = function Ping() {
|
||||
Ping.__super__.constructor.apply(this, arguments);
|
||||
this.commands = ['ping'];
|
||||
|
||||
this.commands = {
|
||||
ping: this.ping.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
Utils.subclass(Ping, Driver);
|
||||
|
@ -25,4 +26,6 @@ Ping.prototype.ping = function() {
|
|||
return "pong";
|
||||
};
|
||||
|
||||
Ping.driver = function(opts) { return new Ping(opts); };
|
||||
Ping.driver = function(opts) {
|
||||
return new Ping(opts);
|
||||
};
|
||||
|
|
|
@ -130,7 +130,7 @@ describe("Device", function() {
|
|||
});
|
||||
|
||||
it("contains the device's driver commands", function() {
|
||||
expect(json.commands).to.be.eql(driver.commands);
|
||||
expect(json.commands).to.be.eql(Object.keys(driver.commands));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ describe("Driver", function() {
|
|||
});
|
||||
|
||||
it("sets @commands to an empty array by default", function() {
|
||||
expect(driver.commands).to.be.eql([]);
|
||||
expect(driver.commands).to.be.eql({});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -84,6 +84,83 @@ describe("Robot", function() {
|
|||
expect(fn).to.throw(Error, "No connections specified");
|
||||
});
|
||||
});
|
||||
|
||||
context("if no commands are provided", function() {
|
||||
var robot;
|
||||
|
||||
beforeEach(function() {
|
||||
robot = new Robot({
|
||||
name: 'NewBot',
|
||||
otherThings: { more: 'details' },
|
||||
sayHello: function() { return "Hello!" }
|
||||
});
|
||||
});
|
||||
|
||||
it("sets #commands to the additionally provided functions", function() {
|
||||
expect(robot.commands).to.be.eql({ sayHello: robot.sayHello });
|
||||
});
|
||||
});
|
||||
|
||||
context("if a commands function is provided", function() {
|
||||
var robot;
|
||||
|
||||
beforeEach(function() {
|
||||
robot = new Robot({
|
||||
name: 'NewBot',
|
||||
|
||||
sayHello: function() { return this.name + " says hello" },
|
||||
|
||||
commands: function() {
|
||||
return {
|
||||
say_hello: this.sayHello
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("sets #commands to the returned object", function() {
|
||||
expect(robot.commands.say_hello).to.be.eql(robot.sayHello);
|
||||
});
|
||||
|
||||
context("if the function doesn't return an object", function() {
|
||||
var fn;
|
||||
beforeEach(function() {
|
||||
fn = function() {
|
||||
new Robot({
|
||||
name: 'NewBot',
|
||||
|
||||
commands: function() {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("throws an error", function() {
|
||||
expect(fn).to.throw(Error, "commands must be an object or a function that returns an object");
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
context("if a commands object is provided", function() {
|
||||
var robot;
|
||||
|
||||
beforeEach(function() {
|
||||
robot = new Robot({
|
||||
name: 'NewBot',
|
||||
|
||||
sayHello: function() { return this.name + " says hello" },
|
||||
|
||||
commands: {
|
||||
say_hello: function() {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("sets #commands to the provided object", function() {
|
||||
expect(robot.commands.say_hello).to.be.a('function');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("all work and no play", function() {
|
||||
|
@ -96,7 +173,7 @@ describe("Robot", function() {
|
|||
it('makes Jack a dull boy', function() {
|
||||
expect(playBot.work).to.be.eql(play);
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
describe("#toJSON", function() {
|
||||
var bot = new Robot({
|
||||
|
@ -115,7 +192,7 @@ describe("Robot", function() {
|
|||
});
|
||||
|
||||
it("contains the robot's commands", function() {
|
||||
expect(json.commands).to.eql(bot.commands);
|
||||
expect(json.commands).to.eql(Object.keys(bot.commands));
|
||||
});
|
||||
|
||||
it("contains the robot's devices", function() {
|
||||
|
|
Loading…
Reference in New Issue