eventemitter seems to work
This commit is contained in:
parent
f4ca876cc2
commit
0f9ada3680
20
README.md
20
README.md
|
@ -30,6 +30,7 @@ dependency packages.
|
||||||
|
|
||||||
[Cross-platform commands](#cross-platform-commands)
|
[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'],
|
'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<v8::Value> *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<v8::Value> that, const std::string &method)`
|
||||||
|
subscribes `that[method]` to receive `name` events from this emitter, basically
|
||||||
|
`emitter.on(name, that[method])`.
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
'use strict';
|
'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;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Example } = require('./core');
|
const Example = require('./core');
|
||||||
|
|
||||||
console.log('Example', Example);
|
console.log('Example', Example);
|
||||||
|
|
||||||
|
|
||||||
const example = new Example();
|
const example = new Example();
|
||||||
|
|
||||||
|
console.log('example 0', example);
|
||||||
|
|
||||||
console.log('static listenerCount', Example.listenerCount);
|
console.log('static listenerCount', Example.listenerCount);
|
||||||
|
|
||||||
|
@ -26,16 +27,15 @@ console.log('setMaxListeners', example.setMaxListeners);
|
||||||
console.log('rawListeners', example.rawListeners);
|
console.log('rawListeners', example.rawListeners);
|
||||||
console.log('destroy', example.destroy);
|
console.log('destroy', example.destroy);
|
||||||
|
|
||||||
// console.log('example.eventNames -2', example.eventNames());
|
|
||||||
example.on('evt1', (arg1, arg2) => {
|
example.on('evt1', (arg1, arg2) => {
|
||||||
console.log('EVT1', arg1, arg2, example.eventNames());
|
console.log('EVT1', arg1, arg2, example.eventNames());
|
||||||
});
|
});
|
||||||
// console.log('example.eventNames -1', example.eventNames());
|
|
||||||
example.once('evt2', (arg1, arg2) => {
|
example.once('evt2', (arg1, arg2) => {
|
||||||
console.log('EVT2', arg1, arg2, example.eventNames());
|
console.log('EVT2', arg1, arg2, example.eventNames());
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log('example.eventNames 0', example.eventNames());
|
|
||||||
|
|
||||||
example.emit('evt1', 111, '221');
|
example.emit('evt1', 111, '221');
|
||||||
example.emit('evt1', 112, '222');
|
example.emit('evt1', 112, '222');
|
||||||
|
@ -48,6 +48,8 @@ console.log('example.eventNames 2', example.eventNames());
|
||||||
|
|
||||||
example.emit('evt2', 112, '222');
|
example.emit('evt2', 112, '222');
|
||||||
|
|
||||||
// console.log('example.eventNames 3', example.eventNames());
|
|
||||||
|
console.log('example 1', example);
|
||||||
|
|
||||||
|
|
||||||
module.exports = Example;
|
module.exports = Example;
|
||||||
|
|
|
@ -6,15 +6,14 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <iostream>
|
// #include <iostream> -> std::cout << "..." << std::endl;
|
||||||
|
|
||||||
|
|
||||||
#define THIS_EMITTER \
|
#define THIS_EMITTER \
|
||||||
EventEmitter *emitter = ObjectWrap::Unwrap<EventEmitter>(info.This());
|
EventEmitter *emitter = ObjectWrap::Unwrap<EventEmitter>(info.This());
|
||||||
|
|
||||||
|
|
||||||
// Use the dummy template for static-int initialization
|
// Use the dummy template class for static-int initialization
|
||||||
|
|
||||||
template< class Dummy >
|
template< class Dummy >
|
||||||
class EventEmitterStatics {
|
class EventEmitterStatics {
|
||||||
protected:
|
protected:
|
||||||
|
@ -36,48 +35,6 @@ class EventEmitter : public Nan::ObjectWrap, public EventEmitterStatics<void> {
|
||||||
typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE;
|
typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE;
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// C++ side emit() method
|
|
||||||
void emit(const std::string &name, int argc = 0, v8::Local<v8::Value> *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<v8::Value> that, const std::string &method) {
|
|
||||||
|
|
||||||
v8::Local<v8::String> code = JS_STR(
|
|
||||||
"((emitter, name, that, method) => emitter.on(name, that[method]))"
|
|
||||||
);
|
|
||||||
|
|
||||||
v8::Local<v8::Function> connector = v8::Local<v8::Function>::Cast(v8::Script::Compile(code)->Run());
|
|
||||||
Nan::Callback connectorCb(connector);
|
|
||||||
|
|
||||||
v8::Local<v8::Object> emitter = Nan::New<v8::Object>();
|
|
||||||
this->Wrap(emitter);
|
|
||||||
|
|
||||||
v8::Local<v8::Value> argv[] = { emitter, JS_STR(name.c_str()), that, JS_STR(method.c_str()) };
|
|
||||||
connectorCb.Call(4, argv);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
EventEmitter () {
|
EventEmitter () {
|
||||||
|
@ -115,12 +72,59 @@ protected:
|
||||||
Nan::SetMethod(ctorFunc, "listenerCount", jsStaticListenerCount);
|
Nan::SetMethod(ctorFunc, "listenerCount", jsStaticListenerCount);
|
||||||
ACCESSOR_RW(ctorObj, defaultMaxListeners);
|
ACCESSOR_RW(ctorObj, defaultMaxListeners);
|
||||||
|
|
||||||
//Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
|
}
|
||||||
// ACCESSOR_RW(proto, type);
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// C++ side emit() method
|
||||||
|
void emit(const std::string &name, int argc = 0, v8::Local<v8::Value> *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<v8::Value> that, const std::string &method) {
|
||||||
|
|
||||||
|
v8::Local<v8::String> code = JS_STR(
|
||||||
|
"((emitter, name, that, method) => emitter.on(name, that[method]))"
|
||||||
|
);
|
||||||
|
|
||||||
|
v8::Local<v8::Function> connector = v8::Local<v8::Function>::Cast(v8::Script::Compile(code)->Run());
|
||||||
|
Nan::Callback connectorCb(connector);
|
||||||
|
|
||||||
|
v8::Local<v8::Object> emitter = Nan::New<v8::Object>();
|
||||||
|
this->Wrap(emitter);
|
||||||
|
|
||||||
|
v8::Local<v8::Value> argv[] = { emitter, JS_STR(name.c_str()), that, JS_STR(method.c_str()) };
|
||||||
|
connectorCb.Call(4, argv);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
// Deprecated static method
|
// Deprecated static method
|
||||||
static NAN_METHOD(jsStaticListenerCount) {
|
static NAN_METHOD(jsStaticListenerCount) {
|
||||||
|
|
||||||
|
@ -137,73 +141,53 @@ protected:
|
||||||
|
|
||||||
static NAN_SETTER(defaultMaxListenersSetter) { THIS_EMITTER; SETTER_INT32_ARG;
|
static NAN_SETTER(defaultMaxListenersSetter) { THIS_EMITTER; SETTER_INT32_ARG;
|
||||||
|
|
||||||
EventEmitter::_defaultMaxListeners = v;
|
_defaultMaxListeners = v;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static NAN_GETTER(defaultMaxListenersGetter) { THIS_EMITTER;
|
static NAN_GETTER(defaultMaxListenersGetter) { THIS_EMITTER;
|
||||||
|
|
||||||
RET_VALUE(JS_INT(EventEmitter::_defaultMaxListeners));
|
RET_VALUE(JS_INT(_defaultMaxListeners));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsAddListener) { THIS_EMITTER;
|
static NAN_METHOD(jsAddListener) { _wrapListener(info); }
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
REQ_FUN_ARG(1, cb);
|
|
||||||
|
|
||||||
Nan::Persistent<v8::Function> persistentCb;
|
|
||||||
persistentCb.Reset(cb);
|
|
||||||
|
|
||||||
emitter->_listeners[std::string(*name)].push_back(persistentCb);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsEmit) { THIS_EMITTER;
|
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);
|
REQ_UTF8_ARG(0, name);
|
||||||
|
|
||||||
int length = info.Length();
|
int length = info.Length();
|
||||||
|
|
||||||
std::vector< v8::Local<v8::Value> > args;
|
std::vector< v8::Local<v8::Value> > args;
|
||||||
std::cout << "emit 1 " << emitter->_listeners.size() << std::endl;
|
|
||||||
for (int i = 1; i < length; i++) {
|
for (int i = 1; i < length; i++) {
|
||||||
args.push_back(info[i]);
|
args.push_back(info[i]);
|
||||||
}
|
}
|
||||||
std::cout << "emit 2 " << emitter->_listeners.size() << std::endl;
|
|
||||||
emitter->emit(*name, length - 1, &args[0]);
|
emitter->emit(*name, length - 1, &args[0]);
|
||||||
std::cout << "emit 3 " << emitter->_listeners.size() << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsEventNames) { THIS_EMITTER;
|
static NAN_METHOD(jsEventNames) { THIS_EMITTER;
|
||||||
std::cout << "jsEventNames 0 " << emitter->_raw.size() << std::endl;
|
|
||||||
v8::Local<v8::Array> jsNames = Nan::New<v8::Array>(emitter->_raw.size());
|
v8::Local<v8::Array> jsNames = Nan::New<v8::Array>(emitter->_raw.size());
|
||||||
|
|
||||||
if (emitter->_raw.empty()) {
|
if (emitter->_raw.empty()) {
|
||||||
RET_VALUE(jsNames);
|
RET_VALUE(jsNames);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::cout << "jsEventNames 1 " << emitter->_raw.size() << std::endl;
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (MAP_IT_TYPE it = emitter->_raw.begin(); it != emitter->_raw.end(); ++it, i++) {
|
for (MAP_IT_TYPE it = emitter->_raw.begin(); it != emitter->_raw.end(); ++it, i++) {
|
||||||
|
|
||||||
jsNames->Set(JS_INT(i), JS_STR(it->first));
|
jsNames->Set(JS_INT(i), JS_STR(it->first));
|
||||||
|
|
||||||
}
|
}
|
||||||
std::cout << "jsEventNames 2 " << emitter->_raw.size() << std::endl;
|
|
||||||
RET_VALUE(jsNames);
|
RET_VALUE(jsNames);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "addon-tools-raub",
|
"name": "addon-tools-raub",
|
||||||
"author": "Luis Blanco <raubtierxxx@gmail.com>",
|
"author": "Luis Blanco <raubtierxxx@gmail.com>",
|
||||||
"description": "A set of extra tools for Node.js addons",
|
"description": "A set of extra tools for Node.js addons",
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"node",
|
"node",
|
||||||
|
|
Loading…
Reference in New Issue