Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leverage dot to generate service event #941

Merged
merged 1 commit into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading