This commit is contained in:
raub 2018-03-05 18:04:12 +03:00
parent cdb498aac3
commit 4e2728c8bc
6 changed files with 165 additions and 75 deletions

View File

@ -1,3 +1,3 @@
'use strict'; 'use strict';
module.exports = require('./binary/example'); module.exports = require('./binary/addon');

View File

@ -28,12 +28,13 @@ void Example::init(Handle<Object> target) {
// prototype // prototype
Nan::SetPrototypeMethod(ctor, "destroy", destroy); Nan::SetPrototypeMethod(ctor, "destroy", destroy);
extend(ctor);
Local<ObjectTemplate> proto = ctor->PrototypeTemplate(); Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
// ACCESSOR_RW(proto, prop); // ACCESSOR_RW(proto, prop);
EventEmitter::extend(ctor, proto);
_constructor.Reset(Nan::GetFunction(ctor).ToLocalChecked()); _constructor.Reset(Nan::GetFunction(ctor).ToLocalChecked());
Nan::Set(target, JS_STR("Example"), Nan::GetFunction(ctor).ToLocalChecked()); Nan::Set(target, JS_STR("Example"), Nan::GetFunction(ctor).ToLocalChecked());

View File

@ -1,10 +1,46 @@
'use strict'; 'use strict';
const Wrapped = require('./js/wrapped'); const Example = require('./core');
const Example = require('./js/example');
console.log('Example', Example); console.log('Example', Example);
console.log('Wrapped', Wrapped);
const example = new Example();
console.log('static listenerCount', Example.listenerCount);
console.log('listenerCount', example.listenerCount);
console.log('addListener', example.addListener);
console.log('emit', example.emit);
console.log('eventNames', example.eventNames);
console.log('getMaxListeners', example.getMaxListeners);
console.log('listeners', example.listeners);
console.log('on', example.on);
console.log('once', example.once);
console.log('prependListener', example.prependListener);
console.log('prependOnceListener', example.prependOnceListener);
console.log('removeAllListeners', example.removeAllListeners);
console.log('removeListener', example.removeListener);
console.log('setMaxListeners', example.setMaxListeners);
console.log('rawListeners', example.rawListeners);
console.log('destroy', example.destroy);
example.on('evt1', (arg1, arg2) => {
console.log('EVT1', arg1, arg2);
});
example.once('evt2', (arg1, arg2) => {
console.log('EVT2', arg1, arg2);
});
example.emit('evt1', 111, '221');
example.emit('evt1', 112, '222');
example.emit('evt2', 111, '221');
example.emit('evt2', 112, '222');
module.exports = { Wrapped, Example }; module.exports = { Wrapped, Example };

View File

@ -1,7 +0,0 @@
'use strict';
const { Example } = require('../core');
module.exports = Example;

View File

@ -1,12 +0,0 @@
'use strict';
const { Example } = require('../core');
class Wrapped extends Example {
}
module.exports = Wrapped;

View File

@ -12,7 +12,19 @@
EventEmitter *emitter = ObjectWrap::Unwrap<EventEmitter>(info.This()); EventEmitter *emitter = ObjectWrap::Unwrap<EventEmitter>(info.This());
class EventEmitter : public Nan::ObjectWrap { // Use the dummy template for static-int initialization
template< class Dummy >
class EventEmitterStatics {
protected:
static int _defaultMaxListeners;
};
template< class Dummy >
int EventEmitterStatics<Dummy>::_defaultMaxListeners = 10;
class EventEmitter : public Nan::ObjectWrap, public EventEmitterStatics<void> {
typedef Nan::CopyablePersistentTraits<v8::Function>::CopyablePersistent FN_TYPE; typedef Nan::CopyablePersistentTraits<v8::Function>::CopyablePersistent FN_TYPE;
typedef std::deque<FN_TYPE> VEC_TYPE; typedef std::deque<FN_TYPE> VEC_TYPE;
@ -22,8 +34,51 @@ class EventEmitter : public Nan::ObjectWrap {
typedef MAP_TYPE::iterator MAP_IT_TYPE; typedef MAP_TYPE::iterator MAP_IT_TYPE;
typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE; typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE;
public: 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:
EventEmitter () { EventEmitter () {
_maxListeners = _defaultMaxListeners; _maxListeners = _defaultMaxListeners;
_freeId = 0; _freeId = 0;
@ -31,17 +86,7 @@ public:
~EventEmitter () {} ~EventEmitter () {}
static void extend(v8::Local<v8::FunctionTemplate> &ctor, v8::Local<v8::ObjectTemplate> &proto) { static void extend(v8::Local<v8::FunctionTemplate> &ctor) {
v8::Local<v8::Function> ctorFunc = Nan::GetFunction(ctor).ToLocalChecked();
v8::Local<v8::Object> ctorObj = ctorFunc;
// -------- static
Nan::SetMethod(ctorFunc, "listenerCount", jsStaticListenerCount);
ACCESSOR_RW(ctorObj, defaultMaxListeners);
// -------- dynamic // -------- dynamic
@ -60,41 +105,31 @@ public:
Nan::SetPrototypeMethod(ctor, "setMaxListeners", jsSetMaxListeners); Nan::SetPrototypeMethod(ctor, "setMaxListeners", jsSetMaxListeners);
Nan::SetPrototypeMethod(ctor, "rawListeners", jsRawListeners); Nan::SetPrototypeMethod(ctor, "rawListeners", jsRawListeners);
// -------- static
v8::Local<v8::Function> ctorFunc = Nan::GetFunction(ctor).ToLocalChecked();
v8::Local<v8::Object> ctorObj = ctorFunc;
Nan::SetMethod(ctorFunc, "listenerCount", jsStaticListenerCount);
ACCESSOR_RW(ctorObj, defaultMaxListeners);
//Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
// ACCESSOR_RW(proto, type); // ACCESSOR_RW(proto, type);
} }
void emit(const std::string &name, int argc = 0, v8::Local<v8::Value> *argv = NULL) { // Deprecated static method
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);
}
}
}
// Deprecated method
static NAN_METHOD(jsStaticListenerCount) { static NAN_METHOD(jsStaticListenerCount) {
// EventEmitter *emitter = ObjectWrap::Unwrap<EventEmitter>(info[0]); REQ_OBJ_ARG(0, obj);
// REQ_UTF8_ARG(1, name); EventEmitter *emitter = ObjectWrap::Unwrap<EventEmitter>(obj);
REQ_UTF8_ARG(1, name);
// const VEC_TYPE &list = emitter->_listeners[*name]; const VEC_TYPE &list = emitter->_listeners[*name];
// RET_VALUE(JS_NUM(list.size())); RET_VALUE(JS_INT(static_cast<int>(list.size())));
} }
@ -129,7 +164,15 @@ public:
REQ_UTF8_ARG(0, name); REQ_UTF8_ARG(0, name);
emitter->emit(*name, info.Length() - 1, &info[1]); int length = info.Length();
std::vector< v8::Local<v8::Value> > args;
for (int i = 1; i < length; i++) {
args.push_back(info[i]);
}
emitter->emit(*name, length - 1, &args[0]);
} }
@ -205,6 +248,9 @@ public:
bool isFront bool isFront
) { THIS_EMITTER; ) { THIS_EMITTER;
v8::Local<v8::Value> args[] = { info[0], info[1] };
emitter->emit("newListener", 2, args);
if (isFront) { if (isFront) {
emitter->_listeners[name].push_front(cb); emitter->_listeners[name].push_front(cb);
emitter->_raw[name].push_front(cb); emitter->_raw[name].push_front(cb);
@ -240,6 +286,9 @@ public:
bool isFront bool isFront
) { THIS_EMITTER; ) { THIS_EMITTER;
v8::Local<v8::Value> args[] = { info[0], info[1] };
emitter->emit("newListener", 2, args);
if (isFront) { if (isFront) {
emitter->_listeners[name].push_front(cb); emitter->_listeners[name].push_front(cb);
emitter->_raw[name].push_front(raw); emitter->_raw[name].push_front(raw);
@ -264,16 +313,16 @@ public:
REQ_FUN_ARG(1, raw); REQ_FUN_ARG(1, raw);
v8::Local<v8::String> code = JS_STR( v8::Local<v8::String> code = JS_STR(
"((emitter, cb) => (...args) => {\n\ "((emitter, name, cb) => (...args) => {\n\
cb(...args);\n\ cb(...args);\n\
emitter.removeListener(cb);\n\ emitter.removeListener(name, cb);\n\
})" })"
); );
v8::Local<v8::Function> decor = v8::Local<v8::Function>::Cast(v8::Script::Compile(code)->Run()); v8::Local<v8::Function> decor = v8::Local<v8::Function>::Cast(v8::Script::Compile(code)->Run());
Nan::Callback decorCb(decor); Nan::Callback decorCb(decor);
v8::Local<v8::Value> argv[] = { info.This(), raw }; v8::Local<v8::Value> argv[] = { info.This(), info[0], raw };
v8::Local<v8::Function> wrap = v8::Local<v8::Function>::Cast(decorCb.Call(2, argv)); v8::Local<v8::Function> wrap = v8::Local<v8::Function>::Cast(decorCb.Call(3, argv));
Nan::Persistent<v8::Function> persistentWrap; Nan::Persistent<v8::Function> persistentWrap;
persistentWrap.Reset(wrap); persistentWrap.Reset(wrap);
@ -299,11 +348,27 @@ public:
if (info.Length() > 0 && info[0]->IsString()) { if (info.Length() > 0 && info[0]->IsString()) {
MAP_TYPE tmpMap = emitter->_raw;
emitter->_listeners.clear(); emitter->_listeners.clear();
emitter->_raw.clear(); emitter->_raw.clear();
emitter->_wrappedIds.clear(); emitter->_wrappedIds.clear();
emitter->_rawIds.clear(); emitter->_rawIds.clear();
for (MAP_IT_TYPE itMap = tmpMap.begin(); itMap != tmpMap.end(); ++itMap) {
const std::string &current = itMap->first;
VEC_TYPE &list = itMap->second;
for (IT_TYPE it = list.begin(); it != list.end(); ++it) {
v8::Local<v8::Value> args[] = { JS_STR(current.c_str()), Nan::New(*it) };
emitter->emit("removeListener", 2, args);
}
}
return; return;
} }
@ -326,7 +391,6 @@ public:
FN_TYPE fn = *it; FN_TYPE fn = *it;
for (FNMAP_IT_TYPE itRaw = emitter->_rawIds.begin(); itRaw != emitter->_rawIds.end(); ++itRaw) { for (FNMAP_IT_TYPE itRaw = emitter->_rawIds.begin(); itRaw != emitter->_rawIds.end(); ++itRaw) {
// emitter->_wrappedIds.erase(*it);
if (fn == itRaw->second) { if (fn == itRaw->second) {
removes.push_back(itRaw->first); removes.push_back(itRaw->first);
} }
@ -346,9 +410,18 @@ public:
} }
VEC_TYPE tmpVec = emitter->_raw[name];
emitter->_listeners[name].clear(); emitter->_listeners[name].clear();
emitter->_raw[name].clear(); emitter->_raw[name].clear();
for (IT_TYPE it = tmpVec.begin(); it != tmpVec.end(); ++it) {
v8::Local<v8::Value> args[] = { JS_STR(name.c_str()), Nan::New(*it) };
emitter->emit("removeListener", 2, args);
}
} }
@ -362,13 +435,14 @@ public:
std::string name = std::string(*n); std::string name = std::string(*n);
VEC_TYPE &rawList = emitter->_raw[name]; VEC_TYPE &rawList = emitter->_raw[name];
if (rawList.empty()) { if (rawList.empty()) {
return; return;
} }
v8::Local<v8::Value> args[] = { info[0], info[1] };
for (IT_TYPE it = rawList.begin(); it != rawList.end(); ++it) { for (IT_TYPE it = rawList.begin(); it != rawList.end(); ++it) {
if (*it == persistentRaw) { if (*it == persistentRaw) {
@ -392,6 +466,7 @@ public:
} }
emitter->emit("removeListener", 2, args);
return; return;
} }
@ -421,6 +496,8 @@ public:
} }
emitter->emit("removeListener", 2, args);
} }
@ -458,11 +535,6 @@ public:
} }
private:
static int _defaultMaxListeners;
private: private:
int _maxListeners; int _maxListeners;