From 0f9ada368008661801ca03c865281d317c9de9ff Mon Sep 17 00:00:00 2001 From: raub Date: Tue, 6 Mar 2018 17:53:43 +0300 Subject: [PATCH] eventemitter seems to work --- README.md | 20 +++++ examples/node-addon/core.js | 12 ++- examples/node-addon/index.js | 12 +-- include/event-emitter.hpp | 138 ++++++++++++++++------------------- package.json | 2 +- 5 files changed, 100 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 6902cad..219ebc1 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ dependency packages. [Cross-platform commands](#cross-platform-commands) +[Class EventEmitter](#class-eventemitter) --- @@ -559,3 +560,22 @@ For Windows the `/y` flag was embedded. ... 'action' : ['<(cp)', 'a', 'b'], ``` + +--- + + +## class EventEmitter + +A C++ implementation of [Events API](https://nodejs.org/api/events.html). + +An example of it's usage can be found in **examples/node-addon** directory. +There is `Example` class, implemented in **cpp/example.cpp**, that inherits +EventEmitter behavior and is exported to JS. + +For C++ side `EventEmitter` has following public methods: +* `void emit(const std::string &name, int argc = 0, v8::Local *argv = NULL)` +emits an event with the given `name` and, optionally, some additional arguments where +`argc` is the number of arguments and `argv` is a pointer to the arguments array. +* `void on(const std::string &name, v8::Local that, const std::string &method)` +subscribes `that[method]` to receive `name` events from this emitter, basically +`emitter.on(name, that[method])`. diff --git a/examples/node-addon/core.js b/examples/node-addon/core.js index 1752c6d..b1dc97b 100644 --- a/examples/node-addon/core.js +++ b/examples/node-addon/core.js @@ -1,3 +1,13 @@ 'use strict'; -module.exports = require('./binary/addon'); +const util = require('util'); + +const { Example } = require('./binary/addon'); + + +Example.prototype[util.inspect.custom] = function() { + return `Example { listeners: [${this.eventNames()}] }`; +}; + + +module.exports = Example; diff --git a/examples/node-addon/index.js b/examples/node-addon/index.js index f0c923b..b5ea524 100644 --- a/examples/node-addon/index.js +++ b/examples/node-addon/index.js @@ -1,12 +1,13 @@ 'use strict'; -const { Example } = require('./core'); +const Example = require('./core'); console.log('Example', Example); const example = new Example(); +console.log('example 0', example); console.log('static listenerCount', Example.listenerCount); @@ -26,16 +27,15 @@ console.log('setMaxListeners', example.setMaxListeners); console.log('rawListeners', example.rawListeners); console.log('destroy', example.destroy); -// console.log('example.eventNames -2', example.eventNames()); + example.on('evt1', (arg1, arg2) => { console.log('EVT1', arg1, arg2, example.eventNames()); }); -// console.log('example.eventNames -1', example.eventNames()); + example.once('evt2', (arg1, arg2) => { console.log('EVT2', arg1, arg2, example.eventNames()); }); -// console.log('example.eventNames 0', example.eventNames()); example.emit('evt1', 111, '221'); example.emit('evt1', 112, '222'); @@ -48,6 +48,8 @@ console.log('example.eventNames 2', example.eventNames()); example.emit('evt2', 112, '222'); -// console.log('example.eventNames 3', example.eventNames()); + +console.log('example 1', example); + module.exports = Example; diff --git a/include/event-emitter.hpp b/include/event-emitter.hpp index df1fd8a..dcfe1eb 100644 --- a/include/event-emitter.hpp +++ b/include/event-emitter.hpp @@ -6,15 +6,14 @@ #include #include -#include +// #include -> std::cout << "..." << std::endl; #define THIS_EMITTER \ EventEmitter *emitter = ObjectWrap::Unwrap(info.This()); -// Use the dummy template for static-int initialization - +// Use the dummy template class for static-int initialization template< class Dummy > class EventEmitterStatics { protected: @@ -36,48 +35,6 @@ class EventEmitter : public Nan::ObjectWrap, public EventEmitterStatics { typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE; -public: - - // C++ side emit() method - void emit(const std::string &name, int argc = 0, v8::Local *argv = NULL) { - - VEC_TYPE list = _listeners[name]; - - if (list.empty()) { - return; - } - - for (IT_TYPE it = list.begin(); it != list.end(); ++it) { - - Nan::Callback callback(Nan::New(*it)); - - if ( ! callback.IsEmpty() ) { - callback.Call(argc, argv); - } - - } - - } - - // C++ side on() method - void on(const std::string &name, v8::Local that, const std::string &method) { - - v8::Local code = JS_STR( - "((emitter, name, that, method) => emitter.on(name, that[method]))" - ); - - v8::Local connector = v8::Local::Cast(v8::Script::Compile(code)->Run()); - Nan::Callback connectorCb(connector); - - v8::Local emitter = Nan::New(); - this->Wrap(emitter); - - v8::Local argv[] = { emitter, JS_STR(name.c_str()), that, JS_STR(method.c_str()) }; - connectorCb.Call(4, argv); - - } - - protected: EventEmitter () { @@ -115,12 +72,59 @@ protected: Nan::SetMethod(ctorFunc, "listenerCount", jsStaticListenerCount); ACCESSOR_RW(ctorObj, defaultMaxListeners); - //Local proto = ctor->PrototypeTemplate(); - // ACCESSOR_RW(proto, type); + } + +public: + + // C++ side emit() method + void emit(const std::string &name, int argc = 0, v8::Local *argv = NULL) { + + // Important! As actual get map[key] produces a new (empty) map entry + if ( _listeners.find(name) == _listeners.end() ) { + return; + } + + // A copy is intended, because handlers can call removeListener (and they DO) + VEC_TYPE list = _listeners[name]; + + if (list.empty()) { + return; + } + + for (IT_TYPE it = list.begin(); it != list.end(); ++it) { + + Nan::Callback callback(Nan::New(*it)); + + if ( ! callback.IsEmpty() ) { + callback.Call(argc, argv); + } + + } } + // C++ side on() method + void on(const std::string &name, v8::Local that, const std::string &method) { + + v8::Local code = JS_STR( + "((emitter, name, that, method) => emitter.on(name, that[method]))" + ); + + v8::Local connector = v8::Local::Cast(v8::Script::Compile(code)->Run()); + Nan::Callback connectorCb(connector); + + v8::Local emitter = Nan::New(); + this->Wrap(emitter); + + v8::Local argv[] = { emitter, JS_STR(name.c_str()), that, JS_STR(method.c_str()) }; + connectorCb.Call(4, argv); + + } + + +protected: + // Deprecated static method static NAN_METHOD(jsStaticListenerCount) { @@ -137,73 +141,53 @@ protected: static NAN_SETTER(defaultMaxListenersSetter) { THIS_EMITTER; SETTER_INT32_ARG; - EventEmitter::_defaultMaxListeners = v; + _defaultMaxListeners = v; } static NAN_GETTER(defaultMaxListenersGetter) { THIS_EMITTER; - RET_VALUE(JS_INT(EventEmitter::_defaultMaxListeners)); + RET_VALUE(JS_INT(_defaultMaxListeners)); } - static NAN_METHOD(jsAddListener) { THIS_EMITTER; - - REQ_UTF8_ARG(0, name); - REQ_FUN_ARG(1, cb); - - Nan::Persistent persistentCb; - persistentCb.Reset(cb); - - emitter->_listeners[std::string(*name)].push_back(persistentCb); - - } + static NAN_METHOD(jsAddListener) { _wrapListener(info); } static NAN_METHOD(jsEmit) { THIS_EMITTER; - std::cout << "emit 0 " << emitter->_listeners.size() << std::endl; - for (MAP_IT_TYPE it = emitter->_listeners.begin(); it != emitter->_listeners.end(); ++it) { - - std::cout << "emit 0 _listeners " << it->first << std::endl; - - } - for (MAP_IT_TYPE it = emitter->_raw.begin(); it != emitter->_raw.end(); ++it) { - - std::cout << "emit 0 _raw " << it->first << std::endl; - - } + REQ_UTF8_ARG(0, name); int length = info.Length(); std::vector< v8::Local > args; - std::cout << "emit 1 " << emitter->_listeners.size() << std::endl; + for (int i = 1; i < length; i++) { args.push_back(info[i]); } - std::cout << "emit 2 " << emitter->_listeners.size() << std::endl; + emitter->emit(*name, length - 1, &args[0]); - std::cout << "emit 3 " << emitter->_listeners.size() << std::endl; + } static NAN_METHOD(jsEventNames) { THIS_EMITTER; - std::cout << "jsEventNames 0 " << emitter->_raw.size() << std::endl; + v8::Local jsNames = Nan::New(emitter->_raw.size()); if (emitter->_raw.empty()) { RET_VALUE(jsNames); return; } - std::cout << "jsEventNames 1 " << emitter->_raw.size() << std::endl; + int i = 0; for (MAP_IT_TYPE it = emitter->_raw.begin(); it != emitter->_raw.end(); ++it, i++) { jsNames->Set(JS_INT(i), JS_STR(it->first)); } - std::cout << "jsEventNames 2 " << emitter->_raw.size() << std::endl; + RET_VALUE(jsNames); } diff --git a/package.json b/package.json index 84f3b43..ce2ebfb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "addon-tools-raub", "author": "Luis Blanco ", "description": "A set of extra tools for Node.js addons", - "version": "0.0.8", + "version": "0.0.9", "main": "index.js", "keywords": [ "node",