From ee20c3e065cababd5b84959bd469fd9b90db1642 Mon Sep 17 00:00:00 2001 From: Jinho Bang Date: Sat, 28 Apr 2018 18:05:34 +0900 Subject: [PATCH] Add resource_name and resource parameters to AsyncWorker constructor This change is initiated from https://github.com/nodejs/node-addon-api/pull/140#discussion_r140302349. --- napi-inl.h | 42 ++++++++++++++++++--- napi.h | 15 +++++++- test/asyncworker.cc | 10 +++-- test/asyncworker.js | 92 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 134 insertions(+), 25 deletions(-) diff --git a/napi-inl.h b/napi-inl.h index 884f8cbbf..77e4d5584 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 a2d1f20ec..303c15c8c 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); + AsyncWorker(const Function& callback, + const char* resource_name); + AsyncWorker(const Function& callback, + const char* resource_name, + const Object& resource); + AsyncWorker(const Object& receiver, + const Function& callback); + AsyncWorker(const Object& receiver, + const Function& callback, + const char* resource_name); + 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 0a3c7e211..12cdcfabe 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 92d2458aa..7954320d4 100644 --- a/test/asyncworker.js +++ b/test/asyncworker.js @@ -1,21 +1,85 @@ 'use strict'; const buildType = process.config.target_defaults.default_configuration; const assert = require('assert'); +const async_hooks = require('async_hooks'); -test(require(`./build/${buildType}/binding.node`)); -test(require(`./build/${buildType}/binding_noexcept.node`)); +(async() => { + await test(require(`./build/${buildType}/binding.node`)); + await test(require(`./build/${buildType}/binding_noexcept.node`)); +})(); -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'); +function installAsyncHooksForTest() { + return new Promise((resolve, reject) => { + let id; + const events = []; + const hook = async_hooks.createHook({ + init(asyncId, type, triggerAsyncId, resource) { + if (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(); + }); +} + +async function test(binding) { + { + 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'); + + assert.deepStrictEqual(await hooks, [ + { eventName: 'init', + type: 'TestResource', + triggerAsyncId, + resource: { foo: 'foo' } }, + { eventName: 'before' }, + { eventName: 'after' }, + { eventName: 'destroy' } + ]); + } + + { + 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'); + assert.deepStrictEqual(await hooks, [ + { eventName: 'init', + type: 'TestResource', + triggerAsyncId, + resource: { foo: 'foo' } }, + { eventName: 'before' }, + { eventName: 'after' }, + { eventName: 'destroy' } + ]); + } }