From b945ac7b46a96bc9243c7f872ba6881208d5af9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20S=C3=B6chting?= Date: Mon, 22 Jan 2018 09:48:38 +0100 Subject: [PATCH 1/3] WIP usage --- LIB_USAGE.md | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 LIB_USAGE.md diff --git a/LIB_USAGE.md b/LIB_USAGE.md new file mode 100644 index 00000000000000..349a6ab75884bd --- /dev/null +++ b/LIB_USAGE.md @@ -0,0 +1,161 @@ +## How to use Node.js as a C++ library +### How to build +TODO + +### Handling the Node.js event loop +There are two different ways of handling the Node.js event loop. +#### C++ keeps control over thread +By calling `node::lib::ProcessEvents()`, the Node.js event loop will be run once, handling the next pending event. The return value of the call specifies whether there are more events in the queue. + +#### C++ gives up control of the thread to Node.js +By calling `node::lib::RunMainLoop(callback)`, the C++ host program gives up the control of the thread and allows the Node.js event loop to run indefinitely until `node::lib::StopEventLoop()` is called. The `callback` parameter in the `RunMainLoop` function is called once per event loop. This allows the C++ programmer to react on changes in the Node.js state and e.g. terminate Node.js preemptively. + +### Examples + +#### (1) Evaluating in-line JS code +This example evaluates a single line of JS code in the global Node context. The result of `console.log` is piped to the stdout. + +```C++ +node::lib::Initialize("example01"); +node::lib::Evaluate("var helloMessage = 'Hello from Node.js!';"); +node::lib::Evaluate("console.log(helloMessage);"); +``` + +#### (2) Running a JS file +This example evaluates a JS file and lets Node handle all pending events until the event loop is empty. + +```C++ +node::lib::Initialize("example02"); +node::lib::Run("cli.js"); +while (node::lib::ProcessEvents()) { } +``` + + +#### (3) Including an NPM Module +This example uses the [fs](https://nodejs.org/api/fs.html) module to check whether a specific file exists. +```C++ +node::lib::Initialize("example03"); +auto fs = node::lib::IncludeModule("fs"); +v8::Isolate *isolate = v8::Isolate::GetCurrent(); + + +// Check if file cli-test.js exists in the current working directory. +auto result = node::lib::Call(fs, "existsSync", {v8::String::NewFromUtf8(isolate, "cli.js")}); + +auto file_exists = v8::Local::Cast(result)->BooleanValue(); +std::cout << (file_exists ? "cli.js exists in cwd" : "cli.js does NOT exist in cwd") << std::endl; + +``` + +Copy-pasted header file: +```C++ +/* +Starts the Node.js engine without a concrete script file to execute. +*Important*: This requires the C++ developer to call `ProcessEvents()` periodically OR call `RunMainLoop()` to start the uv event loop. +*/ +NODE_EXTERN void Initialize(const std::string& program_name = "node_lib_executable"); + + +/* +Stops the existing Node.js engine. Eventloop should not be running at this point. +*Important*: Once this was called, Initialize() will have to be called again for Node.js' library functions to be available again. +*/ +NODE_EXTERN int Deinitialize(); + +/* +Executes a given JavaScript file and returns once the execution has finished. +*Important*: Node.js has to have been initialized by calling Initialize(). +*/ +NODE_EXTERN v8::Local Run(const std::string & path); + +/********************************************************* + * Handle JavaScript events + *********************************************************/ + +/* +Processes the pending event queue of a *running* Node.js engine once. +*/ +NODE_EXTERN bool ProcessEvents(); + +/* +Starts the execution of the Node.js event loop, which processes any events in JavaScript. +Additionally, the given callback will be executed once per main loop run. +*Important*: Call `Initialize()` before using this method. +*/ +NODE_EXTERN void RunEventLoop(const std::function & callback); + + +/********************************************************* + * Stop Node.js engine + *********************************************************/ + +/* +Stops the Node.js event loop after its current execution. Execution can be resumed by calling RunEventLoop() again. +*/ +NODE_EXTERN void StopEventLoop(); + +/********************************************************* + * Basic operations + *********************************************************/ + +/* +Executes a given piece of JavaScript code, using the *running* Node.js engine. +*/ +NODE_EXTERN v8::Local Evaluate(const std::string & java_script_code); + +/* +Returns the JavaScript root object for the running application +*/ +NODE_EXTERN v8::Local GetRootObject(); + +/* +Registers a C++ module in the *running* Node.js engine. +*/ +NODE_EXTERN void RegisterModule(const std::string & name, const addon_context_register_func & callback, void *priv = nullptr); + +/* +Registers a C++ module in the *running* Node.js engine exporting the given set of functions. +*/ +NODE_EXTERN void RegisterModule(const std::string & name, + const std::map & module_functions); + + +/********************************************************* + * Convenience operations + *********************************************************/ + +/* +Adds a new JavaScript module to the *running* Node.js engine. +*/ +NODE_EXTERN v8::Local IncludeModule(const std::string & module_name); + +/* +Returns the local value (specified by its name) of the module (defined in the `exports`-object). +*/ +NODE_EXTERN v8::MaybeLocal GetValue(v8::MaybeLocal object, const std::string & value_name); + +/* +Calls a function (specified by its name) on a given object passing the given arguments. +*Important*: Throws an exception if the receiver does not define the specified function. +*/ +NODE_EXTERN v8::Local Call(v8::Local object, const std::string & function_name, const std::vector> & args = {}); + +/* +Calls a function (specified by its name) on a given object passing the given arguments. +*Important*: Throws an exception if the receiver does not define the specified function. +*/ +NODE_EXTERN v8::Local Call(v8::Local object, const std::string & function_name, std::initializer_list> args); + +/* +Calls a given function on a given receiver passing the given arguments. +*Important*: The amount of arguments can be changed at runtime (for JS var arg functions). +*/ +NODE_EXTERN v8::Local Call(v8::MaybeLocal receiver, v8::MaybeLocal function, const std::vector> & args = {}); + +/* +Calls a given function on a given receiver passing the given arguments. +*Important*: The amount of arguments must be known at compile time. +*/ +NODE_EXTERN v8::Local Call(v8::MaybeLocal receiver, v8::MaybeLocal function, std::initializer_list> args); + +``` \ No newline at end of file From 78329e068a5586b8566f29a6cb356df761de0ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20S=C3=B6chting?= Date: Mon, 22 Jan 2018 10:14:15 +0100 Subject: [PATCH 2/3] Update usage documentation --- LIB_USAGE.md | 129 +++------------------------------------------------ 1 file changed, 7 insertions(+), 122 deletions(-) diff --git a/LIB_USAGE.md b/LIB_USAGE.md index 349a6ab75884bd..db81cde875dc79 100644 --- a/LIB_USAGE.md +++ b/LIB_USAGE.md @@ -1,7 +1,4 @@ ## How to use Node.js as a C++ library -### How to build -TODO - ### Handling the Node.js event loop There are two different ways of handling the Node.js event loop. #### C++ keeps control over thread @@ -12,8 +9,10 @@ By calling `node::lib::RunMainLoop(callback)`, the C++ host program gives up the ### Examples -#### (1) Evaluating in-line JS code -This example evaluates a single line of JS code in the global Node context. The result of `console.log` is piped to the stdout. +In the following, simple examples demonstrate the usage of Node.js as a library. For more complex examples, including handling of the event loop, see the [node-embed](https://github.com/hpicgs/node-embed) repository. + +#### (1) Evaluating in-line JavaScript code +This example evaluates multiple lines of JavaScript code in the global Node context. The result of `console.log` is piped to the stdout. ```C++ node::lib::Initialize("example01"); @@ -21,8 +20,8 @@ node::lib::Evaluate("var helloMessage = 'Hello from Node.js!';"); node::lib::Evaluate("console.log(helloMessage);"); ``` -#### (2) Running a JS file -This example evaluates a JS file and lets Node handle all pending events until the event loop is empty. +#### (2) Running a JavaScript file +This example evaluates a JavaScript file and lets Node handle all pending events until the event loop is empty. ```C++ node::lib::Initialize("example02"); @@ -38,124 +37,10 @@ node::lib::Initialize("example03"); auto fs = node::lib::IncludeModule("fs"); v8::Isolate *isolate = v8::Isolate::GetCurrent(); - -// Check if file cli-test.js exists in the current working directory. +// Check if file cli.js exists in the current working directory. auto result = node::lib::Call(fs, "existsSync", {v8::String::NewFromUtf8(isolate, "cli.js")}); auto file_exists = v8::Local::Cast(result)->BooleanValue(); std::cout << (file_exists ? "cli.js exists in cwd" : "cli.js does NOT exist in cwd") << std::endl; ``` - -Copy-pasted header file: -```C++ -/* -Starts the Node.js engine without a concrete script file to execute. -*Important*: This requires the C++ developer to call `ProcessEvents()` periodically OR call `RunMainLoop()` to start the uv event loop. -*/ -NODE_EXTERN void Initialize(const std::string& program_name = "node_lib_executable"); - - -/* -Stops the existing Node.js engine. Eventloop should not be running at this point. -*Important*: Once this was called, Initialize() will have to be called again for Node.js' library functions to be available again. -*/ -NODE_EXTERN int Deinitialize(); - -/* -Executes a given JavaScript file and returns once the execution has finished. -*Important*: Node.js has to have been initialized by calling Initialize(). -*/ -NODE_EXTERN v8::Local Run(const std::string & path); - -/********************************************************* - * Handle JavaScript events - *********************************************************/ - -/* -Processes the pending event queue of a *running* Node.js engine once. -*/ -NODE_EXTERN bool ProcessEvents(); - -/* -Starts the execution of the Node.js event loop, which processes any events in JavaScript. -Additionally, the given callback will be executed once per main loop run. -*Important*: Call `Initialize()` before using this method. -*/ -NODE_EXTERN void RunEventLoop(const std::function & callback); - - -/********************************************************* - * Stop Node.js engine - *********************************************************/ - -/* -Stops the Node.js event loop after its current execution. Execution can be resumed by calling RunEventLoop() again. -*/ -NODE_EXTERN void StopEventLoop(); - -/********************************************************* - * Basic operations - *********************************************************/ - -/* -Executes a given piece of JavaScript code, using the *running* Node.js engine. -*/ -NODE_EXTERN v8::Local Evaluate(const std::string & java_script_code); - -/* -Returns the JavaScript root object for the running application -*/ -NODE_EXTERN v8::Local GetRootObject(); - -/* -Registers a C++ module in the *running* Node.js engine. -*/ -NODE_EXTERN void RegisterModule(const std::string & name, const addon_context_register_func & callback, void *priv = nullptr); - -/* -Registers a C++ module in the *running* Node.js engine exporting the given set of functions. -*/ -NODE_EXTERN void RegisterModule(const std::string & name, - const std::map & module_functions); - - -/********************************************************* - * Convenience operations - *********************************************************/ - -/* -Adds a new JavaScript module to the *running* Node.js engine. -*/ -NODE_EXTERN v8::Local IncludeModule(const std::string & module_name); - -/* -Returns the local value (specified by its name) of the module (defined in the `exports`-object). -*/ -NODE_EXTERN v8::MaybeLocal GetValue(v8::MaybeLocal object, const std::string & value_name); - -/* -Calls a function (specified by its name) on a given object passing the given arguments. -*Important*: Throws an exception if the receiver does not define the specified function. -*/ -NODE_EXTERN v8::Local Call(v8::Local object, const std::string & function_name, const std::vector> & args = {}); - -/* -Calls a function (specified by its name) on a given object passing the given arguments. -*Important*: Throws an exception if the receiver does not define the specified function. -*/ -NODE_EXTERN v8::Local Call(v8::Local object, const std::string & function_name, std::initializer_list> args); - -/* -Calls a given function on a given receiver passing the given arguments. -*Important*: The amount of arguments can be changed at runtime (for JS var arg functions). -*/ -NODE_EXTERN v8::Local Call(v8::MaybeLocal receiver, v8::MaybeLocal function, const std::vector> & args = {}); - -/* -Calls a given function on a given receiver passing the given arguments. -*Important*: The amount of arguments must be known at compile time. -*/ -NODE_EXTERN v8::Local Call(v8::MaybeLocal receiver, v8::MaybeLocal function, std::initializer_list> args); - -``` \ No newline at end of file From c51f3f6923130596689b3b19da304fa0468b89e1 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 30 Jan 2018 12:22:10 +0100 Subject: [PATCH 3/3] Fix method names --- LIB_USAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LIB_USAGE.md b/LIB_USAGE.md index db81cde875dc79..0edca55a1f32aa 100644 --- a/LIB_USAGE.md +++ b/LIB_USAGE.md @@ -5,7 +5,7 @@ There are two different ways of handling the Node.js event loop. By calling `node::lib::ProcessEvents()`, the Node.js event loop will be run once, handling the next pending event. The return value of the call specifies whether there are more events in the queue. #### C++ gives up control of the thread to Node.js -By calling `node::lib::RunMainLoop(callback)`, the C++ host program gives up the control of the thread and allows the Node.js event loop to run indefinitely until `node::lib::StopEventLoop()` is called. The `callback` parameter in the `RunMainLoop` function is called once per event loop. This allows the C++ programmer to react on changes in the Node.js state and e.g. terminate Node.js preemptively. +By calling `node::lib::RunEventLoop(callback)`, the C++ host program gives up the control of the thread and allows the Node.js event loop to run until no more events are in the queue or `node::lib::StopEventLoop()` is called. The `callback` parameter in the `RunEventLoop` function is called once per event loop. This allows the C++ programmer to react on changes in the Node.js state and e.g. terminate Node.js preemptively. ### Examples @@ -35,7 +35,7 @@ This example uses the [fs](https://nodejs.org/api/fs.html) module to check wheth ```C++ node::lib::Initialize("example03"); auto fs = node::lib::IncludeModule("fs"); -v8::Isolate *isolate = v8::Isolate::GetCurrent(); +v8::Isolate *isolate = node::lib::internal::isolate(); // Check if file cli.js exists in the current working directory. auto result = node::lib::Call(fs, "existsSync", {v8::String::NewFromUtf8(isolate, "cli.js")});