wip new arch
This commit is contained in:
parent
1fb87351a5
commit
95173cd89c
|
@ -1,11 +1,8 @@
|
||||||
.idea
|
|
||||||
.cproject
|
.cproject
|
||||||
.project
|
.idea
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
build*/
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Debug/
|
.project
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
binary/
|
|
||||||
*.log
|
*.log
|
||||||
|
|
15
.npmignore
15
.npmignore
|
@ -1,15 +1,12 @@
|
||||||
*.log
|
|
||||||
.cproject
|
.cproject
|
||||||
.eslintrc
|
|
||||||
.gitignore
|
|
||||||
.idea
|
.idea
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
|
.DS_Store
|
||||||
.project
|
.project
|
||||||
binary/
|
node_modules/
|
||||||
build*/
|
|
||||||
CPPLINT.cfg
|
|
||||||
Debug/
|
|
||||||
examples/
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
.gitignore
|
||||||
|
CPPLINT.cfg
|
||||||
|
.eslintrc
|
||||||
test/
|
test/
|
||||||
qt/
|
*.log
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
- "10.13.0"
|
- "10.16.1"
|
||||||
|
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
|
72
README.md
72
README.md
|
@ -14,14 +14,15 @@ This is a part of [Node3D](https://github.com/node-3d) project.
|
||||||
|
|
||||||
Helpers for Node.js addons and dependency packages:
|
Helpers for Node.js addons and dependency packages:
|
||||||
|
|
||||||
* `consoleLog()` C++ implementation.
|
|
||||||
* `EventEmitter` C++ implementation.
|
|
||||||
* C++ macros and shortcuts.
|
* C++ macros and shortcuts.
|
||||||
|
* `consoleLog()` C++ helper.
|
||||||
|
* `eventEmit()` C++ helper.
|
||||||
|
* `getData()` C++ helper.
|
||||||
* Crossplatform commands for GYP: `cp`, `rm`, `mkdir`.
|
* Crossplatform commands for GYP: `cp`, `rm`, `mkdir`.
|
||||||
* Regarded platforms: win x32/x64, linux x64, mac x64.
|
* Supported platforms (x64): Windows, Linux, OSX.
|
||||||
|
|
||||||
Useful links: [V8 Ref](https://v8.paulfryzel.com/docs/master/),
|
Useful links: [N-API Docs](https://nodejs.org/api/n-api.html),
|
||||||
[Nan Docs](https://github.com/nodejs/nan#api),
|
[Napi Docs](https://github.com/nodejs/node-addon-api/blob/master/doc/setup.md),
|
||||||
[GYP Docs](https://gyp.gsrc.io/docs/UserDocumentation.md).
|
[GYP Docs](https://gyp.gsrc.io/docs/UserDocumentation.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -37,10 +38,10 @@ Useful links: [V8 Ref](https://v8.paulfryzel.com/docs/master/),
|
||||||
|
|
||||||
[Crossplatform commands](#crossplatform-commands)
|
[Crossplatform commands](#crossplatform-commands)
|
||||||
|
|
||||||
[Class EventEmitter](#class-eventemitter)
|
|
||||||
|
|
||||||
[Function consoleLog](#function-consolelog)
|
[Function consoleLog](#function-consolelog)
|
||||||
|
|
||||||
|
[Function eventEmit](#function-eventEmit)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,9 +50,7 @@ Useful links: [V8 Ref](https://v8.paulfryzel.com/docs/master/),
|
||||||
|
|
||||||
### binding.gyp
|
### binding.gyp
|
||||||
|
|
||||||
<details>
|
### Crossplatform commands
|
||||||
|
|
||||||
<summary>Crossplatform commands</summary>
|
|
||||||
|
|
||||||
```
|
```
|
||||||
'variables': {
|
'variables': {
|
||||||
|
@ -64,12 +63,8 @@ Useful links: [V8 Ref](https://v8.paulfryzel.com/docs/master/),
|
||||||
On both Windows and Unix those are the console commands for various
|
On both Windows and Unix those are the console commands for various
|
||||||
file system operations. No need for GYP conditions, yay!
|
file system operations. No need for GYP conditions, yay!
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
### Addon binary directory
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary>Addon binary directory</summary>
|
|
||||||
|
|
||||||
```
|
```
|
||||||
'variables': {
|
'variables': {
|
||||||
|
@ -77,58 +72,18 @@ Useful links: [V8 Ref](https://v8.paulfryzel.com/docs/master/),
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
In some cases, you'd like to have your addon installed for multiple architectures
|
|
||||||
simultaneously. For example, when using NVM to fluently switch environments.
|
|
||||||
Because the target directory is different for each arch, you only have to do
|
|
||||||
`npm rebuild` after the first switch.
|
|
||||||
|
|
||||||
</details>
|
### Include directories
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary>Include directories</summary>
|
|
||||||
|
|
||||||
```
|
```
|
||||||
'include_dirs': [
|
'include_dirs': [
|
||||||
'<!@(node -e "require(\'addon-tools-raub\').include()")',
|
'<!@(node -p "require(\'addon-tools-raub\').include")',
|
||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
Those are the directory paths to C++ include files for Addon Tools and Nan
|
Those are the directory paths to C++ include files for Addon Tools and Napi
|
||||||
(which is preinstalled with Addon Tools)
|
(which is preinstalled with Addon Tools)
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary>Remove intermediates</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
[ 'OS=="linux"', { 'action' : [
|
|
||||||
'<(rm)',
|
|
||||||
'<(module_root_dir)/build/Release/obj.target/addon/cpp/addon.o',
|
|
||||||
'<(module_root_dir)/build/Release/addon.node'
|
|
||||||
] } ],
|
|
||||||
[ 'OS=="mac"', { 'action' : [
|
|
||||||
'<(rm)',
|
|
||||||
'<(module_root_dir)/build/Release/obj.target/addon/cpp/addon.o',
|
|
||||||
'<(module_root_dir)/build/Release/addon.node'
|
|
||||||
] } ],
|
|
||||||
[ 'OS=="win"', { 'action' : [
|
|
||||||
'<(rm)',
|
|
||||||
'<(module_root_dir)/build/Release/addon.*',
|
|
||||||
'<(module_root_dir)/build/Release/obj/addon/*.*'
|
|
||||||
] } ],
|
|
||||||
```
|
|
||||||
|
|
||||||
Build-files can be removed in a separate build-step with `<(rm)`. Those are
|
|
||||||
usually PDB and OBJ files, which are rather big. However, in case of a hardcore
|
|
||||||
debug session you might want to comment this out.
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
### Binary dependency package
|
### Binary dependency package
|
||||||
|
|
||||||
|
@ -137,7 +92,6 @@ would encourage you to abide by the following rules:
|
||||||
|
|
||||||
* Your binary directories are:
|
* Your binary directories are:
|
||||||
|
|
||||||
* bin-win32
|
|
||||||
* bin-win64
|
* bin-win64
|
||||||
* bin-linux64
|
* bin-linux64
|
||||||
* bin-mac64
|
* bin-mac64
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
const WritableBuffer = require('./writable-buffer');
|
||||||
|
|
||||||
|
|
||||||
|
const protocols = { http, https };
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = url => new Promise((res, rej) => {
|
||||||
|
|
||||||
|
url = url.toLowerCase();
|
||||||
|
|
||||||
|
const stream = new WritableBuffer();
|
||||||
|
const proto = protocols[url.match(/^https?/)[0]];
|
||||||
|
|
||||||
|
proto.get(url, response => {
|
||||||
|
|
||||||
|
response.pipe(stream);
|
||||||
|
|
||||||
|
response.on('end', () => res(stream.get()));
|
||||||
|
response.on('error', err => rej(err));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,116 +0,0 @@
|
||||||
{
|
|
||||||
"root": true,
|
|
||||||
"env": {
|
|
||||||
"node" : true,
|
|
||||||
"es6" : true,
|
|
||||||
"mocha" : true
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"expect" : true,
|
|
||||||
"chai" : true,
|
|
||||||
"sinon" : true
|
|
||||||
},
|
|
||||||
"extends": ["eslint:recommended"],
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 8,
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"experimentalObjectRestSpread": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"arrow-parens": ["error", "as-needed"],
|
|
||||||
"no-trailing-spaces": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"skipBlankLines": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"indent": [
|
|
||||||
"error",
|
|
||||||
"tab",
|
|
||||||
{
|
|
||||||
"SwitchCase": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"linebreak-style": [
|
|
||||||
"error",
|
|
||||||
"unix"
|
|
||||||
],
|
|
||||||
"max-len": ["error", 110],
|
|
||||||
"quotes": [
|
|
||||||
"error",
|
|
||||||
"single"
|
|
||||||
],
|
|
||||||
"semi": [
|
|
||||||
"error",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"no-multiple-empty-lines": ["error", { "max": 3, "maxEOF": 1, "maxBOF": 1 }],
|
|
||||||
"keyword-spacing": ["error", { "before": true, "after": true }],
|
|
||||||
"space-before-blocks": ["error"],
|
|
||||||
"space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
|
|
||||||
"space-infix-ops": ["error"],
|
|
||||||
"space-unary-ops": [
|
|
||||||
"error", {
|
|
||||||
"words": true,
|
|
||||||
"nonwords": false,
|
|
||||||
"overrides": {
|
|
||||||
"!": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"spaced-comment": [0],
|
|
||||||
"camelcase": ["error"],
|
|
||||||
"no-tabs": [0],
|
|
||||||
"comma-dangle": [0],
|
|
||||||
"global-require": [0],
|
|
||||||
"func-names": [0],
|
|
||||||
"no-param-reassign": [0],
|
|
||||||
"no-underscore-dangle": [0],
|
|
||||||
"no-restricted-syntax": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"selector": "LabeledStatement",
|
|
||||||
"message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "WithStatement",
|
|
||||||
"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-mixed-operators": [0],
|
|
||||||
"no-plusplus": [0],
|
|
||||||
"comma-spacing": [0],
|
|
||||||
"default-case": [0],
|
|
||||||
"no-shadow": [0],
|
|
||||||
"no-console": [0],
|
|
||||||
"key-spacing": [0],
|
|
||||||
"no-return-assign": [0],
|
|
||||||
"consistent-return": [0],
|
|
||||||
"class-methods-use-this": [0],
|
|
||||||
"no-multi-spaces": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"exceptions": {
|
|
||||||
"VariableDeclarator": true,
|
|
||||||
"Property": true,
|
|
||||||
"ImportDeclaration": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"array-callback-return": [0],
|
|
||||||
"no-use-before-define": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"functions": false,
|
|
||||||
"classes": true,
|
|
||||||
"variables": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"padded-blocks": [0],
|
|
||||||
"space-in-parens": [0],
|
|
||||||
"valid-jsdoc": [0],
|
|
||||||
"no-unused-expressions": [0],
|
|
||||||
"import/no-dynamic-require": [0]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
.idea
|
|
||||||
.cproject
|
|
||||||
.project
|
|
||||||
.lock-wscript
|
|
||||||
build*/
|
|
||||||
bin-*/
|
|
||||||
.DS_Store
|
|
||||||
Debug/
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
binary/
|
|
||||||
*.log
|
|
|
@ -1,16 +0,0 @@
|
||||||
*.log
|
|
||||||
.cproject
|
|
||||||
.eslintrc
|
|
||||||
.gitignore
|
|
||||||
.idea
|
|
||||||
.lock-wscript
|
|
||||||
.project
|
|
||||||
binary/
|
|
||||||
bin-*/
|
|
||||||
build*/
|
|
||||||
CPPLINT.cfg
|
|
||||||
Debug/
|
|
||||||
examples/
|
|
||||||
package-lock.json
|
|
||||||
test/
|
|
||||||
qt/
|
|
|
@ -1,15 +0,0 @@
|
||||||
set noparent
|
|
||||||
linelength=110
|
|
||||||
filter=-legal/copyright
|
|
||||||
filter=-build/include_order
|
|
||||||
filter=-build/header_guard
|
|
||||||
filter=-build/namespaces
|
|
||||||
filter=-build/include_what_you_use
|
|
||||||
filter=-whitespace/blank_line
|
|
||||||
filter=-whitespace/comments
|
|
||||||
filter=-whitespace/tab
|
|
||||||
filter=-whitespace/end_of_line
|
|
||||||
filter=-whitespace/indent
|
|
||||||
filter=-whitespace/operators
|
|
||||||
filter=-whitespace/parens
|
|
||||||
filter=-readability/todo
|
|
|
@ -1,91 +0,0 @@
|
||||||
{
|
|
||||||
'variables': {
|
|
||||||
'rm' : '<!(node -e "require(\'addon-tools-raub\').rm()")',
|
|
||||||
'cp' : '<!(node -e "require(\'addon-tools-raub\').cp()")',
|
|
||||||
'mkdir' : '<!(node -e "require(\'addon-tools-raub\').mkdir()")',
|
|
||||||
'binary' : '<!(node -e "require(\'addon-tools-raub\').bin()")',
|
|
||||||
},
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'addon',
|
|
||||||
'sources': [
|
|
||||||
'cpp/bindings.cpp',
|
|
||||||
'cpp/example.cpp',
|
|
||||||
],
|
|
||||||
'include_dirs': [
|
|
||||||
'<!@(node -e "require(\'addon-tools-raub\').include()")',
|
|
||||||
],
|
|
||||||
'conditions' : [
|
|
||||||
[
|
|
||||||
'OS=="win"',
|
|
||||||
{
|
|
||||||
'msvs_settings' : {
|
|
||||||
'VCCLCompilerTool' : {
|
|
||||||
'AdditionalOptions' : [
|
|
||||||
'/O2','/Oy', # Comment this for debugging
|
|
||||||
# '/Z7', # Unomment this for debugging
|
|
||||||
'/GL','/GF','/Gm-', '/Fm-',
|
|
||||||
'/EHsc','/MT','/GS','/Gy','/GR-','/Gd',
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'VCLinkerTool' : {
|
|
||||||
'AdditionalOptions' : ['/RELEASE','/OPT:REF','/OPT:ICF','/LTCG']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'target_name' : 'make_directory',
|
|
||||||
'type' : 'none',
|
|
||||||
'dependencies' : ['addon'],
|
|
||||||
'actions' : [{
|
|
||||||
'action_name' : 'Directory created.',
|
|
||||||
'inputs' : [],
|
|
||||||
'outputs' : ['build'],
|
|
||||||
'action': ['<(mkdir)', '-p', '<(binary)']
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'target_name' : 'copy_binary',
|
|
||||||
'type' : 'none',
|
|
||||||
'dependencies' : ['make_directory'],
|
|
||||||
'actions' : [{
|
|
||||||
'action_name' : 'Module copied.',
|
|
||||||
'inputs' : [],
|
|
||||||
'outputs' : ['binary'],
|
|
||||||
'action' : ['<(cp)', 'build/Release/addon.node', '<(binary)/addon.node'],
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'target_name' : 'remove_extras',
|
|
||||||
'type' : 'none',
|
|
||||||
'dependencies' : ['copy_binary'],
|
|
||||||
'actions' : [{
|
|
||||||
'action_name' : 'Build intermediates removed.',
|
|
||||||
'inputs' : [],
|
|
||||||
'outputs' : ['cpp'],
|
|
||||||
'conditions' : [
|
|
||||||
[ 'OS=="linux"', { 'action' : [
|
|
||||||
'rm',
|
|
||||||
'<(module_root_dir)/build/Release/obj.target/addon/cpp/bindings.o',
|
|
||||||
'<(module_root_dir)/build/Release/obj.target/addon/cpp/example.o',
|
|
||||||
'<(module_root_dir)/build/Release/addon.node'
|
|
||||||
] } ],
|
|
||||||
[ 'OS=="mac"', { 'action' : [
|
|
||||||
'rm',
|
|
||||||
'<(module_root_dir)/build/Release/obj.target/addon/cpp/bindings.o',
|
|
||||||
'<(module_root_dir)/build/Release/obj.target/addon/cpp/example.o',
|
|
||||||
'<(module_root_dir)/build/Release/addon.node'
|
|
||||||
] } ],
|
|
||||||
[ 'OS=="win"', { 'action' : [
|
|
||||||
'<(rm)',
|
|
||||||
'<(module_root_dir)/build/Release/addon.*',
|
|
||||||
'<(module_root_dir)/build/Release/obj/addon/*.*'
|
|
||||||
] } ],
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const util = require('util');
|
|
||||||
|
|
||||||
const { binPath } = require('addon-tools-raub');
|
|
||||||
|
|
||||||
const core = require(`./${binPath}/addon`);
|
|
||||||
|
|
||||||
|
|
||||||
const { Example } = core;
|
|
||||||
|
|
||||||
Example.prototype[util.inspect.custom] = function () {
|
|
||||||
return `Example { listeners: [${this.eventNames()}] }`;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = core;
|
|
|
@ -1,23 +0,0 @@
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <event-emitter.hpp>
|
|
||||||
|
|
||||||
#include "example.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
|
|
||||||
void init(V8_VAR_OBJ target) {
|
|
||||||
|
|
||||||
EventEmitter::init(target);
|
|
||||||
|
|
||||||
Example::init(target);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NODE_MODULE(example, init);
|
|
||||||
|
|
||||||
|
|
||||||
} // extern "C"
|
|
|
@ -1,105 +0,0 @@
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include "example.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
using namespace v8;
|
|
||||||
using namespace node;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
// ------ Aux macros
|
|
||||||
|
|
||||||
#define THIS_EXAMPLE \
|
|
||||||
Example *example = ObjectWrap::Unwrap<Example>(info.This());
|
|
||||||
|
|
||||||
#define THIS_CHECK \
|
|
||||||
if (example->_isDestroyed) return;
|
|
||||||
|
|
||||||
|
|
||||||
// ------ Constructor and Destructor
|
|
||||||
|
|
||||||
Example::Example() : EventEmitter() {
|
|
||||||
|
|
||||||
_isDestroyed = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Example::~Example() {
|
|
||||||
|
|
||||||
_destroy();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NAN_METHOD(Example::cppOn) { THIS_EXAMPLE; THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_STR_ARG(0, name);
|
|
||||||
REQ_FUN_ARG(1, cb);
|
|
||||||
|
|
||||||
example->on(*name, cb);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------ System methods and props for ObjectWrap
|
|
||||||
|
|
||||||
V8_STORE_FT Example::_protoExample;
|
|
||||||
V8_STORE_FUNC Example::_ctorExample;
|
|
||||||
|
|
||||||
|
|
||||||
void Example::init(V8_VAR_OBJ target) {
|
|
||||||
|
|
||||||
V8_VAR_FT proto = Nan::New<FunctionTemplate>(newCtor);
|
|
||||||
|
|
||||||
// class AudioBufferSourceNode inherits AudioScheduledSourceNode
|
|
||||||
V8_VAR_FT parent = Nan::New(EventEmitter::_protoEventEmitter);
|
|
||||||
proto->Inherit(parent);
|
|
||||||
|
|
||||||
proto->InstanceTemplate()->SetInternalFieldCount(1);
|
|
||||||
proto->SetClassName(JS_STR("Example"));
|
|
||||||
|
|
||||||
// -------- dynamic
|
|
||||||
Nan::SetPrototypeMethod(proto, "destroy", destroy);
|
|
||||||
Nan::SetPrototypeMethod(proto, "cppOn", cppOn);
|
|
||||||
|
|
||||||
// -------- static
|
|
||||||
V8_VAR_FUNC ctor = Nan::GetFunction(proto).ToLocalChecked();
|
|
||||||
|
|
||||||
_protoExample.Reset(proto);
|
|
||||||
_ctorExample.Reset(ctor);
|
|
||||||
|
|
||||||
Nan::Set(target, JS_STR("Example"), ctor);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NAN_METHOD(Example::newCtor) {
|
|
||||||
|
|
||||||
CTOR_CHECK("EventEmitter");
|
|
||||||
|
|
||||||
Example *example = new Example();
|
|
||||||
example->Wrap(info.This());
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Example::_destroy() { DES_CHECK;
|
|
||||||
|
|
||||||
_isDestroyed = true;
|
|
||||||
|
|
||||||
EventEmitter::_destroy();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NAN_METHOD(Example::destroy) { THIS_EXAMPLE; THIS_CHECK;
|
|
||||||
|
|
||||||
example->emit("destroy");
|
|
||||||
|
|
||||||
example->_destroy();
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
#ifndef _EXAMPLE_HPP_
|
|
||||||
#define _EXAMPLE_HPP_
|
|
||||||
|
|
||||||
|
|
||||||
#include <event-emitter.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
class Example : public EventEmitter {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
~Example();
|
|
||||||
|
|
||||||
static void init(V8_VAR_OBJ target);
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Example();
|
|
||||||
|
|
||||||
void _destroy();
|
|
||||||
|
|
||||||
static V8_STORE_FT _protoExample;
|
|
||||||
static V8_STORE_FUNC _ctorExample;
|
|
||||||
|
|
||||||
bool _isDestroyed;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
static NAN_METHOD(newCtor);
|
|
||||||
static NAN_METHOD(destroy);
|
|
||||||
|
|
||||||
static NAN_METHOD(cppOn);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _EXAMPLE_HPP_
|
|
|
@ -1,65 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const { Example, EventEmitter } = require('./core');
|
|
||||||
|
|
||||||
console.log('Example', Example);
|
|
||||||
|
|
||||||
|
|
||||||
const example = new Example();
|
|
||||||
|
|
||||||
console.log('example 0', example, 'instanceof EventEmitter', example instanceof EventEmitter);
|
|
||||||
|
|
||||||
console.log('static listenerCount', EventEmitter.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.eventNames());
|
|
||||||
});
|
|
||||||
|
|
||||||
example.once('evt2', (arg1, arg2) => {
|
|
||||||
console.log('EVT2', arg1, arg2, example.eventNames());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
example.emit('evt1', 111, '221');
|
|
||||||
example.emit('evt1', 112, '222');
|
|
||||||
|
|
||||||
console.log('example.eventNames 1', example.eventNames());
|
|
||||||
|
|
||||||
example.emit('evt2', 111, '221');
|
|
||||||
|
|
||||||
console.log('example.eventNames 2', example.eventNames());
|
|
||||||
|
|
||||||
example.emit('evt2', 112, '222');
|
|
||||||
|
|
||||||
|
|
||||||
console.log('example 1', example);
|
|
||||||
|
|
||||||
|
|
||||||
example.setMaxListeners(2);
|
|
||||||
example.on('max1', () => {});
|
|
||||||
example.on('max1', () => {});
|
|
||||||
example.on('max1', () => {});
|
|
||||||
|
|
||||||
example.on('cpp-on', (arg1, arg2) => {
|
|
||||||
console.log('CPP_ON', arg1, arg2, example.eventNames());
|
|
||||||
});
|
|
||||||
example.emit('cpp-on', 555, 'abc');
|
|
||||||
|
|
||||||
module.exports = Example;
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"name": "example",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"main": "index.js",
|
|
||||||
"dependencies": {
|
|
||||||
"addon-tools-raub": "https://github.com/node-3d/addon-tools-raub.git"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
node_modules
|
|
||||||
*.log
|
|
||||||
build*
|
|
||||||
.DS_Store
|
|
||||||
*.pro.user
|
|
||||||
*.exp
|
|
||||||
*.pdb
|
|
||||||
*.ilk
|
|
||||||
package-lock.json
|
|
|
@ -1,11 +0,0 @@
|
||||||
node_modules
|
|
||||||
*.log
|
|
||||||
build*
|
|
||||||
.DS_Store
|
|
||||||
*.pro.user
|
|
||||||
*.exp
|
|
||||||
*.pdb
|
|
||||||
*.ilk
|
|
||||||
.gitignore
|
|
||||||
package-lock.json
|
|
||||||
test
|
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
'variables': {
|
|
||||||
'rm' : '<!(node -e "require(\'addon-tools-raub\').rm()")',
|
|
||||||
'rem' : '<!(node -e "require(\'.\').rem()")',
|
|
||||||
'XALL%': 'false',
|
|
||||||
},
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name' : 'remove_extras',
|
|
||||||
'type' : 'none',
|
|
||||||
'conditions' : [['XALL=="false"', {'actions': [
|
|
||||||
{
|
|
||||||
'action_name' : 'Unnecessary binaries removed.',
|
|
||||||
'inputs' : [],
|
|
||||||
'outputs' : ['build'],
|
|
||||||
'action' : ['<(rm)', '-rf', '<@(rem)'],
|
|
||||||
}
|
|
||||||
]}]],
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports = require('addon-tools-raub').paths(__dirname);
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"name": "example",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"main": "index.js",
|
|
||||||
"dependencies": {
|
|
||||||
"addon-tools-raub": "https://github.com/node-3d/addon-tools-raub.git"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,251 +2,315 @@
|
||||||
#define _ADDON_TOOLS_HPP_
|
#define _ADDON_TOOLS_HPP_
|
||||||
|
|
||||||
|
|
||||||
#include <nan.h>
|
#include <napi.h>
|
||||||
|
|
||||||
|
|
||||||
#define NAN_HS Nan::HandleScope scope;
|
#define NAPI_ENV Napi::Env env = info.Env();
|
||||||
|
#define NAPI_HS Napi::HandleScope scope(env);
|
||||||
|
|
||||||
|
|
||||||
#define RET_VALUE(VAL) info.GetReturnValue().Set(VAL);
|
#define JS_STR(val) Napi::String::New(env, val)
|
||||||
#define RET_UNDEFINED RET_VALUE(Nan::Undefined());
|
#define JS_NUM(val) Napi::Number::New(env, static_cast<double>(val))
|
||||||
|
#define JS_EXT(val) Napi::External::New(env, reinterpret_cast<void*>(val))
|
||||||
|
#define JS_BOOL(val) Napi::Boolean::New(env, val)
|
||||||
|
#define JS_FUN(val) Napi::Function::Function(env, val)
|
||||||
|
#define JS_OBJ(val) Napi::Object::Object(env, val)
|
||||||
|
|
||||||
|
|
||||||
typedef v8::Local<v8::Value> V8_VAR_VAL;
|
#define RET_VALUE(VAL) return VAL;
|
||||||
typedef v8::Local<v8::Object> V8_VAR_OBJ;
|
#define RET_UNDEFINED RET_VALUE(env.Undefined())
|
||||||
typedef v8::Local<v8::Array> V8_VAR_ARR;
|
#define RET_NULL RET_VALUE(env.Null())
|
||||||
typedef v8::Local<v8::ArrayBufferView> V8_VAR_ABV;
|
#define RET_STR(val) RET_VALUE(JS_STR(val))
|
||||||
typedef v8::Local<v8::String> V8_VAR_STR;
|
|
||||||
typedef v8::Local<v8::Function> V8_VAR_FUNC;
|
|
||||||
typedef v8::Local<v8::External> V8_VAR_EXT;
|
|
||||||
typedef v8::Local<v8::FunctionTemplate> V8_VAR_FT;
|
|
||||||
typedef v8::Local<v8::ObjectTemplate> V8_VAR_OT;
|
|
||||||
|
|
||||||
typedef Nan::Persistent<v8::FunctionTemplate> V8_STORE_FT;
|
|
||||||
typedef Nan::Persistent<v8::Function> V8_STORE_FUNC;
|
|
||||||
typedef Nan::Persistent<v8::Object> V8_STORE_OBJ;
|
|
||||||
typedef Nan::Persistent<v8::Value> V8_STORE_VAL;
|
|
||||||
|
|
||||||
|
|
||||||
#define JS_STR(...) Nan::New<v8::String>(__VA_ARGS__).ToLocalChecked()
|
|
||||||
#define JS_UTF8(...) Nan::New<v8::String>(__VA_ARGS__).ToLocalChecked()
|
|
||||||
#define JS_INT(val) Nan::New<v8::Integer>(val)
|
|
||||||
#define JS_INT32(val) Nan::New<v8::Integer>(val)
|
|
||||||
#define JS_UINT32(val) Nan::New<v8::Integer>(val)
|
|
||||||
#define JS_NUM(val) Nan::New<v8::Number>(val)
|
|
||||||
#define JS_OFFS(val) Nan::New<v8::Number>(static_cast<double>(val))
|
|
||||||
#define JS_FLOAT(val) Nan::New<v8::Number>(val)
|
|
||||||
#define JS_DOUBLE(val) Nan::New<v8::Number>(val)
|
|
||||||
#define JS_EXT(val) Nan::New<v8::External>(reinterpret_cast<void*>(val))
|
|
||||||
#define JS_BOOL(val) (val) ? Nan::True() : Nan::False()
|
|
||||||
#define JS_FUN(val) Nan::New<v8::Function>(val)
|
|
||||||
#define JS_OBJ(val) Nan::New<v8::Object>(val)
|
|
||||||
|
|
||||||
|
|
||||||
#define RET_STR(...) RET_VALUE(JS_STR(__VA_ARGS__))
|
|
||||||
#define RET_UTF8(...) RET_VALUE(JS_UTF8(__VA_ARGS__))
|
|
||||||
#define RET_INT(val) RET_VALUE(JS_INT(val))
|
|
||||||
#define RET_INT32(val) RET_VALUE(JS_INT32(val))
|
|
||||||
#define RET_UINT32(val) RET_VALUE(JS_UINT32(val))
|
|
||||||
#define RET_NUM(val) RET_VALUE(JS_NUM(val))
|
#define RET_NUM(val) RET_VALUE(JS_NUM(val))
|
||||||
#define RET_OFFS(val) RET_VALUE(JS_OFFS(val))
|
|
||||||
#define RET_FLOAT(val) RET_VALUE(JS_FLOAT(val))
|
|
||||||
#define RET_DOUBLE(val) RET_VALUE(JS_DOUBLE(val))
|
|
||||||
#define RET_EXT(val) RET_VALUE(JS_EXT(val))
|
#define RET_EXT(val) RET_VALUE(JS_EXT(val))
|
||||||
#define RET_BOOL(val) RET_VALUE(JS_BOOL(val))
|
#define RET_BOOL(val) RET_VALUE(JS_BOOL(val))
|
||||||
#define RET_FUN(val) RET_VALUE(JS_FUN(val))
|
#define RET_FUN(val) RET_VALUE(JS_FUN(val))
|
||||||
#define RET_OBJ(val) RET_VALUE(JS_OBJ(val))
|
#define RET_OBJ(val) RET_VALUE(JS_OBJ(val))
|
||||||
|
|
||||||
|
|
||||||
|
#define JS_THROW(val) \
|
||||||
|
Napi::Error::New(env, val).ThrowAsJavaScriptException();
|
||||||
|
|
||||||
|
|
||||||
#define REQ_ARGS(N) \
|
#define REQ_ARGS(N) \
|
||||||
if (info.Length() < (N)) \
|
if (info.Length() < (N)) { \
|
||||||
return Nan::ThrowTypeError("Expected at least " #N " arguments");
|
JS_THROW("Expected at least " #N " arguments"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define IS_ARG_EMPTY(I) (info[I]->IsNull() || info[I]->IsUndefined())
|
#define IS_EMPTY(val) (val.IsNull() || val.IsUndefined())
|
||||||
|
#define IS_ARG_EMPTY(I) IS_EMPTY(info[I])
|
||||||
|
|
||||||
|
|
||||||
#define CHECK_REQ_ARG(I, C, T) \
|
#define CHECK_REQ_ARG(I, C, T) \
|
||||||
if (info.Length() <= (I) || ! info[I]->C) \
|
if (info.Length() <= (I) || ! info[I].C) { \
|
||||||
return Nan::ThrowTypeError("Argument " #I " must be " T);
|
JS_THROW("Argument " #I " must be of type `" T "`"); \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_LET_ARG(I, C, T) \
|
#define CHECK_LET_ARG(I, C, T) \
|
||||||
if ( ! (IS_ARG_EMPTY(I) || info[I]->C) ) \
|
if ( ! (IS_ARG_EMPTY(I) || info[I].C) ) { \
|
||||||
return Nan::ThrowTypeError("Argument " #I " must be " T " or null");
|
JS_THROW( \
|
||||||
|
"Argument " #I \
|
||||||
|
" must be of type `" T \
|
||||||
|
"` or be `null`/`undefined`" \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define REQ_UTF8_ARG(I, VAR) \
|
#define REQ_STR_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsString(), "string"); \
|
CHECK_REQ_ARG(I, IsString(), "String"); \
|
||||||
Nan::Utf8String VAR(info[I]);
|
std::string VAR = info[I].ToString().Utf8Value();
|
||||||
|
|
||||||
#define LET_UTF8_ARG(I, VAR) \
|
#define USE_STR_ARG(I, VAR, DEF) \
|
||||||
CHECK_LET_ARG(I, IsString(), "string"); \
|
CHECK_LET_ARG(I, IsString(), "String"); \
|
||||||
Nan::Utf8String VAR(JS_STR(""));
|
std::string VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].ToString().Utf8Value();
|
||||||
|
|
||||||
|
#define LET_STR_ARG(I, VAR) USE_STR_ARG(I, VAR, "")
|
||||||
|
|
||||||
#define REQ_STR_ARG(I, VAR) REQ_UTF8_ARG(I, VAR)
|
|
||||||
#define LET_STR_ARG(I, VAR) LET_UTF8_ARG(I, VAR)
|
|
||||||
|
|
||||||
#define REQ_INT32_ARG(I, VAR) \
|
#define REQ_INT32_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsInt32(), "int32"); \
|
CHECK_REQ_ARG(I, IsNumber(), "Int32"); \
|
||||||
int VAR = info[I].As<v8::Int32>()->Value();
|
int VAR = info[I].ToNumber().Int32Value();
|
||||||
|
|
||||||
|
#define USE_INT32_ARG(I, VAR, DEF) \
|
||||||
|
CHECK_LET_ARG(I, IsNumber(), "Int32"); \
|
||||||
|
int VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].Int32Value();
|
||||||
|
|
||||||
|
#define LET_INT32_ARG(I, VAR) USE_INT32_ARG(I, VAR, 0)
|
||||||
|
|
||||||
|
#define REQ_INT_ARG(I, VAR) REQ_INT32_ARG(I, VAR)
|
||||||
|
#define USE_INT_ARG(I, VAR, DEF) USE_INT32_ARG(I, VAR, DEF)
|
||||||
|
#define LET_INT_ARG(I, VAR) LET_INT32_ARG(I, VAR)
|
||||||
|
|
||||||
#define LET_INT32_ARG(I, VAR) \
|
|
||||||
CHECK_LET_ARG(I, IsInt32(), "int32"); \
|
|
||||||
int VAR = IS_ARG_EMPTY(I) ? 0 : info[I].As<v8::Int32>()->Value();
|
|
||||||
|
|
||||||
#define REQ_UINT32_ARG(I, VAR) \
|
#define REQ_UINT32_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsUint32(), "uint32"); \
|
CHECK_REQ_ARG(I, IsNumber(), "Uint32"); \
|
||||||
unsigned int VAR = info[I].As<v8::Uint32>()->Value();
|
unsigned int VAR = info[I].ToNumber().Uint32Value();
|
||||||
|
|
||||||
#define LET_UINT32_ARG(I, VAR) \
|
#define USE_UINT32_ARG(I, VAR, DEF) \
|
||||||
CHECK_LET_ARG(I, IsUint32(), "uint32"); \
|
CHECK_LET_ARG(I, IsNumber(), "Uint32"); \
|
||||||
unsigned int VAR = IS_ARG_EMPTY(I) ? 0 : info[I].As<v8::Uint32>()->Value();
|
unsigned int VAR = IS_ARG_EMPTY(I) \
|
||||||
|
? (DEF) \
|
||||||
|
: info[I].ToNumber().Uint32Value();
|
||||||
|
|
||||||
|
#define LET_UINT32_ARG(I, VAR) USE_UINT32_ARG(I, VAR, 0)
|
||||||
|
|
||||||
|
#define REQ_UINT_ARG(I, VAR) REQ_UINT_ARG(I, VAR)
|
||||||
|
#define USE_UINT_ARG(I, VAR, DEF) USE_UINT32_ARG(I, VAR, DEF)
|
||||||
|
#define LET_UINT_ARG(I, VAR) LET_UINT32_ARG(I, VAR)
|
||||||
|
|
||||||
#define REQ_INT_ARG(I, VAR) LET_INT32_ARG(I, VAR)
|
|
||||||
#define LET_INT_ARG(I, VAR) REQ_UINT32_ARG(I, VAR)
|
|
||||||
|
|
||||||
#define REQ_BOOL_ARG(I, VAR) \
|
#define REQ_BOOL_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsBoolean(), "bool"); \
|
CHECK_REQ_ARG(I, IsBoolean(), "Bool"); \
|
||||||
bool VAR = info[I].As<v8::Boolean>()->Value();
|
bool VAR = info[I].ToBoolean().Value();
|
||||||
|
|
||||||
|
#define USE_BOOL_ARG(I, VAR, DEF) \
|
||||||
|
CHECK_LET_ARG(I, IsBoolean(), "Bool"); \
|
||||||
|
bool VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].ToBoolean().Value();
|
||||||
|
|
||||||
|
#define LET_BOOL_ARG(I, VAR) USE_BOOL_ARG(I, VAR, false)
|
||||||
|
|
||||||
#define LET_BOOL_ARG(I, VAR) \
|
|
||||||
CHECK_LET_ARG(I, IsBoolean(), "bool"); \
|
|
||||||
bool VAR = IS_ARG_EMPTY(I) ? false : info[I].As<v8::Boolean>()->Value();
|
|
||||||
|
|
||||||
#define REQ_OFFS_ARG(I, VAR) \
|
#define REQ_OFFS_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsNumber(), "number"); \
|
CHECK_REQ_ARG(I, IsNumber(), "Number"); \
|
||||||
size_t VAR = static_cast<size_t>(info[I].As<v8::Integer>()->Value());
|
size_t VAR = static_cast<size_t>(info[I].ToNumber().DoubleValue());
|
||||||
|
|
||||||
#define LET_OFFS_ARG(I, VAR) \
|
#define USE_OFFS_ARG(I, VAR, DEF) \
|
||||||
CHECK_LET_ARG(I, IsNumber(), "number"); \
|
CHECK_LET_ARG(I, IsNumber(), "Number"); \
|
||||||
size_t VAR = IS_ARG_EMPTY(I) ? 0 : static_cast<size_t>( \
|
size_t VAR = IS_ARG_EMPTY(I) \
|
||||||
info[I].As<v8::Integer>()->Value() \
|
? (DEF) \
|
||||||
);
|
: static_cast<size_t>(info[I].ToNumber().DoubleValue());
|
||||||
|
|
||||||
|
#define LET_OFFS_ARG(I, VAR) USE_OFFS_ARG(I, VAR, 0)
|
||||||
|
|
||||||
|
|
||||||
#define REQ_DOUBLE_ARG(I, VAR) \
|
#define REQ_DOUBLE_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsNumber(), "number"); \
|
CHECK_REQ_ARG(I, IsNumber(), "Number"); \
|
||||||
double VAR = info[I].As<v8::Number>()->Value();
|
double VAR = info[I].ToNumber().DoubleValue();
|
||||||
|
|
||||||
#define LET_DOUBLE_ARG(I, VAR) \
|
#define USE_DOUBLE_ARG(I, VAR, DEF) \
|
||||||
CHECK_LET_ARG(I, IsNumber(), "number"); \
|
CHECK_LET_ARG(I, IsNumber(), "Number"); \
|
||||||
double VAR = IS_ARG_EMPTY(I) ? 0.0 : info[I].As<v8::Number>()->Value();
|
double VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].ToNumber().DoubleValue();
|
||||||
|
|
||||||
|
#define LET_DOUBLE_ARG(I, VAR) USE_DOUBLE_ARG(I, VAR, 0.0)
|
||||||
|
|
||||||
|
|
||||||
#define REQ_FLOAT_ARG(I, VAR) \
|
#define REQ_FLOAT_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsNumber(), "number"); \
|
CHECK_REQ_ARG(I, IsNumber(), "Number"); \
|
||||||
float VAR = static_cast<float>(info[I].As<v8::Number>()->Value());
|
float VAR = info[I].ToNumber().FloatValue();
|
||||||
|
|
||||||
#define LET_FLOAT_ARG(I, VAR) \
|
#define USE_FLOAT_ARG(I, VAR, DEF) \
|
||||||
CHECK_LET_ARG(I, IsNumber(), "number"); \
|
CHECK_LET_ARG(I, IsNumber(), "Number"); \
|
||||||
float VAR = IS_ARG_EMPTY(I) ? 0.f : static_cast<float>( \
|
float VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].ToNumber().FloatValue();
|
||||||
info[I].As<v8::Number>()->Value() \
|
|
||||||
);
|
#define LET_FLOAT_ARG(I, VAR) USE_FLOAT_ARG(I, VAR, 0.f)
|
||||||
|
|
||||||
|
|
||||||
#define REQ_EXT_ARG(I, VAR) \
|
#define REQ_EXT_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsExternal(), "void*"); \
|
CHECK_REQ_ARG(I, IsExternal(), "Pointer"); \
|
||||||
V8_VAR_EXT VAR = V8_VAR_EXT::Cast(info[I]);
|
Napi::External VAR = info[I].As<Napi::External>();
|
||||||
|
|
||||||
#define LET_EXT_ARG(I, VAR) \
|
#define USE_EXT_ARG(I, VAR, DEF) \
|
||||||
CHECK_LET_ARG(I, IsExternal(), "number"); \
|
CHECK_LET_ARG(I, IsExternal(), "Pointer"); \
|
||||||
V8_VAR_EXT VAR = IS_ARG_EMPTY(I) ? JS_EXT(nullptr) : V8_VAR_EXT::Cast(info[I]);
|
Napi::External VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].As<Napi::External>();
|
||||||
|
|
||||||
|
#define LET_EXT_ARG(I, VAR) USE_EXT_ARG(I, VAR, JS_EXT(nullptr))
|
||||||
|
|
||||||
|
|
||||||
#define REQ_FUN_ARG(I, VAR) \
|
#define REQ_FUN_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsFunction(), "function"); \
|
CHECK_REQ_ARG(I, IsFunction(), "Function"); \
|
||||||
V8_VAR_FUNC VAR = V8_VAR_FUNC::Cast(info[I]);
|
Napi::Function VAR = info[I].As<Napi::Function>();
|
||||||
|
|
||||||
|
|
||||||
#define REQ_OBJ_ARG(I, VAR) \
|
#define REQ_OBJ_ARG(I, VAR) \
|
||||||
CHECK_REQ_ARG(I, IsObject(), "object"); \
|
CHECK_REQ_ARG(I, IsObject(), "Object"); \
|
||||||
V8_VAR_OBJ VAR = V8_VAR_OBJ::Cast(info[I]);
|
Napi::Object VAR = info[I].As<Napi::Object>();
|
||||||
|
|
||||||
|
#define USE_OBJ_ARG(I, VAR, DEF) \
|
||||||
|
CHECK_LET_ARG(I, IsObject(), "Object"); \
|
||||||
|
Napi::Object VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].As<Napi::Object>();
|
||||||
|
|
||||||
|
#define LET_OBJ_ARG(I, VAR) USE_OBJ_ARG(I, VAR, info[I].As<Napi::Object>())
|
||||||
|
|
||||||
|
|
||||||
|
#define REQ_OBJ_ARG(I, VAR) \
|
||||||
|
CHECK_REQ_ARG(I, IsObject(), "Object"); \
|
||||||
|
Napi::Object VAR = info[I].As<Napi::Object>();
|
||||||
|
|
||||||
|
#define USE_OBJ_ARG(I, VAR, DEF) \
|
||||||
|
CHECK_LET_ARG(I, IsObject(), "Object"); \
|
||||||
|
Napi::Object VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].As<Napi::Object>();
|
||||||
|
|
||||||
|
#define LET_OBJ_ARG(I, VAR) USE_OBJ_ARG(I, VAR, info[I].As<Napi::Object>())
|
||||||
|
|
||||||
|
|
||||||
#define REQ_ARRV_ARG(I, VAR) \
|
#define REQ_ARRV_ARG(I, VAR) \
|
||||||
REQ_OBJ_ARG(I, _obj_##VAR); \
|
CHECK_REQ_ARG(I, IsArrayBuffer(), "Object"); \
|
||||||
if( ! _obj_##VAR->IsArrayBufferView() ) \
|
Napi::ArrayBuffer VAR = info[I].As<Napi::ArrayBuffer>();
|
||||||
return Nan::ThrowTypeError("Argument " #I " must be an array buffer");\
|
|
||||||
V8_VAR_ABV VAR = V8_VAR_ABV::Cast(_obj_##VAR);
|
|
||||||
|
|
||||||
|
|
||||||
#define SET_PROP(OBJ, KEY, VAL) OBJ->Set(JS_STR(KEY), VAL);
|
#define REQ_BUF_ARG(I, VAR) \
|
||||||
#define SET_I(ARR, I, VAL) ARR->Set(I, VAL);
|
CHECK_REQ_ARG(I, IsBuffer(), "Buffer"); \
|
||||||
|
Napi::Buffer<uint8_t> VAR = info[I].As< Napi::Buffer<uint8_t> >();
|
||||||
|
|
||||||
|
|
||||||
#define CTOR_CHECK(T) \
|
#define CTOR_CHECK(T) \
|
||||||
if ( ! info.IsConstructCall() ) \
|
if ( ! info.IsConstructCall() ) \
|
||||||
return Nan::ThrowTypeError(T " must be called with the 'new' keyword.");
|
JS_THROW(T " must be called with the 'new' keyword.");
|
||||||
|
|
||||||
#define DES_CHECK \
|
#define DES_CHECK \
|
||||||
if (_isDestroyed) return;
|
if (_isDestroyed) return;
|
||||||
|
|
||||||
|
#define THIS_CHECK \
|
||||||
|
NAPI_ENV; \
|
||||||
|
if (_isDestroyed) RET_UNDEFINED;
|
||||||
|
|
||||||
#define SETTER_CHECK(C, T) \
|
#define SETTER_CHECK(C, T) \
|
||||||
if ( ! value->C ) \
|
if ( ! value.C ) \
|
||||||
return Nan::ThrowTypeError("Value must be " T);
|
JS_THROW("Value must be " T);
|
||||||
|
|
||||||
|
|
||||||
#define ACCESSOR_RW(OBJ, NAME) \
|
#define JS_METHOD(NAME) Napi::Value NAME(const Napi::CallbackInfo &info)
|
||||||
Nan::SetAccessor(OBJ, JS_STR(#NAME), NAME ## Getter, NAME ## Setter);
|
#define JS_GETTER(NAME) Napi::Value NAME(const Napi::CallbackInfo &info)
|
||||||
|
#define JS_SETTER(NAME) \
|
||||||
|
void NAME(const Napi::CallbackInfo &info, const Napi::Value &value)
|
||||||
|
|
||||||
#define ACCESSOR_R(OBJ, NAME) \
|
#define ACCESSOR_RW(CLASS, NAME) \
|
||||||
Nan::SetAccessor(OBJ, JS_STR(#NAME), NAME ## Getter);
|
InstanceAccessor(#NAME, &CLASS::NAME ## Getter, &CLASS::NAME ## Setter)
|
||||||
|
|
||||||
|
#define ACCESSOR_R(CLASS, NAME) \
|
||||||
|
InstanceAccessor(#NAME, &CLASS::NAME ## Getter, nullptr)
|
||||||
|
|
||||||
|
#define ACCESSOR_M(CLASS, NAME) \
|
||||||
|
InstanceMethod(#NAME, &CLASS::NAME)
|
||||||
|
|
||||||
|
|
||||||
#define SETTER_UTF8_ARG \
|
#define SETTER_STR_ARG \
|
||||||
SETTER_CHECK(IsString(), "string"); \
|
SETTER_CHECK(IsNumber(), "String"); \
|
||||||
Nan::Utf8String v(value);
|
std::string v = value.ToString().Utf8Value();
|
||||||
|
|
||||||
#define SETTER_STR_ARG SETTER_UTF8_ARG
|
|
||||||
|
|
||||||
#define SETTER_INT32_ARG \
|
#define SETTER_INT32_ARG \
|
||||||
SETTER_CHECK(IsInt32(), "int32"); \
|
SETTER_CHECK(IsNumber(), "Int32"); \
|
||||||
int v = value.As<v8::Int32>()->Value();
|
int v = value.ToNumber().Int32Value();
|
||||||
|
|
||||||
#define SETTER_INT_ARG SETTER_INT32_ARG
|
#define SETTER_INT_ARG SETTER_INT32_ARG
|
||||||
|
|
||||||
#define SETTER_BOOL_ARG \
|
#define SETTER_BOOL_ARG \
|
||||||
SETTER_CHECK(IsBoolean(), "bool"); \
|
SETTER_CHECK(IsBoolean(), "Bool"); \
|
||||||
bool v = value.As<v8::Boolean>()->Value();
|
bool v = value.ToBoolean().Value();
|
||||||
|
|
||||||
#define SETTER_UINT32_ARG \
|
#define SETTER_UINT32_ARG \
|
||||||
SETTER_CHECK(IsUint32(), "uint32"); \
|
SETTER_CHECK(IsNumber(), "Uint32"); \
|
||||||
unsigned int v = value.As<v8::Uint32>()->Value();
|
unsigned int v = value.ToNumber().Uint32Value();
|
||||||
|
|
||||||
|
#define SETTER_UINT_ARG SETTER_UINT32_ARG
|
||||||
|
|
||||||
#define SETTER_OFFS_ARG \
|
#define SETTER_OFFS_ARG \
|
||||||
SETTER_CHECK(IsNumber(), "number"); \
|
SETTER_CHECK(IsNumber(), "Number"); \
|
||||||
size_t v = static_cast<size_t>(value.As<v8::Integer>()->Value());
|
size_t v = static_cast<size_t>(value.ToNumber().DoubleValue());
|
||||||
|
|
||||||
#define SETTER_DOUBLE_ARG \
|
#define SETTER_DOUBLE_ARG \
|
||||||
SETTER_CHECK(IsNumber(), "number"); \
|
SETTER_CHECK(IsNumber(), "Number"); \
|
||||||
double v = value.As<v8::Number>()->Value();
|
double v = value.ToNumber().DoubleValue();
|
||||||
|
|
||||||
#define SETTER_FLOAT_ARG \
|
#define SETTER_FLOAT_ARG \
|
||||||
SETTER_CHECK(IsNumber(), "number"); \
|
SETTER_CHECK(IsNumber(), "Number"); \
|
||||||
float v = static_cast<float>(value.As<v8::Number>()->Value());
|
float v = value.ToNumber().FloatValue();
|
||||||
|
|
||||||
#define SETTER_EXT_ARG \
|
#define SETTER_EXT_ARG \
|
||||||
SETTER_CHECK(IsExternal(), "void*"); \
|
SETTER_CHECK(IsExternal(), "Pointer"); \
|
||||||
V8_VAR_EXT v = V8_VAR_EXT::Cast(value);
|
Napi::External v = value.As<Napi::External>();
|
||||||
|
|
||||||
#define SETTER_FUN_ARG \
|
#define SETTER_FUN_ARG \
|
||||||
SETTER_CHECK(IsFunction(), "function"); \
|
SETTER_CHECK(IsFunction(), "Function"); \
|
||||||
V8_VAR_FUNC v = V8_VAR_FUNC::Cast(value);
|
Napi::Function v = value.As<Napi::Function>()
|
||||||
|
|
||||||
#define SETTER_OBJ_ARG \
|
#define SETTER_OBJ_ARG \
|
||||||
SETTER_CHECK(IsObject(), "object"); \
|
SETTER_CHECK(IsObject(), "Object"); \
|
||||||
V8_VAR_OBJ v = V8_VAR_OBJ::Cast(value);
|
Napi::Object v = value.As<Napi::Object>()
|
||||||
|
|
||||||
#define SETTER_ARRV_ARG \
|
#define SETTER_ARRV_ARG \
|
||||||
SETTER_CHECK(IsObject(), "object"); \
|
SETTER_CHECK(IsArrayBuffer(), "TypedArray"); \
|
||||||
V8_VAR_OBJ _obj_v = V8_VAR_OBJ::Cast(value); \
|
Napi::ArrayBuffer v = value.As<Napi::ArrayBuffer>();
|
||||||
if( ! _obj_v->IsArrayBufferView() ) \
|
|
||||||
return Nan::ThrowTypeError("The value must be an array buffer"); \
|
|
||||||
V8_VAR_ABV v = V8_VAR_ABV::Cast(_obj_v);
|
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_AND_THROW_LAST_ERROR() \
|
||||||
|
do { \
|
||||||
|
const napi_extended_error_info *error_info; \
|
||||||
|
napi_get_last_error_info((env), &error_info); \
|
||||||
|
bool is_pending; \
|
||||||
|
napi_is_exception_pending((env), &is_pending); \
|
||||||
|
/* If an exception is already pending, don't rethrow it */ \
|
||||||
|
if (!is_pending) { \
|
||||||
|
const char* error_message = error_info->error_message != NULL \
|
||||||
|
? error_info->error_message \
|
||||||
|
: "empty error message"; \
|
||||||
|
JS_THROW(error_message); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define NAPI_CALL(the_call, ATE) \
|
||||||
|
do { \
|
||||||
|
if ((the_call) != napi_ok) { \
|
||||||
|
GET_AND_THROW_LAST_ERROR(); \
|
||||||
|
ATE; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define JS_RUN_3(code, VAR, ATE) \
|
||||||
|
napi_value __RESULT_ ## VAR; \
|
||||||
|
NAPI_CALL( \
|
||||||
|
napi_run_script(env, napi_value(JS_STR(code)), &__RESULT_ ## VAR), \
|
||||||
|
ATE \
|
||||||
|
); \
|
||||||
|
Napi::Value VAR(env, __RESULT_ ## VAR);
|
||||||
|
|
||||||
|
#define JS_RUN_2(code, VAR) JS_RUN_3(code, VAR, return)
|
||||||
|
#define JS_RUN JS_RUN_3
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
inline Type* getArrayData(V8_VAR_OBJ obj, int *num = nullptr) {
|
inline Type* getArrayData(Napi::Env env, Napi::Object obj, int *num = nullptr) {
|
||||||
|
|
||||||
Type *data = nullptr;
|
Type *data = nullptr;
|
||||||
|
|
||||||
|
@ -254,32 +318,68 @@ inline Type* getArrayData(V8_VAR_OBJ obj, int *num = nullptr) {
|
||||||
*num = 0;
|
*num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! obj->IsArrayBufferView() ) {
|
if ( ! obj.IsArrayBuffer() ) {
|
||||||
Nan::ThrowError("Argument must be a TypedArray.");
|
JS_THROW("Argument must be of type `TypedArray`.");
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
V8_VAR_ABV arr = V8_VAR_ABV::Cast(obj);
|
Napi::ArrayBuffer arr = obj.As<Napi::ArrayBuffer>();
|
||||||
if (num) {
|
if (num) {
|
||||||
*num = arr->ByteLength() / sizeof(Type);
|
*num = arr.ByteLength() / sizeof(Type);
|
||||||
}
|
}
|
||||||
data = reinterpret_cast<Type*>(arr->Buffer()->GetContents().Data());
|
data = static_cast<Type *>(arr.Data());
|
||||||
|
|
||||||
|
return data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
inline Type* getBufferData(Napi::Env env, Napi::Object obj, int *num = nullptr) {
|
||||||
|
|
||||||
|
Type *data = nullptr;
|
||||||
|
|
||||||
|
if (num) {
|
||||||
|
*num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! obj.IsBuffer() ) {
|
||||||
|
JS_THROW("Argument must be of type `Buffer`.");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Buffer<uint8_t> arr = obj.As< Napi::Buffer<uint8_t> >();
|
||||||
|
if (num) {
|
||||||
|
*num = arr.Length() / sizeof(Type);
|
||||||
|
}
|
||||||
|
data = arr.Data();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void *getData(V8_VAR_OBJ obj) {
|
inline void *getData(Napi::Env env, Napi::Object obj) {
|
||||||
|
|
||||||
void *pixels = nullptr;
|
void *pixels = nullptr;
|
||||||
|
|
||||||
if (obj->IsArrayBufferView()) {
|
if (obj.IsArrayBuffer()) {
|
||||||
pixels = getArrayData<unsigned char>(obj);
|
pixels = getArrayData<unsigned char>(env, obj);
|
||||||
} else if (obj->Has(JS_STR("data"))) {
|
} else if (obj.IsTypedArray()) {
|
||||||
V8_VAR_VAL data = Nan::Get(obj, JS_STR("data")).ToLocalChecked();
|
pixels = getArrayData<unsigned char>(
|
||||||
if ( ! data->IsNullOrUndefined() ) {
|
env,
|
||||||
pixels = node::Buffer::Data(data);
|
obj.As<Napi::TypedArray>().ArrayBuffer()
|
||||||
|
);
|
||||||
|
} else if (obj.Has("data")) {
|
||||||
|
Napi::Object data = obj.Get("data").As<Napi::Object>();
|
||||||
|
if (data.IsArrayBuffer()) {
|
||||||
|
pixels = getArrayData<unsigned char>(env, data);
|
||||||
|
} else if (data.IsBuffer()) {
|
||||||
|
pixels = getBufferData<unsigned char>(env, data);
|
||||||
|
} else if (data.IsTypedArray()) {
|
||||||
|
pixels = getArrayData<unsigned char>(
|
||||||
|
env,
|
||||||
|
data.As<Napi::TypedArray>().ArrayBuffer()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,28 +388,49 @@ inline void *getData(V8_VAR_OBJ obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void consoleLog(int argc, V8_VAR_VAL *argv) {
|
inline void consoleLog(Napi::Env env, int argc, Napi::Value *argv) {
|
||||||
|
|
||||||
V8_VAR_STR code = JS_STR("((...args) => console.log(...args))");
|
JS_RUN_2("((...args) => console.log(...args))", log);
|
||||||
|
std::vector<napi_value> args;
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
args.push_back(napi_value(argv[i]));
|
||||||
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> log = v8::Script::Compile(
|
log.As<Napi::Function>().Call(napi_value(env.Null()), args);
|
||||||
Nan::GetCurrentContext(), code
|
|
||||||
).ToLocalChecked()->Run(
|
|
||||||
Nan::GetCurrentContext()
|
|
||||||
).ToLocalChecked();
|
|
||||||
Nan::Callback logCb(Nan::To<v8::Function>(log).ToLocalChecked());
|
|
||||||
|
|
||||||
Nan::AsyncResource async("consoleLog()");
|
|
||||||
|
|
||||||
logCb.Call(argc, argv, &async);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void consoleLog(const std::string &message) {
|
inline void consoleLog(Napi::Env env, const std::string &message) {
|
||||||
|
|
||||||
V8_VAR_VAL arg = JS_STR(message);
|
Napi::Value arg = JS_STR(message);
|
||||||
consoleLog(1, &arg);
|
consoleLog(env, 1, &arg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void eventEmit(
|
||||||
|
Napi::Env env,
|
||||||
|
Napi::Object that,
|
||||||
|
const std::string &name,
|
||||||
|
int argc = 0,
|
||||||
|
Napi::Value *argv = nullptr
|
||||||
|
) {
|
||||||
|
|
||||||
|
if ( ! that.Has("emit") ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::String eventName = JS_STR(name);
|
||||||
|
Napi::Function thatEmit = that.Get("emit").As<Napi::Function>();
|
||||||
|
|
||||||
|
std::vector<napi_value> args;
|
||||||
|
args.push_back(napi_value(eventName));
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
args.push_back(napi_value(argv[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
thatEmit.Call(napi_value(that), args);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,723 +0,0 @@
|
||||||
#ifndef _EVENT_EMITTER_
|
|
||||||
#define _EVENT_EMITTER_
|
|
||||||
|
|
||||||
|
|
||||||
#include <addon-tools.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <deque>
|
|
||||||
|
|
||||||
|
|
||||||
#define THIS_EVENT_EMITTER \
|
|
||||||
EventEmitter *eventEmitter = ObjectWrap::Unwrap<EventEmitter>(info.This());
|
|
||||||
|
|
||||||
#define EVENT_EMITTER_THIS_CHECK \
|
|
||||||
if (eventEmitter->_isDestroyed) return;
|
|
||||||
|
|
||||||
|
|
||||||
// This template class provides static-member initialization in-header
|
|
||||||
template <typename T>
|
|
||||||
class StaticHolder {
|
|
||||||
protected:
|
|
||||||
static V8_STORE_FT _protoEventEmitter;
|
|
||||||
static V8_STORE_FUNC _ctorEventEmitter;
|
|
||||||
};
|
|
||||||
template <typename T> V8_STORE_FT StaticHolder<T>::_protoEventEmitter;
|
|
||||||
template <typename T> V8_STORE_FUNC StaticHolder<T>::_ctorEventEmitter;
|
|
||||||
|
|
||||||
|
|
||||||
class EventEmitter : public StaticHolder<int>, public Nan::ObjectWrap {
|
|
||||||
|
|
||||||
typedef Nan::CopyablePersistentTraits<v8::Function>::CopyablePersistent FN_TYPE;
|
|
||||||
typedef std::deque<FN_TYPE> VEC_TYPE;
|
|
||||||
typedef std::map<std::string, VEC_TYPE> MAP_TYPE;
|
|
||||||
typedef std::map<int, FN_TYPE> FNMAP_TYPE;
|
|
||||||
typedef VEC_TYPE::iterator IT_TYPE;
|
|
||||||
typedef MAP_TYPE::iterator MAP_IT_TYPE;
|
|
||||||
typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Public V8 init
|
|
||||||
static void init(V8_VAR_OBJ target) {
|
|
||||||
|
|
||||||
V8_VAR_FT proto = Nan::New<v8::FunctionTemplate>(newCtor);
|
|
||||||
|
|
||||||
proto->InstanceTemplate()->SetInternalFieldCount(1);
|
|
||||||
proto->SetClassName(JS_STR("EventEmitter"));
|
|
||||||
|
|
||||||
|
|
||||||
// Accessors
|
|
||||||
V8_VAR_OT obj = proto->PrototypeTemplate();
|
|
||||||
ACCESSOR_R(obj, isDestroyed);
|
|
||||||
|
|
||||||
|
|
||||||
// -------- dynamic
|
|
||||||
|
|
||||||
Nan::SetPrototypeMethod(proto, "listenerCount", jsListenerCount);
|
|
||||||
Nan::SetPrototypeMethod(proto, "addEventListener", jsAddListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "addListener", jsAddListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "dispatchEvent", jsDispatchEvent);
|
|
||||||
Nan::SetPrototypeMethod(proto, "emit", jsEmit);
|
|
||||||
Nan::SetPrototypeMethod(proto, "eventNames", jsEventNames);
|
|
||||||
Nan::SetPrototypeMethod(proto, "getMaxListeners", jsGetMaxListeners);
|
|
||||||
Nan::SetPrototypeMethod(proto, "listeners", jsListeners);
|
|
||||||
Nan::SetPrototypeMethod(proto, "off", jsRemoveListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "on", jsAddListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "once", jsAddListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "prependListener", jsPrependListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "prependOnceListener", jsPrependOnceListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "removeAllListeners", jsRemoveAllListeners);
|
|
||||||
Nan::SetPrototypeMethod(proto, "removeEventListener", jsRemoveListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "removeListener", jsRemoveListener);
|
|
||||||
Nan::SetPrototypeMethod(proto, "setMaxListeners", jsSetMaxListeners);
|
|
||||||
Nan::SetPrototypeMethod(proto, "rawListeners", jsRawListeners);
|
|
||||||
|
|
||||||
Nan::SetPrototypeMethod(proto, "destroy", jsDestroy);
|
|
||||||
|
|
||||||
// -------- static
|
|
||||||
|
|
||||||
V8_VAR_FUNC ctor = Nan::GetFunction(proto).ToLocalChecked();
|
|
||||||
|
|
||||||
V8_VAR_OBJ ctorObj = V8_VAR_OBJ::Cast(ctor);
|
|
||||||
|
|
||||||
Nan::SetMethod(ctorObj, "listenerCount", jsStaticListenerCount);
|
|
||||||
|
|
||||||
|
|
||||||
_ctorEventEmitter.Reset(ctor);
|
|
||||||
_protoEventEmitter.Reset(proto);
|
|
||||||
|
|
||||||
Nan::Set(target, JS_STR("EventEmitter"), ctor);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// C++ side emit() method
|
|
||||||
void emit(const std::string &name, int argc = 0, V8_VAR_VAL *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() ) {
|
|
||||||
Nan::AsyncResource async("EventEmitter::cpp_emit()");
|
|
||||||
callback.Call(handle(), argc, argv, &async);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// C++ side on() method
|
|
||||||
void on(const std::string &name, V8_VAR_FUNC cb) {
|
|
||||||
|
|
||||||
V8_VAR_OBJ me = handle();
|
|
||||||
|
|
||||||
V8_VAR_VAL onVal = Nan::Get(me, JS_STR("on")).ToLocalChecked();
|
|
||||||
V8_VAR_FUNC onFunc = V8_VAR_FUNC::Cast(onVal);
|
|
||||||
|
|
||||||
Nan::Callback onCb(onFunc);
|
|
||||||
|
|
||||||
V8_VAR_VAL argv[] = { JS_STR(name.c_str()), cb };
|
|
||||||
Nan::AsyncResource async("EventEmitter::cpp_on()");
|
|
||||||
|
|
||||||
onCb.Call(me, 2, argv, &async);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _destroy() { DES_CHECK;
|
|
||||||
|
|
||||||
_isDestroyed = true;
|
|
||||||
|
|
||||||
_listeners.clear();
|
|
||||||
_raw.clear();
|
|
||||||
_wrappedIds.clear();
|
|
||||||
_rawIds.clear();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
~EventEmitter () { _destroy(); }
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
EventEmitter () {
|
|
||||||
_isDestroyed = false;
|
|
||||||
_maxListeners = 0;
|
|
||||||
_freeId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
static NAN_METHOD(newCtor) {
|
|
||||||
|
|
||||||
CTOR_CHECK("EventEmitter");
|
|
||||||
|
|
||||||
EventEmitter *eventEmitter = new EventEmitter();
|
|
||||||
eventEmitter->Wrap(info.This());
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_GETTER(isDestroyedGetter) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
RET_BOOL(eventEmitter->_isDestroyed);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Deprecated static method
|
|
||||||
static NAN_METHOD(jsStaticListenerCount) {
|
|
||||||
|
|
||||||
REQ_OBJ_ARG(0, obj);
|
|
||||||
EventEmitter *eventEmitter = ObjectWrap::Unwrap<EventEmitter>(obj);
|
|
||||||
REQ_UTF8_ARG(1, name);
|
|
||||||
|
|
||||||
const VEC_TYPE &list = eventEmitter->_listeners[*name];
|
|
||||||
|
|
||||||
RET_INT(static_cast<int>(list.size()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsAddListener) {
|
|
||||||
|
|
||||||
_wrapListener(info);
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsDispatchEvent) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_OBJ_ARG(0, event);
|
|
||||||
|
|
||||||
if ( ! event->Has(JS_STR("type")) ) {
|
|
||||||
return Nan::ThrowError("Event must have the `type` property.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Nan::Utf8String name(event->Get(JS_STR("type")));
|
|
||||||
|
|
||||||
V8_VAR_VAL args = event;
|
|
||||||
|
|
||||||
eventEmitter->emit(*name, 1, &args);
|
|
||||||
|
|
||||||
RET_BOOL(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsEmit) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
|
|
||||||
int length = info.Length();
|
|
||||||
|
|
||||||
std::vector< V8_VAR_VAL > args;
|
|
||||||
|
|
||||||
for (int i = 1; i < length; i++) {
|
|
||||||
args.push_back(info[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
eventEmitter->emit(*name, length - 1, &args[0]);
|
|
||||||
|
|
||||||
if ( eventEmitter->_listeners.find(*name) == eventEmitter->_listeners.end() ) {
|
|
||||||
RET_BOOL(false);
|
|
||||||
} else {
|
|
||||||
RET_BOOL(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsEventNames) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
V8_VAR_ARR jsNames = Nan::New<v8::Array>(eventEmitter->_raw.size());
|
|
||||||
|
|
||||||
if (eventEmitter->_raw.empty()) {
|
|
||||||
RET_VALUE(jsNames);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (MAP_IT_TYPE it = eventEmitter->_raw.begin(); it != eventEmitter->_raw.end(); ++it, i++) {
|
|
||||||
|
|
||||||
jsNames->Set(JS_INT(i), JS_STR(it->first));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
RET_VALUE(jsNames);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsGetMaxListeners) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
RET_INT(eventEmitter->_maxListeners);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsListenerCount) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
|
|
||||||
const VEC_TYPE &list = eventEmitter->_listeners[*name];
|
|
||||||
|
|
||||||
RET_INT(static_cast<int>(list.size()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsListeners) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
|
|
||||||
VEC_TYPE &list = eventEmitter->_listeners[*name];
|
|
||||||
|
|
||||||
V8_VAR_ARR jsListeners = Nan::New<v8::Array>(list.size());
|
|
||||||
|
|
||||||
if (list.empty()) {
|
|
||||||
RET_VALUE(jsListeners);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (IT_TYPE it = list.begin(); it != list.end(); ++it, i++) {
|
|
||||||
|
|
||||||
jsListeners->Set(JS_INT(i), Nan::New(*it));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
RET_VALUE(jsListeners);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void _reportListeners(
|
|
||||||
const std::string &name,
|
|
||||||
int numListeners,
|
|
||||||
int maxListeners
|
|
||||||
) {
|
|
||||||
|
|
||||||
std::string msg = "EventEmitter Warning: too many listeners (";
|
|
||||||
msg += std::to_string(numListeners);
|
|
||||||
msg += " > ";
|
|
||||||
msg += std::to_string(maxListeners);
|
|
||||||
msg += ") on '";
|
|
||||||
msg += name;
|
|
||||||
msg += "' event, possible memory leak.\n";
|
|
||||||
|
|
||||||
// Some JS magic to retrieve the call stack
|
|
||||||
V8_VAR_STR code = JS_STR(
|
|
||||||
"(new Error()).stack.split('\\n').slice(2).join('\\n')"
|
|
||||||
);
|
|
||||||
|
|
||||||
v8::Local<v8::Value> stack = v8::Script::Compile(
|
|
||||||
Nan::GetCurrentContext(), code
|
|
||||||
).ToLocalChecked()->Run(
|
|
||||||
Nan::GetCurrentContext()
|
|
||||||
).ToLocalChecked();
|
|
||||||
Nan::Utf8String stackStr(stack);
|
|
||||||
|
|
||||||
msg += *stackStr;
|
|
||||||
|
|
||||||
consoleLog(msg);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void _addListener(
|
|
||||||
const Nan::FunctionCallbackInfo<v8::Value> &info,
|
|
||||||
const std::string &name,
|
|
||||||
V8_STORE_FUNC *cb,
|
|
||||||
bool isFront
|
|
||||||
) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
V8_VAR_VAL args[] = { info[0], info[1] };
|
|
||||||
eventEmitter->emit("newListener", 2, args);
|
|
||||||
|
|
||||||
if (isFront) {
|
|
||||||
eventEmitter->_listeners[name].push_front(*cb);
|
|
||||||
eventEmitter->_raw[name].push_front(*cb);
|
|
||||||
} else {
|
|
||||||
eventEmitter->_listeners[name].push_back(*cb);
|
|
||||||
eventEmitter->_raw[name].push_back(*cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = eventEmitter->_raw[name].size();
|
|
||||||
|
|
||||||
if (eventEmitter->_maxListeners > 0 && count > eventEmitter->_maxListeners) {
|
|
||||||
|
|
||||||
_reportListeners(name, count, eventEmitter->_maxListeners);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void _wrapListener(
|
|
||||||
const Nan::FunctionCallbackInfo<v8::Value> &info,
|
|
||||||
bool isFront = false
|
|
||||||
) {
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
REQ_FUN_ARG(1, cb);
|
|
||||||
|
|
||||||
V8_STORE_FUNC persistentCb;
|
|
||||||
persistentCb.Reset(cb);
|
|
||||||
|
|
||||||
_addListener(info, *name, &persistentCb, isFront);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void _addOnceListener(
|
|
||||||
const Nan::FunctionCallbackInfo<v8::Value> &info,
|
|
||||||
const std::string &name,
|
|
||||||
V8_STORE_FUNC *raw,
|
|
||||||
V8_STORE_FUNC *cb,
|
|
||||||
bool isFront
|
|
||||||
) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
V8_VAR_VAL args[] = { info[0], info[1] };
|
|
||||||
eventEmitter->emit("newListener", 2, args);
|
|
||||||
|
|
||||||
if (isFront) {
|
|
||||||
eventEmitter->_listeners[name].push_front(*cb);
|
|
||||||
eventEmitter->_raw[name].push_front(*raw);
|
|
||||||
} else {
|
|
||||||
eventEmitter->_listeners[name].push_back(*cb);
|
|
||||||
eventEmitter->_raw[name].push_back(*raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nextId = eventEmitter->_freeId++;
|
|
||||||
eventEmitter->_wrappedIds[nextId] = *cb;
|
|
||||||
eventEmitter->_rawIds[nextId] = *raw;
|
|
||||||
|
|
||||||
int count = eventEmitter->_raw[name].size();
|
|
||||||
|
|
||||||
if (eventEmitter->_maxListeners > 0 && count > eventEmitter->_maxListeners) {
|
|
||||||
|
|
||||||
_reportListeners(name, count, eventEmitter->_maxListeners);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void _wrapOnceListener(
|
|
||||||
const Nan::FunctionCallbackInfo<v8::Value> &info,
|
|
||||||
bool isFront = false
|
|
||||||
) {
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
REQ_FUN_ARG(1, raw);
|
|
||||||
|
|
||||||
V8_VAR_STR code = JS_STR(R"(
|
|
||||||
((emitter, name, cb) => (...args) => {
|
|
||||||
cb(...args);
|
|
||||||
emitter.removeListener(name, cb);
|
|
||||||
})
|
|
||||||
)");
|
|
||||||
|
|
||||||
v8::Local<v8::Value> decor = v8::Script::Compile(
|
|
||||||
Nan::GetCurrentContext(), code
|
|
||||||
).ToLocalChecked()->Run(
|
|
||||||
Nan::GetCurrentContext()
|
|
||||||
).ToLocalChecked();
|
|
||||||
Nan::Callback decorCb(Nan::To<v8::Function>(decor).ToLocalChecked());
|
|
||||||
|
|
||||||
V8_VAR_VAL argv[] = { info.This(), info[0], raw };
|
|
||||||
Nan::AsyncResource async("EventEmitter::js_once()");
|
|
||||||
V8_VAR_VAL wrapValue = decorCb.Call(3, argv, &async).ToLocalChecked();
|
|
||||||
V8_VAR_FUNC wrap = V8_VAR_FUNC::Cast(wrapValue);
|
|
||||||
|
|
||||||
V8_STORE_FUNC persistentWrap;
|
|
||||||
persistentWrap.Reset(wrap);
|
|
||||||
|
|
||||||
V8_STORE_FUNC persistentRaw;
|
|
||||||
persistentRaw.Reset(raw);
|
|
||||||
|
|
||||||
_addOnceListener(info, *name, &persistentRaw, &persistentWrap, isFront);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsOnce) {
|
|
||||||
|
|
||||||
_wrapOnceListener(info);
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static NAN_METHOD(jsPrependListener) {
|
|
||||||
|
|
||||||
_wrapListener(info, true);
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static NAN_METHOD(jsPrependOnceListener) {
|
|
||||||
|
|
||||||
_wrapOnceListener(info, true);
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsRemoveAllListeners) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
if (info.Length() == 0) {
|
|
||||||
|
|
||||||
MAP_TYPE tmpMap = eventEmitter->_raw;
|
|
||||||
|
|
||||||
eventEmitter->_listeners.clear();
|
|
||||||
eventEmitter->_raw.clear();
|
|
||||||
eventEmitter->_wrappedIds.clear();
|
|
||||||
eventEmitter->_rawIds.clear();
|
|
||||||
|
|
||||||
for (MAP_IT_TYPE itMap = tmpMap.begin(); itMap != tmpMap.end(); ++itMap) {
|
|
||||||
|
|
||||||
const std::string ¤t = itMap->first;
|
|
||||||
VEC_TYPE &list = itMap->second;
|
|
||||||
|
|
||||||
for (IT_TYPE it = list.begin(); it != list.end(); ++it) {
|
|
||||||
|
|
||||||
V8_VAR_VAL args[] = { JS_STR(current.c_str()), Nan::New(*it) };
|
|
||||||
eventEmitter->emit("removeListener", 2, args);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, n);
|
|
||||||
|
|
||||||
std::string name = std::string(*n);
|
|
||||||
VEC_TYPE &list = eventEmitter->_raw[name];
|
|
||||||
|
|
||||||
if (list.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventEmitter->_rawIds.size()) {
|
|
||||||
|
|
||||||
std::vector<int> removes;
|
|
||||||
|
|
||||||
for (IT_TYPE it = list.begin(); it != list.end(); ++it) {
|
|
||||||
|
|
||||||
FN_TYPE fn = *it;
|
|
||||||
|
|
||||||
for (FNMAP_IT_TYPE itRaw = eventEmitter->_rawIds.begin(); itRaw != eventEmitter->_rawIds.end(); ++itRaw) {
|
|
||||||
if (fn == itRaw->second) {
|
|
||||||
removes.push_back(itRaw->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removes.size()) {
|
|
||||||
for (std::vector<int>::const_iterator it = removes.begin(); it != removes.end(); ++it) {
|
|
||||||
|
|
||||||
eventEmitter->_wrappedIds.erase(*it);
|
|
||||||
eventEmitter->_rawIds.erase(*it);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VEC_TYPE tmpVec = eventEmitter->_raw[name];
|
|
||||||
|
|
||||||
eventEmitter->_listeners[name].clear();
|
|
||||||
eventEmitter->_raw[name].clear();
|
|
||||||
|
|
||||||
for (IT_TYPE it = tmpVec.begin(); it != tmpVec.end(); ++it) {
|
|
||||||
|
|
||||||
V8_VAR_VAL args[] = { JS_STR(name.c_str()), Nan::New(*it) };
|
|
||||||
eventEmitter->emit("removeListener", 2, args);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsRemoveListener) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, n);
|
|
||||||
REQ_FUN_ARG(1, raw);
|
|
||||||
|
|
||||||
V8_STORE_FUNC persistentRaw;
|
|
||||||
persistentRaw.Reset(raw);
|
|
||||||
|
|
||||||
std::string name = std::string(*n);
|
|
||||||
|
|
||||||
VEC_TYPE &rawList = eventEmitter->_raw[name];
|
|
||||||
|
|
||||||
if (rawList.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
V8_VAR_VAL args[] = { info[0], info[1] };
|
|
||||||
|
|
||||||
for (IT_TYPE it = rawList.begin(); it != rawList.end(); ++it) {
|
|
||||||
|
|
||||||
if (*it == persistentRaw) {
|
|
||||||
rawList.erase(it);
|
|
||||||
if (rawList.empty()) {
|
|
||||||
eventEmitter->_raw.erase(name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VEC_TYPE &wrapList = eventEmitter->_listeners[name];
|
|
||||||
|
|
||||||
if (eventEmitter->_wrappedIds.size() == 0) {
|
|
||||||
|
|
||||||
for (IT_TYPE it = wrapList.begin(); it != wrapList.end(); ++it) {
|
|
||||||
|
|
||||||
if (*it == persistentRaw) {
|
|
||||||
wrapList.erase(it);
|
|
||||||
if (wrapList.empty()) {
|
|
||||||
eventEmitter->_listeners.erase(name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
eventEmitter->emit("removeListener", 2, args);
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (FNMAP_IT_TYPE itRaw = eventEmitter->_rawIds.begin(); itRaw != eventEmitter->_rawIds.end(); ++itRaw) {
|
|
||||||
|
|
||||||
if (persistentRaw == itRaw->second) {
|
|
||||||
|
|
||||||
FN_TYPE fn = eventEmitter->_wrappedIds[itRaw->first];
|
|
||||||
|
|
||||||
for (IT_TYPE it = wrapList.begin(); it != wrapList.end(); ++it) {
|
|
||||||
|
|
||||||
if (*it == fn) {
|
|
||||||
wrapList.erase(it);
|
|
||||||
if (wrapList.empty()) {
|
|
||||||
eventEmitter->_listeners.erase(name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
eventEmitter->_wrappedIds.erase(itRaw->first);
|
|
||||||
eventEmitter->_rawIds.erase(itRaw->first);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
eventEmitter->emit("removeListener", 2, args);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsSetMaxListeners) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_INT32_ARG(0, value);
|
|
||||||
|
|
||||||
eventEmitter->_maxListeners = value;
|
|
||||||
|
|
||||||
RET_VALUE(info.This());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsRawListeners) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
REQ_UTF8_ARG(0, name);
|
|
||||||
|
|
||||||
VEC_TYPE &list = eventEmitter->_raw[*name];
|
|
||||||
|
|
||||||
V8_VAR_ARR jsListeners = Nan::New<v8::Array>(list.size());
|
|
||||||
|
|
||||||
if (list.empty()) {
|
|
||||||
RET_VALUE(jsListeners);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (IT_TYPE it = list.begin(); it != list.end(); ++it, i++) {
|
|
||||||
|
|
||||||
jsListeners->Set(JS_INT(i), Nan::New(*it));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
RET_VALUE(jsListeners);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static NAN_METHOD(jsDestroy) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK;
|
|
||||||
|
|
||||||
eventEmitter->emit("destroy");
|
|
||||||
|
|
||||||
eventEmitter->_destroy();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool _isDestroyed;
|
|
||||||
|
|
||||||
int _maxListeners;
|
|
||||||
|
|
||||||
MAP_TYPE _listeners;
|
|
||||||
MAP_TYPE _raw;
|
|
||||||
|
|
||||||
int _freeId;
|
|
||||||
FNMAP_TYPE _wrappedIds;
|
|
||||||
FNMAP_TYPE _rawIds;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _EVENT_EMITTER_
|
|
71
index.js
71
index.js
|
@ -2,58 +2,43 @@
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const download = require('./js/download');
|
const platformNames = {
|
||||||
|
win32 : 'win',
|
||||||
|
linux : 'lin',
|
||||||
const NAMES = ['win32', 'win64', 'linux64', 'mac64'];
|
darwin : 'osx',
|
||||||
|
|
||||||
const prefixName = name => `bin-${name}`;
|
|
||||||
|
|
||||||
const getPlatformDir = () => {
|
|
||||||
switch (process.platform) {
|
|
||||||
case 'win32' : return process.arch === 'x64' ? 'win64' : 'win32';
|
|
||||||
case 'linux' : return 'linux64';
|
|
||||||
case 'darwin' : return 'mac64';
|
|
||||||
default : throw new Error(`Platform "${process.platform}" is not supported.`);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootPath = __dirname.replace(/\\/g, '/');
|
const platformName = platformNames[process.platform];
|
||||||
const nanInclude = path.dirname(require.resolve('nan')).replace(/\\/g, '/');
|
|
||||||
const thisInclude = `${rootPath}/include`;
|
if ( ! platformName ) {
|
||||||
|
console.log(`Error: UNKNOWN PLATFORM "${process.platform}"`);
|
||||||
|
}
|
||||||
|
|
||||||
const isWindows = process.platform === 'win32';
|
const isWindows = process.platform === 'win32';
|
||||||
const currentDir = prefixName(getPlatformDir());
|
|
||||||
const remDirs = NAMES.map(prefixName).filter(n => n !== currentDir);
|
const rootPath = __dirname.replace(/\\/g, '/');
|
||||||
|
|
||||||
|
const napiInclude = require('node-addon-api').include.replace(/\\/g, '/');
|
||||||
|
const thisInclude = `${rootPath}/include`;
|
||||||
|
|
||||||
const paths = dir => {
|
const paths = dir => {
|
||||||
|
|
||||||
dir = dir.replace(/\\/g, '/');
|
dir = dir.replace(/\\/g, '/');
|
||||||
|
|
||||||
const binPath = `${dir}/${currentDir}`;
|
const binPath = `${dir}/${platformName}`;
|
||||||
|
|
||||||
if (isWindows) {
|
if (isWindows) {
|
||||||
process.env.path = `${binPath};${process.env.path ? `${process.env.path}` : ''}`;
|
process.env.path = `${binPath};${process.env.path ? `${process.env.path}` : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remPath = remDirs.map(k => `${dir}/${k}`).join(' ');
|
|
||||||
const includePath = `${dir}/include`;
|
const includePath = `${dir}/include`;
|
||||||
|
|
||||||
return {
|
return { bin, include };
|
||||||
|
|
||||||
binPath,
|
|
||||||
remPath,
|
|
||||||
includePath,
|
|
||||||
|
|
||||||
bin() { console.log(binPath); },
|
|
||||||
rem() { console.log(remPath); },
|
|
||||||
include() { console.log(includePath); },
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const includePath = `${napiInclude} ${thisInclude}`;
|
||||||
const includePath = `${nanInclude} ${thisInclude}`;
|
|
||||||
const binPath = currentDir;
|
const binPath = currentDir;
|
||||||
|
|
||||||
const mkdirPath = isWindows ? `${rootPath}/bat/mkdir.bat` : 'mkdir';
|
const mkdirPath = isWindows ? `${rootPath}/bat/mkdir.bat` : 'mkdir';
|
||||||
|
@ -65,21 +50,11 @@ module.exports = {
|
||||||
|
|
||||||
paths,
|
paths,
|
||||||
|
|
||||||
binPath,
|
platform: platformName,
|
||||||
rootPath,
|
include: includePath,
|
||||||
includePath,
|
|
||||||
mkdirPath,
|
|
||||||
rmPath,
|
|
||||||
cpPath,
|
|
||||||
|
|
||||||
bin() { return console.log(binPath); },
|
mkdir: mkdirPath,
|
||||||
root() { return console.log(rootPath); },
|
rm: rmPath,
|
||||||
include() { console.log(includePath); },
|
cp: cpPath,
|
||||||
|
|
||||||
mkdir() { return console.log(mkdirPath); },
|
|
||||||
rm() { return console.log(rmPath); },
|
|
||||||
cp() { return console.log(cpPath); },
|
|
||||||
|
|
||||||
download,
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
const https = require('https');
|
||||||
|
const unzipper = require('unzipper');
|
||||||
|
|
||||||
|
const unzipper = require('unzipper');
|
||||||
|
|
||||||
|
const REPO = process.argv[1];
|
||||||
|
|
||||||
|
|
||||||
|
const download = (url, count = 1) => {
|
||||||
|
const sendReq = https.get(url, response => {
|
||||||
|
if ([301, 302, 303, 307].includes(response.statusCode)) {
|
||||||
|
if (count < 5) {
|
||||||
|
return download(response.headers.location, count + 1);
|
||||||
|
}
|
||||||
|
console.error('Error: Too many redirects.');
|
||||||
|
process.exit(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
console.log('Response status was ' + response.statusCode);
|
||||||
|
process.exit(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.pipe(unzipper.Extract({ path: 'bin' }));
|
||||||
|
});
|
||||||
|
|
||||||
|
sendReq.on('error', err => {
|
||||||
|
console.log(err.message);
|
||||||
|
process.exit(-1);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
download('https://github.com/raub/test-download/releases/download/v1.0.0/win.zip');
|
|
@ -1,30 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const https = require('https');
|
|
||||||
const http = require('http');
|
|
||||||
|
|
||||||
const WritableBuffer = require('./writable-buffer');
|
|
||||||
|
|
||||||
|
|
||||||
const protocols = { http, https };
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = url => new Promise(
|
|
||||||
(res, rej) => {
|
|
||||||
|
|
||||||
url = url.toLowerCase();
|
|
||||||
|
|
||||||
const stream = new WritableBuffer();
|
|
||||||
const proto = protocols[url.match(/^https?/)[0]];
|
|
||||||
|
|
||||||
proto.get(url, response => {
|
|
||||||
|
|
||||||
response.pipe(stream);
|
|
||||||
|
|
||||||
response.on('end', () => res(stream.get()));
|
|
||||||
response.on('error', err => rej(err));
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
17
package.json
17
package.json
|
@ -1,39 +1,32 @@
|
||||||
{
|
{
|
||||||
"author": "Luis Blanco <luisblanco1337@gmail.com>",
|
"author": "Luis Blanco <luisblanco1337@gmail.com>",
|
||||||
"name": "addon-tools-raub",
|
"name": "addon-tools-raub",
|
||||||
"version": "4.2.0",
|
"version": "5.0.0",
|
||||||
"description": "Helpers for Node.js addons and dependency packages",
|
"description": "Helpers for Node.js addons and dependency packages",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"support",
|
|
||||||
"headers",
|
"headers",
|
||||||
"include",
|
"include",
|
||||||
"eventemitter",
|
|
||||||
"events",
|
"events",
|
||||||
"utils",
|
"utils",
|
||||||
"c++",
|
"c++",
|
||||||
"addon",
|
"addon",
|
||||||
"bindings",
|
"bindings",
|
||||||
"native",
|
"native",
|
||||||
|
"napi",
|
||||||
"gyp"
|
"gyp"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.13.0",
|
"node": ">=10.16.1",
|
||||||
"npm": ">=6.4.1"
|
"npm": ">=6.4.1"
|
||||||
},
|
},
|
||||||
"maintainers": [
|
|
||||||
{
|
|
||||||
"name": "Luis Blanco",
|
|
||||||
"email": "luisblanco1337@gmail.com",
|
|
||||||
"skype": "rauber666"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/node-3d/addon-tools-raub.git"
|
"url": "https://github.com/node-3d/addon-tools-raub.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nan": "2.12.1"
|
"node-addon-api": "1.7.1",
|
||||||
|
"unzipper": "0.10.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
"main": "mocha",
|
"main": "mocha",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha",
|
"test": "mocha",
|
||||||
"start": "mocha"
|
"preinstall": "cd .. && npm i"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"addon-tools-raub": "https://github.com/node-3d/addon-tools-raub.git",
|
"addon-tools-raub": "..",
|
||||||
"chai": "^4.2.0",
|
"chai": "4.2.0",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "6.2.0",
|
||||||
"sinon": "^7.1.1"
|
"sinon": "7.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue