Skip to content

Commit 68d01fd

Browse files
chfritzchris-smith
authored andcommitted
Fix on demand default arrays + support for Node 4.5 (#40)
- Fixes arrays for complex subtypes for on-demand messages - Added babel prepublish script to support Node 4.5 - Added test cases for on-the-fly message definitions - Fixed a bug in fixed-size on-the-fly array serialization
1 parent 72b0294 commit 68d01fd

File tree

5 files changed

+111
-59
lines changed

5 files changed

+111
-59
lines changed

package.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "rosnodejs",
33
"version": "1.0.3",
44
"description": "Native ROS for nodejs",
5-
"main": "index.js",
5+
"main": "dist/index.js",
66
"keywords": [
77
"ros"
88
],
@@ -11,7 +11,9 @@
1111
"gennodejsTest": "mocha test/gennodejsTest.js",
1212
"stressTest": "mocha test/stress.js",
1313
"flatten": "node tools/flatten.js",
14-
"generate": "node tools/generateMessages.js"
14+
"generate": "node tools/generateMessages.js",
15+
"compile": "babel --presets es2015 index.js -d dist/ && for dir in utils utils/messageGeneration utils/log lib tools test examples; do babel --presets es2015 $dir -d dist/$dir; done",
16+
"prepublish": "npm run compile"
1517
},
1618
"author": "chris smith",
1719
"license": "Apache-2.0",
@@ -21,15 +23,17 @@
2123
},
2224
"devDependencies": {
2325
"chai": "^3.5.0",
24-
"mocha": "^2.4.5"
26+
"mocha": "^2.4.5",
27+
"babel-cli": "^6.18.0",
28+
"babel-preset-es2015": "^6.18.0"
2529
},
2630
"dependencies": {
2731
"argparse": "1.0.7",
2832
"async": "2.0.1",
2933
"bunyan": "1.8.1",
3034
"md5": "2.1.0",
3135
"moment": "2.12.0",
32-
"ros_msg_utils": "RethinkRobotics-opensource/ros_msg_utils#v1.0.1",
36+
"ros_msg_utils": "1.0.2",
3337
"walker": "1.0.7",
3438
"xmlrpc": "chfritz/node-xmlrpc"
3539
}

test/directory.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ require('./DeserializeStream.js');
22
require('./SpinnerTest.js');
33
require('./xmlrpcTest.js');
44
require('./Log.js');
5+
require('./onTheFly.js');

test/onTheFly.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict'
2+
3+
const chai = require('chai');
4+
const expect = chai.expect;
5+
let rosnodejs = require('../index.js');
6+
7+
rosnodejs.initNode('/my_node', { onTheFly: true})
8+
.then((rosNode) => {
9+
10+
const geometry_msgs = rosnodejs.require('geometry_msgs').msg;
11+
const msg = new geometry_msgs.PoseWithCovariance({
12+
pose: {
13+
position: {x:0, y:0, z:0},
14+
orientation: {w:1, x:0, y:0, z:0}
15+
},
16+
covariance: [
17+
0,0,0,0,0,0.123,
18+
0,2,0,0,0,0,
19+
0,0,4,0,0,0,
20+
0,0,0,6,0,0,
21+
0,0,0,0,8,0,
22+
0.123,0,0,0,0,0.654321654321
23+
]
24+
});
25+
26+
describe('OnTheFly', () => {
27+
28+
it('serialize/deserialize', (done) => {
29+
const size = geometry_msgs.PoseWithCovariance.getMessageSize(msg);
30+
const buffer = new Buffer(size);
31+
geometry_msgs.PoseWithCovariance.serialize(msg, buffer, 0);
32+
33+
const read = geometry_msgs.PoseWithCovariance.deserialize(buffer);
34+
expect(read.covariance.length == msg.covariance.length
35+
&& read.covariance.every((v,i)=> v === msg.covariance[i])).to.be.true;
36+
37+
done();
38+
});
39+
});
40+
});

utils/messageGeneration/fields.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,17 @@ fields.isPrimitive = function(fieldType) {
7272
return (fields.primitiveTypes.indexOf(fieldType) >= 0);
7373
};
7474

