Skip to content

Commit

Permalink
Leverage dot to generate service event (#941)
Browse files Browse the repository at this point in the history
  • Loading branch information
minggangw committed Nov 16, 2023
1 parent 3302b6d commit 8159eac
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 324 deletions.
93 changes: 71 additions & 22 deletions rosidl_gen/idl_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ async function writeGeneratedCode(dir, fileName, code) {
await fse.writeFile(path.join(dir, fileName), code);
}

async function generateServiceJSStruct(serviceInfo, dir) {
async function generateServiceJSStruct(
serviceInfo,
dir,
isActionService = true
) {
dir = path.join(dir, `${serviceInfo.pkgName}`);
const fileName =
serviceInfo.pkgName +
Expand All @@ -55,26 +59,67 @@ async function generateServiceJSStruct(serviceInfo, dir) {
const generatedSrvCode = removeEmptyLines(
dots.service({ serviceInfo: serviceInfo })
);
let result = writeGeneratedCode(dir, fileName, generatedSrvCode);

if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
return result;
// We are going to only generate the service JavaScript file if it meets one
// of the followings:
// 1. It's a action's request/response service.
// 2. For pre-Humble ROS 2 releases, because it doesn't support service
// introspection.
if (
isActionService ||
DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')
) {
return writeGeneratedCode(dir, fileName, generatedSrvCode);
}

// Otherwise, for post-Humble ROS 2 releases generate service_event msgs
await result;
return writeGeneratedCode(dir, fileName, generatedSrvCode).then(() => {
return generateServiceEventMsg(serviceInfo, dir);
});
}

async function generateServiceEventMsg(serviceInfo, dir) {
const fileName = serviceInfo.interfaceName + '.msg';
const generatedEvent = removeEmptyLines(
dots.service_event({ serviceInfo: serviceInfo })
);

return writeGeneratedCode(dir, fileName, generatedEvent).then(() => {
serviceInfo.interfaceName += '_Event';
serviceInfo.filePath = path.join(dir, fileName);
return generateServiceEventJSStruct(serviceInfo, dir);
});
}

async function generateServiceEventJSStruct(msgInfo, dir) {
const spec = await parser.parseMessageFile(msgInfo.pkgName, msgInfo.filePath);

// Remove the `.msg` files generated in `generateServiceEventMsg()` to avoid
// being found later.
fse.removeSync(msgInfo.filePath);
const eventFileName =
serviceInfo.pkgName +
msgInfo.pkgName +
'__' +
serviceInfo.subFolder +
msgInfo.subFolder +
'__' +
serviceInfo.interfaceName +
'_Event.js';
const generatedSrvEventCode = removeEmptyLines(
dots.service_event({ serviceInfo: serviceInfo })
msgInfo.interfaceName +
'.js';

// Set `msgInfo.isServiceEvent` to true, so when generating the JavaScript
// message files for the service event leveraging message.dot, it will use
// "__srv__" to require the JS files for the request/response of a specific
// service, e.g.,
// const AddTwoInts_RequestWrapper = require('../../generated/example_interfaces/example_interfaces__srv__AddTwoInts_Request.js');
// const AddTwoInts_ResponseWrapper = require('../../generated/example_interfaces/example_interfaces__srv__AddTwoInts_Response.js');
msgInfo.isServiceEvent = true;
const generatedCode = removeEmptyLines(
dots.message({
messageInfo: msgInfo,
spec: spec,
json: JSON.stringify(spec, null, ' '),
})
);

return writeGeneratedCode(dir, eventFileName, generatedSrvEventCode);
return writeGeneratedCode(dir, eventFileName, generatedCode);
}

async function generateMessageJSStruct(messageInfo, dir) {
Expand Down Expand Up @@ -258,15 +303,19 @@ async function generateActionJSStruct(actionInfo, dir) {
}

async function generateJSStructFromIDL(pkg, dir) {
await Promise.all([
...pkg.messages.map((messageInfo) =>
generateMessageJSStruct(messageInfo, dir)
),
...pkg.services.map((serviceInfo) =>
generateServiceJSStruct(serviceInfo, dir)
),
...pkg.actions.map((actionInfo) => generateActionJSStruct(actionInfo, dir)),
]);
const results = [];
pkg.messages.forEach((messageInfo) => {
results.push(generateMessageJSStruct(messageInfo, dir));
});
pkg.services.forEach((serviceInfo) => {
results.push(
generateServiceJSStruct(serviceInfo, dir, /*isActionService=*/ false)
);
});
pkg.actions.forEach((actionInfo) => {
results.push(generateActionJSStruct(actionInfo, dir));
});
await Promise.all(results);
}

module.exports = generateJSStructFromIDL;
3 changes: 2 additions & 1 deletion rosidl_gen/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ function grabInterfaceInfo(filePath, amentExecuted) {
let pkgName = getPackageName(filePath, amentExecuted);
let interfaceName = path.parse(filePath).name;
let subFolder = getSubFolder(filePath, amentExecuted);
return { pkgName, interfaceName, subFolder, filePath };
const isServiceEvent = false;
return { pkgName, interfaceName, subFolder, filePath, isServiceEvent };
}

function addInterfaceInfo(info, type, pkgMap) {
Expand Down
4 changes: 4 additions & 0 deletions rosidl_gen/templates/message.dot
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ function getModulePathByType(type, messageInfo) {
return type.pkgName + '__action__' + type.type + '.js';
}

/* We should use '__msg__' to require "service_msgs/msg/ServiceEventInfo.msg" for service event message. */
if (messageInfo && messageInfo.isServiceEvent && (type.type !== 'ServiceEventInfo')) {
return type.pkgName + '__srv__' + type.type + '.js';
}
return type.pkgName + '__msg__' + type.type + '.js';
}

Expand Down
Loading

0 comments on commit 8159eac

Please sign in to comment.