Skip to content
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
2 changes: 1 addition & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
],
'include_dirs': [
'.',
"<!(node -e \"require('nan')\")",
'<(ros_include_root)',
"<!@(node -p \"require('node-addon-api').include\")",
],
'cflags!': [
'-fno-exceptions'
Expand Down
35 changes: 26 additions & 9 deletions lib/logging.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,31 @@ let LoggingSeverity = {

class Caller {
constructor() {
this._info = {};
let frame = new Error().stack.split('\n').slice(4, 5)[0];
let results = frame.match(/at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i);

if (results && results.length === 5) {
this._info['functionName'] = results[1];
this._info['lineNumber'] = results[3];
this._info['fileName'] = path.basename(results[2]);
this._info = {
functionName: 'unknown',
fileName: 'unknown',
lineNumber: 'unknown',
};

const stackLines = new Error().stack.split('\n');

// Adjust the index (usually 3 or 4) to correctly point to the caller frame.
const callerFrame = stackLines[4] || stackLines[3];
// Match both named and anonymous function stack frames.
const frameRegex = /^\s*at\s+(?:(.+)\s+\()?(.+):(\d+):(\d+)\)?$/;
const match = callerFrame.match(frameRegex);
if (match && match.length === 5) {
this._info.functionName = match[1] || '(anonymous)';
this._info.fileName = path.basename(match[2]);
this._info.lineNumber = match[3];
} else {
// Handle anonymous functions or different stack formats.
const altMatch = callerFrame.match(/at\s+(.*):(\d+):(\d+)/i);
if (altMatch && altMatch.length >= 4) {
this._info.functionName = '(anonymous)';
this._info.fileName = path.basename(altMatch[1]);
this._info.lineNumber = altMatch[2];
}
}
}

Expand Down Expand Up @@ -156,7 +173,7 @@ class Logging {
severity,
message,
caller.functionName,
caller.lineNumber,
parseInt(caller.lineNumber, 10),
Copy link

Copilot AI Apr 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If caller.lineNumber remains the default 'unknown', parseInt will return NaN. Consider implementing a fallback for non-numeric values to prevent propagation of NaN.

Suggested change
parseInt(caller.lineNumber, 10),
isNaN(parseInt(caller.lineNumber, 10)) ? -1 : parseInt(caller.lineNumber, 10),

Copilot uses AI. Check for mistakes.
caller.fileName
);
}
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"docs": "cd docs && make",
"test": "nyc node --expose-gc ./scripts/run_test.js && tsd",
"lint": "eslint && node ./scripts/cpplint.js",
"format": "clang-format -i -style=file ./src/*.cpp ./src/*.hpp && npx --yes prettier --write \"{lib,rosidl_gen,rostsd_gen,rosidl_parser,types,example,test,scripts,benchmark,rostsd_gen}/**/*.{js,md,ts}\" ./*.{js,md,ts}",
"format": "clang-format -i -style=file ./src/*.cpp ./src/*.h && npx --yes prettier --write \"{lib,rosidl_gen,rostsd_gen,rosidl_parser,types,example,test,scripts,benchmark,rostsd_gen}/**/*.{js,md,ts}\" ./*.{js,md,ts}",
"prepare": "husky",
"coverage": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js"
},
Expand Down Expand Up @@ -79,9 +79,9 @@
"fs-extra": "^11.2.0",
"is-close": "^1.3.3",
"json-bigint": "^1.0.0",
"nan": "^2.22.0",
"terser": "^5.39.0",
"walk": "^2.3.15"
"walk": "^2.3.15",
"node-addon-api": "^8.3.1"
},
"husky": {
"hooks": {
Expand Down
79 changes: 26 additions & 53 deletions src/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <nan.h>
#include <node_api.h>
#include <rcutils/logging.h>

#include "macros.hpp"
#include "rcl_action_bindings.hpp"
#include "rcl_bindings.hpp"
#include "rcl_handle.hpp"
#include "rcl_lifecycle_bindings.hpp"
#include "rcutils/logging.h"
#include "rcutils/macros.h"
#include "shadow_node.hpp"
#include "macros.h"
#include "rcl_action_bindings.h"
#include "rcl_bindings.h"
#include "rcl_handle.h"
#include "rcl_lifecycle_bindings.h"
#include "rcl_utilities.h"
#include "shadow_node.h"

bool IsRunningInElectronRenderer() {
auto global = Nan::GetCurrentContext()->Global();
auto process =
Nan::To<v8::Object>(Nan::Get(global, Nan::New("process").ToLocalChecked())
.ToLocalChecked())
.ToLocalChecked();
auto process_type =
Nan::Get(process, Nan::New("type").ToLocalChecked()).ToLocalChecked();
return process_type->StrictEquals(Nan::New("renderer").ToLocalChecked());
bool IsRunningInElectronRenderer(const Napi::Env& env) {
Napi::Object global = env.Global();
Napi::Object process = global.Get("process").As<Napi::Object>();
Napi::Value processType = process.Get("type");
return processType.StrictEquals(Napi::String::New(env, "renderer"));
}

void InitModule(v8::Local<v8::Object> exports) {
Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
// workaround process name mangling by chromium
//
// rcl logging uses `program_invocation_name` to determine the log file,
Expand All @@ -43,52 +39,29 @@ void InitModule(v8::Local<v8::Object> exports) {
// occurence of ' -' with the null terminator. see:
// https://unix.stackexchange.com/questions/432419/unexpected-non-null-encoding-of-proc-pid-cmdline
#if defined(__linux__) && defined(__GLIBC__)
if (IsRunningInElectronRenderer()) {
if (IsRunningInElectronRenderer(env)) {
auto prog_name = program_invocation_name;
auto end = strstr(prog_name, " -");
assert(end);
prog_name[end - prog_name] = 0;
}
#endif

v8::Local<v8::Context> context = exports->GetIsolate()->GetCurrentContext();

for (uint32_t i = 0; i < rclnodejs::binding_methods.size(); i++) {
Nan::Set(
exports, Nan::New(rclnodejs::binding_methods[i].name).ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(rclnodejs::binding_methods[i].function)
->GetFunction(context)
.ToLocalChecked());
}

for (uint32_t i = 0; i < rclnodejs::action_binding_methods.size(); i++) {
Nan::Set(
exports,
Nan::New(rclnodejs::action_binding_methods[i].name).ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(
rclnodejs::action_binding_methods[i].function)
->GetFunction(context)
.ToLocalChecked());
}

for (uint32_t i = 0; i < rclnodejs::lifecycle_binding_methods.size(); i++) {
Nan::Set(
exports,
Nan::New(rclnodejs::lifecycle_binding_methods[i].name).ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(
rclnodejs::lifecycle_binding_methods[i].function)
->GetFunction(context)
.ToLocalChecked());
}

rclnodejs::ShadowNode::Init(exports);
rclnodejs::RclHandle::Init(exports);
// Init the C++ bindings.
rclnodejs::StoreEnv(env);
rclnodejs::InitBindings(env, exports);
rclnodejs::InitAction(env, exports);
rclnodejs::InitLifecycle(env, exports);
rclnodejs::ShadowNode::Init(env, exports);
rclnodejs::RclHandle::Init(env, exports);

#ifdef DEBUG_ON
int result = rcutils_logging_set_logger_level(PACKAGE_NAME,
RCUTILS_LOG_SEVERITY_DEBUG);
RCUTILS_UNUSED(result);
#endif

return exports;
}

NODE_MODULE(rclnodejs, InitModule);
NODE_API_MODULE(rclnodejs, InitModule)
29 changes: 19 additions & 10 deletions src/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include "executor.hpp"
#include "executor.h"

#include <rcl/error_handling.h>

#include <stdexcept>
#include <string>

#include "handle_manager.hpp"
#include "macros.hpp"
#include "rcl_bindings.hpp"
#include "handle_manager.h"
#include "macros.h"
#include "rcl_bindings.h"

#ifdef WIN32
#define UNUSED
Expand All @@ -41,12 +41,14 @@ struct RclResult {
std::string error_msg;
};

Executor::Executor(HandleManager* handle_manager, Delegate* delegate)
Executor::Executor(Napi::Env env, HandleManager* handle_manager,
Delegate* delegate)
: async_(nullptr),
main_thread_(uv_thread_self()),
handle_manager_(handle_manager),
delegate_(delegate),
context_(nullptr) {
context_(nullptr),
env_(env) {
running_.store(false);
}

Expand Down Expand Up @@ -74,20 +76,27 @@ void Executor::SpinOnce(rcl_context_t* context, int32_t time_out) {
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_ret_t ret = rcl_wait_set_init(&wait_set, 0, 0, 0, 0, 0, 0, context,
rcl_get_default_allocator());
if (ret != RCL_RET_OK) Nan::ThrowError(rcl_get_error_string().str);
if (ret != RCL_RET_OK) {
Napi::Error::New(env_, rcl_get_error_string().str)
.ThrowAsJavaScriptException();
return;
}

RclResult wait_result = WaitForReadyCallbacks(&wait_set, time_out);

if (wait_result.ret != RCL_RET_OK)
Nan::ThrowError(wait_result.error_msg.c_str());
if (wait_result.ret != RCL_RET_OK) {
Napi::Error::New(env_, wait_result.error_msg.c_str())
.ThrowAsJavaScriptException();
return;
}

if (handle_manager_->ready_handles_count() > 0) ExecuteReadyHandles();

if (rcl_wait_set_fini(&wait_set) != RCL_RET_OK) {
std::string error_message =
std::string("Failed to destroy guard waitset:") +
std::string(rcl_get_error_string().str);
Nan::ThrowError(error_message.c_str());
Napi::Error::New(env_, error_message.c_str()).ThrowAsJavaScriptException();
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/executor.hpp → src/executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SRC_EXECUTOR_HPP_
#define SRC_EXECUTOR_HPP_
#ifndef SRC_EXECUTOR_H_
#define SRC_EXECUTOR_H_

#include <napi.h>
#include <rcl/wait.h>
#include <uv.h>

#include <atomic>
#include <exception>
#include <vector>

#include "rcl_handle.hpp"
#include "rcl_handle.h"

namespace rclnodejs {

Expand All @@ -37,7 +38,7 @@ class Executor {
virtual void CatchException(std::exception_ptr e_ptr) = 0;
};

Executor(HandleManager* handle_manager, Delegate* delegate);
Executor(Napi::Env env, HandleManager* handle_manager, Delegate* delegate);
~Executor();

void Start(rcl_context_t* context, int32_t time_out);
Expand Down Expand Up @@ -68,10 +69,11 @@ class Executor {
Delegate* delegate_;
rcl_context_t* context_;
int32_t time_out_;
Napi::Env env_;

std::atomic_bool running_;
};

} // namespace rclnodejs

#endif // SRC_EXECUTOR_HPP_
#endif // SRC_EXECUTOR_H_
Loading
Loading