75-
var isArrayRegex = /\[*\]$/;
76-
fields.isArray = function(fieldType) {
77-
return (fieldType.match(isArrayRegex) !== null);
75+
var isArrayRegex = /\[(\d*)\]$/;
76+
fields.isArray = function(fieldType, details) {
77+
var match = fieldType.match(isArrayRegex);
78+
if (match) {
79+
if (match[1] && details) {
80+
details.length = match[1];
81+
}
82+
return true;
83+
} else {
84+
return false;
85+
}
7886
};
7987

8088
fields.isMessage = function(fieldType) {

utils/messageGeneration/messages.js

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,12 @@ function getMessageFromFile(messageType, filePath, type, callback) {
196196
callback(error);
197197
} else {
198198
if (type == "msg") {
199-
message = buildMessageClass(details);
199+
var message = buildMessageClass(details);
200200
setMessageInRegistry(messageType, message, type);
201201
callback(null, message);
202202
} else if (type == "srv") {
203-
request = buildMessageClass(details.request);
204-
response = buildMessageClass(details.response);
203+
var request = buildMessageClass(details.request);
204+
var response = buildMessageClass(details.response);
205205
setMessageInRegistry(messageType, request, type, "Request");
206206
setMessageInRegistry(messageType, response, type, "Response");
207207
setMessageInRegistry(messageType, () => {return request.md5sum(); }, type, 'md5sum');
@@ -461,38 +461,6 @@ function camelCase(underscoreWord, lowerCaseFirstLetter) {
461461
return camelCaseWord;
462462
}
463463

464-
function buildValidator (details) {
465-
466-
function validator (candidate, strict) {
467-
return Object.keys(candidate).every(function(property) {
468-
var valid = true;
469-
var exists = false;
470-
471-
details.constants.forEach(function(field) {
472-
if (field.name === property) {
473-
exists = true;
474-
}
475-
});
476-
if (!exists) {
477-
details.fields.forEach(function(field) {
478-
if (field.name === property) {
479-
exists = true;
480-
}
481-
});
482-
}
483-
484-
if (strict) {
485-
return exists;
486-
}
487-
else {
488-
return valid;
489-
}
490-
});
491-
}
492-
493-
validator.name = 'validate' + camelCase(details.messageName);
494-
return validator;
495-
}
496464

497465
/** Construct the class definition for the given message type. The
498466
* resulting class holds the data and has the methods required for
@@ -515,14 +483,36 @@ function buildMessageClass(details) {
515483
details.fields.forEach(function(field) {
516484
if (field.messageType) {
517485
// sub-message class
518-
that[field.name] =
519-
new (field.messageType)(values ? values[field.name] : undefined);
486+
// is it an array?
487+
var match = field.type.match(/(.*)\[(\d*)\]/);
488+
if (values && typeof values[field.name] != "undefined") {
489+
// values provided
490+
if (match) {
491+
// it's an array
492+
that[field.name] = values[field.name].map(function(value) {
493+
return new (field.messageType)(value);
494+
});
495+
} else {
496+
that[field.name] =
497+
new (field.messageType)(values[field.name]);
498+
}
499+
} else {
500+
// use defaults
501+
if (match) {
502+
// it's an array
503+
const basetype = match[1];
504+
const length = (match[2].length > 0 ? parseInt(match[2]) : 0);
505+
that[field.name] = new Array(length).fill(new (field.messageType)());
506+
} else {
507+
that[field.name] = new (field.messageType)();
508+
}
509+
}
520510
} else {
521-
// simple value
511+
// simple type
522512
that[field.name] =
523-
(values && typeof values[field.name] != "undefined") ?
524-
values[field.name] :
525-
(field.value || fieldsUtil.getDefaultValue(field.type));
513+
(values && typeof values[field.name] != "undefined") ?
514+
values[field.name] :
515+
(field.value || fieldsUtil.getDefaultValue(field.type));
526516
}
527517
});
528518
}
@@ -556,7 +546,6 @@ function buildMessageClass(details) {
556546
return message;
557547
};
558548
Message.getMessageSize = function(msg) { return fieldsUtil.getMessageSize(msg); };
559-
Message.prototype.validate = buildValidator(details);
560549

561550
return Message;
562551
}
@@ -594,22 +583,26 @@ function getMessageNameFromMessageType(messageType) {
594583
function serializeInnerMessage(message, buffer, bufferOffset) {
595584
message.fields.forEach(function(field) {
596585
var fieldValue = message[field.name];
586+
var details = {}; // to be filled in for arrays
597587

598588
if (fieldsUtil.isPrimitive(field.type)) {
599589
fieldsUtil.serializePrimitive(
600590
field.type, fieldValue, buffer, bufferOffset);
601591
bufferOffset += fieldsUtil.getPrimitiveSize(field.type, fieldValue);
602592
}
603-
else if (fieldsUtil.isArray(field.type)) {
604-
buffer.writeUInt32LE(fieldValue.length, bufferOffset);
605-
bufferOffset += 4;
593+
else if (fieldsUtil.isArray(field.type, details)) {
594+
if (typeof details.length == "undefined") {
595+
buffer.writeUInt32LE(fieldValue.length, bufferOffset);
596+
bufferOffset += 4; // only for variable length arrays
597+
}
606598

607599
var arrayType = fieldsUtil.getTypeOfArray(field.type);
608600
fieldValue.forEach(function(value) {
609601
if (fieldsUtil.isPrimitive(arrayType)) {
610602
fieldsUtil.serializePrimitive(
611603
arrayType, value, buffer, bufferOffset);
612-
bufferOffset += fieldsUtil.getPrimitiveSize(arrayType, value);
604+
var size = fieldsUtil.getPrimitiveSize(arrayType, value)
605+
bufferOffset += size;
613606
}
614607
else if (fieldsUtil.isMessage(arrayType)) {
615608
serializeInnerMessage(value, buffer, bufferOffset);
@@ -630,18 +623,24 @@ function serializeInnerMessage(message, buffer, bufferOffset) {
630623
function deserializeInnerMessage(message, buffer, bufferOffset) {
631624
message.fields.forEach(function(field) {
632625
var fieldValue = message[field.name];
626+
var details = {}; // to be filled in for arrays
633627

634628
if (fieldsUtil.isPrimitive(field.type)) {
635629
fieldValue = fieldsUtil.deserializePrimitive(
636630
field.type, buffer, bufferOffset)
637631
bufferOffset += fieldsUtil.getPrimitiveSize(field.type, fieldValue)
638632
}
639-
else if (fieldsUtil.isArray(field.type)) {
640-
var array = []
641-
, arraySize = buffer.readUInt32LE(bufferOffset)
642-
, arrayType = fieldsUtil.getTypeOfArray(field.type)
643-
;
644-
bufferOffset += 4;
633+
else if (fieldsUtil.isArray(field.type, details)) {
634+
var array = [];
635+
var arrayType = fieldsUtil.getTypeOfArray(field.type)
636+
637+
var arraySize;
638+
if (details.length) {
639+
arraySize = details.length
640+
} else {
641+
arraySize = buffer.readUInt32LE(bufferOffset)
642+
bufferOffset += 4; // only for variable length arrays
643+
}
645644

646645
for (var i = 0; i < arraySize; i++) {
647646
if (fieldsUtil.isPrimitive(arrayType)) {

0 commit comments

Comments
 (0)