From 6a5b21b6eab97f96ca9ca26f230b3e30817c8b68 Mon Sep 17 00:00:00 2001 From: Roy Wright Date: Sat, 28 Apr 2018 18:05:34 +0900 Subject: [PATCH] Add resource parameters to AsyncWorker constructor This change is initiated from https://github.com/nodejs/node-addon-api/pull/140#discussion_r140302349. PR-URL: https://github.com/nodejs/node-addon-api/pull/253 Reviewed-By: Michael Dawson Reviewed-By: Nicola Del Gobbo --- napi-inl.h | 42 ++++++++++++++++++--- napi.h | 15 +++++++- test/asyncworker.cc | 10 +++-- test/asyncworker.js | 89 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 134 insertions(+), 22 deletions(-) diff --git a/napi-inl.h b/napi-inl.h index 884f8cb..77e4d55 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -3079,21 +3079,51 @@ inline Value EscapableHandleScope::Escape(napi_value escapee) { //////////////////////////////////////////////////////////////////////////////// inline AsyncWorker::AsyncWorker(const Function& callback) - : AsyncWorker(Object::New(callback.Env()), callback) { + : AsyncWorker(callback, "generic") { } -inline AsyncWorker::AsyncWorker(const Object& receiver, const Function& callback) +inline AsyncWorker::AsyncWorker(const Function& callback, + const char* resource_name) + : AsyncWorker(callback, resource_name, Object::New(callback.Env())) { +} + +inline AsyncWorker::AsyncWorker(const Function& callback, + const char* resource_name, + const Object& resource) + : AsyncWorker(Object::New(callback.Env()), + callback, + resource_name, + resource) { +} + +inline AsyncWorker::AsyncWorker(const Object& receiver, + const Function& callback) + : AsyncWorker(receiver, callback, "generic") { +} + +inline AsyncWorker::AsyncWorker(const Object& receiver, + const Function& callback, + const char* resource_name) + : AsyncWorker(receiver, + callback, + resource_name, + Object::New(callback.Env())) { +} + +inline AsyncWorker::AsyncWorker(const Object& receiver, + const Function& callback, + const char* resource_name, + const Object& resource) : _env(callback.Env()), _receiver(Napi::Persistent(receiver)), _callback(Napi::Persistent(callback)) { - napi_value resource_id; napi_status status = napi_create_string_latin1( - _env, "generic", NAPI_AUTO_LENGTH, &resource_id); + _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); NAPI_THROW_IF_FAILED(_env, status); - status = napi_create_async_work( - _env, nullptr, resource_id, OnExecute, OnWorkComplete, this, &_work); + status = napi_create_async_work(_env, resource, resource_id, OnExecute, + OnWorkComplete, this, &_work); NAPI_THROW_IF_FAILED(_env, status); } diff --git a/napi.h b/napi.h index a2d1f20..0aa9a6a 100644 --- a/napi.h +++ b/napi.h @@ -1515,7 +1515,20 @@ namespace Napi { protected: explicit AsyncWorker(const Function& callback); - explicit AsyncWorker(const Object& receiver, const Function& callback); + explicit AsyncWorker(const Function& callback, + const char* resource_name); + explicit AsyncWorker(const Function& callback, + const char* resource_name, + const Object& resource); + explicit AsyncWorker(const Object& receiver, + const Function& callback); + explicit AsyncWorker(const Object& receiver, + const Function& callback, + const char* resource_name); + explicit AsyncWorker(const Object& receiver, + const Function& callback, + const char* resource_name, + const Object& resource); virtual void Execute() = 0; virtual void OnOK(); diff --git a/test/asyncworker.cc b/test/asyncworker.cc index 0a3c7e2..12cdcfa 100644 --- a/test/asyncworker.cc +++ b/test/asyncworker.cc @@ -6,10 +6,11 @@ class TestWorker : public AsyncWorker { public: static void DoWork(const CallbackInfo& info) { bool succeed = info[0].As(); - Function cb = info[1].As(); - Value data = info[2]; + Object resource = info[1].As(); + Function cb = info[2].As(); + Value data = info[3]; - TestWorker* worker = new TestWorker(cb); + TestWorker* worker = new TestWorker(cb, "TestResource", resource); worker->Receiver().Set("data", data); worker->_succeed = succeed; worker->Queue(); @@ -23,7 +24,8 @@ class TestWorker : public AsyncWorker { } private: - TestWorker(Function cb) : AsyncWorker(cb) {} + TestWorker(Function cb, const char* resource_name, const Object& resource) + : AsyncWorker(cb, resource_name, resource) {} bool _succeed; }; diff --git a/test/asyncworker.js b/test/asyncworker.js index 92d2458..05195e4 100644 --- a/test/asyncworker.js +++ b/test/asyncworker.js @@ -1,21 +1,88 @@ 'use strict'; const buildType = process.config.target_defaults.default_configuration; const assert = require('assert'); +const async_hooks = require('async_hooks'); +const common = require('./common'); test(require(`./build/${buildType}/binding.node`)); test(require(`./build/${buildType}/binding_noexcept.node`)); +function installAsyncHooksForTest() { + return new Promise((resolve, reject) => { + let id; + const events = []; + const hook = async_hooks.createHook({ + init(asyncId, type, triggerAsyncId, resource) { + if (id === undefined && type === 'TestResource') { + id = asyncId; + events.push({ eventName: 'init', type, triggerAsyncId, resource }); + } + }, + before(asyncId) { + if (asyncId === id) { + events.push({ eventName: 'before' }); + } + }, + after(asyncId) { + if (asyncId === id) { + events.push({ eventName: 'after' }); + } + }, + destroy(asyncId) { + if (asyncId === id) { + events.push({ eventName: 'destroy' }); + hook.disable(); + resolve(events); + } + } + }).enable(); + }); +} + function test(binding) { - binding.asyncworker.doWork(true, function (e) { - assert.strictEqual(typeof e, 'undefined'); - assert.strictEqual(typeof this, 'object'); - assert.strictEqual(this.data, 'test data'); - }, 'test data'); + { + const hooks = installAsyncHooksForTest(); + const triggerAsyncId = async_hooks.executionAsyncId(); + binding.asyncworker.doWork(true, { foo: 'foo' }, function (e) { + assert.strictEqual(typeof e, 'undefined'); + assert.strictEqual(typeof this, 'object'); + assert.strictEqual(this.data, 'test data'); + }, 'test data'); + + hooks.then(actual => { + assert.deepStrictEqual(actual, [ + { eventName: 'init', + type: 'TestResource', + triggerAsyncId: triggerAsyncId, + resource: { foo: 'foo' } }, + { eventName: 'before' }, + { eventName: 'after' }, + { eventName: 'destroy' } + ]); + }).catch(common.mustNotCall()); + } + + { + const hooks = installAsyncHooksForTest(); + const triggerAsyncId = async_hooks.executionAsyncId(); + + binding.asyncworker.doWork(false, { foo: 'foo' }, function (e) { + assert.ok(e instanceof Error); + assert.strictEqual(e.message, 'test error'); + assert.strictEqual(typeof this, 'object'); + assert.strictEqual(this.data, 'test data'); + }, 'test data'); - binding.asyncworker.doWork(false, function (e) { - assert.ok(e instanceof Error); - assert.strictEqual(e.message, 'test error'); - assert.strictEqual(typeof this, 'object'); - assert.strictEqual(this.data, 'test data'); - }, 'test data'); + hooks.then(actual => { + assert.deepStrictEqual(actual, [ + { eventName: 'init', + type: 'TestResource', + triggerAsyncId: triggerAsyncId, + resource: { foo: 'foo' } }, + { eventName: 'before' }, + { eventName: 'after' }, + { eventName: 'destroy' } + ]); + }).catch(common.mustNotCall()); + } }