231103.1 · 7f4a9ed91bbecb84e39f4bc8030247ce5116ddf8
Reorganize examples into categorized folders (#341)
* refactor: create directory structure to organize exmaples
* test: update test_all to work with new directory structure
* fix: bug in test_all if no package.json scripts
* test: cleanup output of test_all
* fix: remove default test script that throws from thread_safe_function_with_object_wrap
* fix: remove build_with_cmake from .gitignore
* fix: swith to ' from " and remove subdir from getAllTests call
* test: add extra test cases for npm start and just running the pkgJson.main with node
* refactor: move all examples to src directory
* refactor: add numbers to categories so they are ordered in the src folder
* refactor: simplify getAllExamples in test_all.js
* docs: add directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure example in readme
* add back build_with_cmake
---------
Co-authored-by: legendecas <legendecas@gmail.com>
reading declarations
Changes to src/5-async-work/async_work_promise/napi/. All files
src/5-async-work/async_work_promise/napi/binding.c
@@ -0,0 +1,170 @@+#include <stdio.h>+#include <stdlib.h>+#include <node_api.h>++// Limit ourselves to this many primes, starting at 2+#define PRIME_COUNT 10+#define CHECK(expr) \+ { \+ if ((expr) == 0) { \+ fprintf(stderr, "%s:%d: failed assertion `%s'\n", __FILE__, __LINE__, #expr); \+ fflush(stderr); \+ abort(); \+ } \+ }++typedef struct linked_box_s linked_box_t;+struct linked_box_s {+ linked_box_t* prev;+ int the_prime;+};++typedef struct {+ napi_async_work work;+ napi_deferred deferred;+ int data[PRIME_COUNT];+} AddonData;++// This function runs on a worker thread. It has no access to the JavaScript.+static void ExecuteWork(napi_env env, void* data) {+ AddonData* addon_data = (AddonData*)data;+ int idx_inner, idx_outer;+ int prime_count = 0;++ // Find the first 1000 prime numbers using an extremely inefficient algorithm.+ for (idx_outer = 2; prime_count < PRIME_COUNT; idx_outer++) {+ for (idx_inner = 2; idx_inner < idx_outer; idx_inner++) {+ if (idx_outer % idx_inner == 0) {+ break;+ }+ }+ if (idx_inner < idx_outer) {+ continue;+ }++ // Save the prime number to the heap. The JavaScript marshaller (CallJs)+ // will free this item after having sent it to JavaScript.+ addon_data->data[prime_count] = idx_outer;+ ++prime_count;+ }+}++// This function runs on the main thread after `ExecuteWork` exits.+static void WorkComplete(napi_env env, napi_status status, void* data) {+ if (status != napi_ok) {+ return;+ }++ AddonData* addon_data = (AddonData*)data;+ napi_value array;+ CHECK(napi_create_array(env, &array) == napi_ok);++ for (uint32_t idx = 0; idx < PRIME_COUNT; idx++) {+ napi_value js_the_prime;++ // Convert the integer to a napi_value.+ CHECK(napi_create_int32(env, addon_data->data[idx], &js_the_prime) == napi_ok);++ // Store the js value in the array.+ CHECK(napi_set_element(env, array, idx, js_the_prime) == napi_ok);+ }+ CHECK(napi_resolve_deferred(env, addon_data->deferred, array) == napi_ok);++ // Clean up the work item associated with this run.+ CHECK(napi_delete_async_work(env, addon_data->work) == napi_ok);++ // Set both values to NULL so JavaScript can order a new run of the thread.+ addon_data->work = NULL;+ addon_data->deferred = NULL;+}++// Create a deferred promise and an async queue work item.+static napi_value StartWork(napi_env env, napi_callback_info info) {+ napi_value work_name, promise;+ AddonData* addon_data;++ // Retrieve the per-addon data.+ CHECK(napi_get_cb_info(env,+ info,+ NULL,+ NULL,+ NULL,+ (void**)(&addon_data)) == napi_ok);++ // Ensure that no work is currently in progress.+ CHECK(addon_data->work == NULL && "Only one work item must exist at a time");++ // Create a string to describe this asynchronous operation.+ CHECK(napi_create_string_utf8(env,+ "Node-API Deferred Promise from Async Work Item",+ NAPI_AUTO_LENGTH,+ &work_name) == napi_ok);++ // Create a deferred promise which we will resolve at the completion of the work.+ CHECK(napi_create_promise(env,+ &(addon_data->deferred),+ &promise) == napi_ok);++ // Create an async work item, passing in the addon data, which will give the+ // worker thread access to the above-created deferred promise.+ CHECK(napi_create_async_work(env,+ NULL,+ work_name,+ ExecuteWork,+ WorkComplete,+ addon_data,+ &(addon_data->work)) == napi_ok);++ // Queue the work item for execution.+ CHECK(napi_queue_async_work(env, addon_data->work) == napi_ok);++ // This causes created `promise` to be returned to JavaScript.+ return promise;+}++// Free the per-addon-instance data.+static void addon_getting_unloaded(napi_env env, void* data, void* hint) {+ AddonData* addon_data = (AddonData*)data;+ CHECK(addon_data->work == NULL &&+ "No work item in progress at module unload");+ free(addon_data);+}++// The commented-out return type and the commented out formal function+// parameters below help us keep in mind the signature of the addon+// initialization function. We write the body as though the return value were as+// commented below and as though there were parameters passed in as commented+// below.+/*napi_value*/ NAPI_MODULE_INIT(/*napi_env env, napi_value exports*/) {++ // Define addon-level data associated with this instance of the addon.+ AddonData* addon_data = (AddonData*)malloc(sizeof(*addon_data));+ addon_data->work = NULL;++ // Define the properties that will be set on exports.+ napi_property_descriptor start_work = {+ "startWork",+ NULL,+ StartWork,+ NULL,+ NULL,+ NULL,+ napi_default,+ addon_data+ };++ // Decorate exports with the above-defined properties.+ CHECK(napi_define_properties(env, exports, 1, &start_work) == napi_ok);++ // Associate the addon data with the exports object, to make sure that when+ // the addon gets unloaded our data gets freed.+ CHECK(napi_wrap(env,+ exports,+ addon_data,+ addon_getting_unloaded,+ NULL,+ NULL) == napi_ok);++ // Return the decorated exports object.+ return exports;+}
src/5-async-work/async_work_promise/napi/binding.gyp
@@ -0,0 +1,8 @@+{+ 'targets': [+ {+ 'target_name': 'binding',+ 'sources': [ 'binding.c' ]+ }+ ]+}
src/5-async-work/async_work_promise/napi/index.js
@@ -0,0 +1,10 @@+// Use the "bindings" package to locate the native bindings.+const binding = require('bindings')('binding');++// Call the function "startWork" which the native bindings library exposes.+// The function returns a promise which will be resolved at the complete of the+// work with an array of worked out primes. This resolution simply prints them out.+binding.startWork()+ .then((thePrimes) => {+ console.log("Received primes from completed work: " + thePrimes)+ });
src/5-async-work/async_work_promise/napi/package.json
@@ -0,0 +1,17 @@+{+ "name": "async_work_promise",+ "version": "0.0.0",+ "description": "Calling into JS from the thread pool",+ "main": "index.js",+ "private": true,+ "dependencies": {+ "bindings": "~1.5.0"+ },+ "engines": {+ "node": ">= 10.6.0"+ },+ "scripts": {+ "test": "node index.js"+ },+ "gypfile": true+}