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('../..');
|
var Cylon = require('../..');
|
||||||
|
|
||||||
|
Cylon.api();
|
||||||
|
|
||||||
Cylon.robot({
|
Cylon.robot({
|
||||||
|
name: 'test',
|
||||||
connection: { name: 'loopback', adaptor: 'loopback' },
|
connection: { name: 'loopback', adaptor: 'loopback' },
|
||||||
device: { name: 'ping', driver: 'ping' },
|
device: { name: 'ping', driver: 'ping' },
|
||||||
|
|
||||||
work: function() {
|
work: function(my) {
|
||||||
every((1).seconds(), function(){
|
every((1).seconds(), function(){
|
||||||
console.log("Hello, human!")
|
console.log("Hello, human!")
|
||||||
|
console.log(my.ping.ping());
|
||||||
});
|
});
|
||||||
|
|
||||||
after((5).seconds(), function(){
|
after((5).seconds(), function(){
|
||||||
|
|
|
@ -1,29 +1,25 @@
|
||||||
var Cylon = require('../..');
|
var Cylon = require('../..');
|
||||||
|
|
||||||
Cylon.api({ host: '0.0.0.0', port: '8080' });
|
Cylon.api();
|
||||||
|
|
||||||
var MyRobot = (function() {
|
Cylon.robot({
|
||||||
function MyRobot() {}
|
name: 'Frankie',
|
||||||
|
|
||||||
MyRobot.prototype.commands = ["relax"];
|
sayRelax: function() {
|
||||||
|
return this.name + " says relax";
|
||||||
|
},
|
||||||
|
|
||||||
MyRobot.prototype.relax = function() {
|
work: function(my) {
|
||||||
return "" + this.name + " says relax";
|
every((5).seconds(), function() {
|
||||||
};
|
console.log(my.sayRelax());
|
||||||
|
|
||||||
MyRobot.prototype.work = function(me) {
|
|
||||||
every((1).seconds(), function() {
|
|
||||||
console.log(me.name);
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
commands: function() {
|
||||||
|
return {
|
||||||
|
say_relax: this.sayRelax
|
||||||
};
|
};
|
||||||
|
}
|
||||||
return MyRobot;
|
});
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
var robot = new MyRobot;
|
|
||||||
robot.name = "frankie";
|
|
||||||
|
|
||||||
Cylon.robot(robot);
|
|
||||||
|
|
||||||
Cylon.start();
|
Cylon.start();
|
||||||
|
|
|
@ -14,48 +14,40 @@ First, let's make sure to load up Cylon:
|
||||||
|
|
||||||
var Cylon = require('../..');
|
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
|
And with that done let's define our robot:
|
||||||
robot's logic:
|
|
||||||
|
|
||||||
var MyRobot = (function() {
|
Cylon.robot({
|
||||||
function MyRobot() {}
|
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"];
|
sayRelax: function() {
|
||||||
|
return this.name + " says 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";
|
|
||||||
};
|
|
||||||
|
|
||||||
Since we don't really care what actual work this robot does, but need to keep it
|
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) {
|
work: function(my) {
|
||||||
every((1).seconds(), function() {
|
every((5).seconds(), function() {
|
||||||
console.log(me.name);
|
console.log(my.sayRelax());
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
We'll then set up the `commands` object, which tells the API which commands the
|
||||||
|
Robot has should be publically accessible:
|
||||||
|
|
||||||
|
commands: function() {
|
||||||
|
return {
|
||||||
|
say_relax: this.sayRelax
|
||||||
};
|
};
|
||||||
|
}
|
||||||
return MyRobot;
|
});
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
And now that all the pieces are in place, we can start up Cylon:
|
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) {
|
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) {
|
router.all("/robots/:robot/commands/:command", load, function(req, res) {
|
||||||
var command = req.params.command;
|
var command = req.robot.commands[req.params.command];
|
||||||
var result = req.robot[command].apply(req.robot, req.commandParams);
|
var result = command.apply(req.robot, req.commandParams);
|
||||||
res.json({ result: result });
|
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) {
|
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) {
|
router.all("/robots/:robot/devices/:device/commands/:command", load, function(req, res) {
|
||||||
var command = req.params.command;
|
var command = req.device.driver.commands[req.params.command];
|
||||||
|
var result = command.apply(req.device, req.commandParams);
|
||||||
var result = req.device[command].apply(req.device, req.commandParams);
|
|
||||||
res.json({ result: result });
|
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);
|
Utils.subclass(Device, EventEmitter);
|
||||||
|
@ -86,7 +86,7 @@ Device.prototype.toJSON = function() {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
driver: this.driver.constructor.name || this.driver.name,
|
driver: this.driver.constructor.name || this.driver.name,
|
||||||
connection: this.connection.name,
|
connection: this.connection.name,
|
||||||
commands: this.driver.commands,
|
commands: Object.keys(this.driver.commands),
|
||||||
details: this.details
|
details: this.details
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,12 +25,12 @@ var Driver = module.exports = function Driver(opts) {
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
this.device = opts.device;
|
this.device = opts.device;
|
||||||
this.connection = this.device.connection;
|
this.connection = this.device.connection;
|
||||||
|
|
||||||
|
this.commands = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.subclass(Driver, Basestar);
|
Utils.subclass(Driver, Basestar);
|
||||||
|
|
||||||
Driver.prototype.commands = [];
|
|
||||||
|
|
||||||
// Public: Starts up the driver, and triggers the provided callback when done.
|
// Public: Starts up the driver, and triggers the provided callback when done.
|
||||||
//
|
//
|
||||||
// callback - function to run when the driver is started
|
// 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.devices = {};
|
||||||
this.adaptors = {};
|
this.adaptors = {};
|
||||||
this.drivers = {};
|
this.drivers = {};
|
||||||
this.commands = [];
|
this.commands = {};
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.work = opts.work || opts.play;
|
this.work = opts.work || opts.play;
|
||||||
|
|
||||||
|
@ -95,13 +95,31 @@ var Robot = module.exports = function Robot(opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var n in opts) {
|
for (var n in opts) {
|
||||||
var func = opts[n],
|
var opt = opts[n],
|
||||||
reserved = ['connection', 'connections', 'device', 'devices', 'work'];
|
reserved = ['connection', 'connections', 'device', 'devices', 'work', 'commands'];
|
||||||
|
|
||||||
if (reserved.indexOf(n) < 0) {
|
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);
|
Utils.subclass(Robot, EventEmitter);
|
||||||
|
@ -143,7 +161,7 @@ Robot.prototype.toJSON = function() {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
connections: connections,
|
connections: connections,
|
||||||
devices: devices,
|
devices: devices,
|
||||||
commands: this.commands
|
commands: Object.keys(this.commands)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
var Driver = require('../driver'),
|
var Driver = require('../driver'),
|
||||||
Utils = require('../utils');
|
Utils = require('../utils');
|
||||||
|
|
||||||
var Ping;
|
var Ping = module.exports = function Ping() {
|
||||||
|
|
||||||
module.exports = Ping = function Ping() {
|
|
||||||
Ping.__super__.constructor.apply(this, arguments);
|
Ping.__super__.constructor.apply(this, arguments);
|
||||||
this.commands = ['ping'];
|
|
||||||
|
this.commands = {
|
||||||
|
ping: this.ping.bind(this)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.subclass(Ping, Driver);
|
Utils.subclass(Ping, Driver);
|
||||||
|
@ -25,4 +26,6 @@ Ping.prototype.ping = function() {
|
||||||
return "pong";
|
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() {
|
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() {
|
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");
|
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() {
|
describe("all work and no play", function() {
|
||||||
|
@ -96,7 +173,7 @@ describe("Robot", function() {
|
||||||
it('makes Jack a dull boy', function() {
|
it('makes Jack a dull boy', function() {
|
||||||
expect(playBot.work).to.be.eql(play);
|
expect(playBot.work).to.be.eql(play);
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
|
|
||||||
describe("#toJSON", function() {
|
describe("#toJSON", function() {
|
||||||
var bot = new Robot({
|
var bot = new Robot({
|
||||||
|
@ -115,7 +192,7 @@ describe("Robot", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contains the robot's commands", 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() {
|
it("contains the robot's devices", function() {
|
||||||
|
|
Loading…
Reference in New Issue