├── .gitignore ├── 1_hello_world ├── README.md ├── nan │ ├── binding.gyp │ ├── hello.cc │ ├── hello.js │ └── package.json ├── napi │ ├── binding.gyp │ ├── hello.cc │ ├── hello.js │ └── package.json ├── node-addon-api │ ├── binding.gyp │ ├── hello.cc │ ├── hello.js │ └── package.json ├── node_0.10 │ ├── binding.gyp │ ├── hello.cc │ ├── hello.js │ └── package.json └── node_0.12 │ ├── binding.gyp │ ├── hello.cc │ ├── hello.js │ └── package.json ├── 2_function_arguments ├── README.md ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── 3_callbacks ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── 4_object_factory ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── 5_function_factory ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ └── package.json ├── 6_object_wrap ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── 7_factory_wrap ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── 8_passing_wrapped ├── nan │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── napi │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── node-addon-api │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── node_0.10 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json └── node_0.12 │ ├── addon.cc │ ├── addon.js │ ├── binding.gyp │ ├── myobject.cc │ ├── myobject.h │ └── package.json ├── README.md ├── async_pi_estimate ├── nan │ ├── README.md │ ├── addon.cc │ ├── addon.js │ ├── async.cc │ ├── async.h │ ├── binding.gyp │ ├── package.json │ ├── pi_est.cc │ ├── pi_est.h │ ├── sync.cc │ └── sync.h └── node-addon-api │ ├── README.md │ ├── addon.cc │ ├── addon.js │ ├── async.cc │ ├── async.h │ ├── binding.gyp │ ├── package.json │ ├── pi_est.cc │ ├── pi_est.h │ ├── sync.cc │ └── sync.h ├── emit_event_from_cpp └── node-addon-api │ ├── binding.gyp │ ├── index.js │ ├── package.json │ └── src │ └── emit-from-cpp.cc ├── inherits_from_event_emitter └── node-addon-api │ ├── binding.gyp │ ├── index.js │ ├── package.json │ └── src │ ├── binding.cc │ ├── native-emitter.cc │ └── native-emitter.h └── original_docs_source.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /1_hello_world/README.md: -------------------------------------------------------------------------------- 1 | ## Example 1: *Hello world* 2 | 3 | To get started let's make a small addon which is the C++ equivalent of 4 | the following JavaScript code: 5 | 6 | ```js 7 | module.exports.hello = function() { return 'world'; }; 8 | ``` 9 | 10 | ### Step 1 11 | 12 | First we need to set up an npm-compatible package. Use `npm init` in a new directory to create the skeleton *package.json*. 13 | 14 | ### Step 2 15 | 16 | Next we need to install **[NAN](https://github.com/rvagg/nan)**. NAN will serve as a thin abstraction layer between the C++ code we write and the Node and V8 APIs so that we can target multiple versions of Node without worrying too much about the changing V8 or Node APIs. Run `npm install nan@latest --save` to install NAN and save it as a `"dependency"` in your *package.json*. 17 | 18 | ### Step 3 19 | 20 | All Node addons are compiled using the **[GYP](http://code.google.com/p/gyp/wiki/GypUserDocumentation)** build tool via **[node-gyp](https://github.com/TooTallNate/node-gyp)**. Add a `"gypfile": true` entry to your *package.json* so that npm knows this is a binary addon that needs compiling and it needs to invoke node-gyp. When node-gyp is invoked, it looks for a *binding.gyp* file in the same directory as your *package.json*. This file is written in YAML and describes the particulars of your build, including the source files and any binary dependencies. node-gyp will invoke GYP with your *binding.gyp* and also the [common.gypi](https://github.com/joyent/node/blob/master/common.gypi) settings file found in the source of the version of Node it is invoked with. Because your code will be compiled against the Node source and it requires the common.gypi file for that source, it must also download the complete tarball of the particular release you are running. These tarballs are stored in ~/.node-gyp/ so they only need to be installed once. 21 | 22 | Create a *binding.gyp* file with the following contents: 23 | 24 | ```yaml 25 | { 26 | "targets": [ 27 | { 28 | "target_name": "hello", 29 | "sources": [ "hello.cc" ], 30 | "include_dirs": [ 31 | " 51 | 52 | using namespace v8; 53 | 54 | NAN_METHOD(Method) { 55 | NanScope(); 56 | NanReturnValue(String::New("world")); 57 | } 58 | 59 | void Init(Handle exports) { 60 | exports->Set(NanSymbol("hello"), FunctionTemplate::New(Method)->GetFunction()); 61 | } 62 | 63 | NODE_MODULE(hello, Init) 64 | ``` 65 | 66 | This code contains three main components, starting from the bottom: 67 | 68 | ```c++ 69 | NODE_MODULE(hello, Init) 70 | ``` 71 | 72 | This code defines the entry-point for the Node addon, it tells Node where to go once the library has been loaded into active memory. The first argument **must match the "target" in our *binding.gyp***. The second argument points to the function to invoke. 73 | 74 | ```c++ 75 | void Init(Handle exports) { 76 | exports->Set(NanSymbol("hello"), FunctionTemplate::New(Method)->GetFunction()); 77 | } 78 | ``` 79 | 80 | This code is our entry-point. We can receive up to two arguments here, the first is `exports`, the same as `module.exports` in a .js file and the second argument (omitted in this case) is `module` which is the same as `module` in a .js file. Normally you would attach properties to `exports` but you can use the `module` argument to *replace* its `exports` property so you are exporting a single thing, the equivalent of: `module.exports = function () { ... }`. 81 | 82 | In our case we just want to attach a `"hello"` property to `module.exports` so we set a V8 `String` property to a V8 `Function` object. We use the `NanSymbol()` function to create a "symbol" string that we may reuse in future, so generally you should use these for object properties and other repeatable symbols. We use a V8 `FunctionTemplate` to turn a regular (but compatible) C++ function into a V8-callable function. In this case, the `Method` function. 83 | 84 | ```c++ 85 | NAN_METHOD(Method) { 86 | NanScope(); 87 | NanReturnValue(String::New("world")); 88 | } 89 | ``` 90 | 91 | This is where NAN first comes in useful for us. The changing V8 API has made it difficult to target different versions of Node with the same C++ code so NAN helps provide a simple mapping so we can define a V8 compatible function that `FunctionTemplate` will accept. In recent versions of V8, `NAN_METHOD(Method)` would expand to: `void Method(const v8::FunctionCallbackInfo& args)` which is the standard signature for a function that can be called by V8. The `args` parameter contains call information, such as JavaScript function parameters, and allows us to set return values. 92 | 93 | `NanScope()` is used here to set a V8 "handle scope" which is much like the function-scope in JavaScript. It defines the lifetime for which any created "handles" are safe from the garbage collector. When we use this at the top of our function we are declaring that any V8 object we create should live for the life of that function. If we omit the handle scope then created objects may attach to the global scope and may end up not being garbage collected, leading to a memory leak. 94 | 95 | `NanReturnValue()` sets the return value for our function. In this case we are creating a simple V8 `String` object with the contents `"world"`, this will be exposed as a standard JavaScript `String` with the value `"world"`. Since this object is created within the handle scope we declared above, its freedom from garbage collection will be lost as soon as it leaves our function *unless* it is referenced by another function, either in JavaScript or in a new handle scope in our C++. In our case we will be printing the string so it will be attached to a new scope in our JavaScript code. 96 | 97 | ### Step 5 98 | 99 | Compile your addon: if you don't have `node-gyp` installed, use `sudo npm install node-gyp -g` to install it. It comes bundled with npm but is not normally linked as an executable in your `PATH` so it's best to install it separately. 100 | 101 | Run `node-gyp configure` to set up the build fixtures. In the *./build/* directory, a *Makefile* and associated property files will be created on Unix systems and a *vcxproj* file will be created on Windows. 102 | 103 | Next, run `node-gyp build` to start the build process and watch your addon compile. You can use `node-gyp build` again to incrementally recompile changed source files. Alternatively you can use `node-gyp rebuild` to combine the `configure` and `build` steps in one. 104 | 105 | You should now have a compiled binary addon ready for use. Node will load it just like it loads a .js module file and include it in your running application. The binary file should be be located at *./build/Release/hello.node*. 106 | 107 | ### Step 6 108 | 109 | Write some JavaScript! 110 | 111 | Create a file called *hello.js* with the following contents: 112 | 113 | ```js 114 | var addon = require('./build/Release/hello.node'); 115 | 116 | console.log(addon.hello()); 117 | ``` 118 | 119 | The first line is responsible for loading our compiled add-on and pulling in the exports to our module. The path may substitute Debug for Release if you have run node-gyp with the `--debug` flag or you have used another method to signal to GYP that this should be a debug build. 120 | 121 | The best approach to this uncertainty of where the module file is located is to pull in an additional dependency, **[node-bindings](https://github.com/TooTallNate/node-bindings)** which will locate the binary for you, use it like so: 122 | 123 | ```js 124 | var addon = require('bindings')('hello.node') 125 | ``` 126 | 127 | The invocation of our addon comes from `console.log(addon.hello())` where we fetch the `Method` function in our C++ code and execute it. It returns a `"hello"` String which is printed to the console. 128 | 129 | The [nan](./nan/) directory contains a complete copy of this example. Run `npm install` and `node hello.js` to compile and run the code. 130 | 131 | The [node_0.10](./node_0.10/) directory contains a version of the example without NAN, compatible with Node 0.10 and prior (only). 132 | 133 | The [node_0.12](./node_0.12/) directory contains a version of the example without NAN, compatible with Node 0.11 and above (only). 134 | 135 | ***[Proceed to example 2 »](../2_function_arguments/)*** 136 | 137 | ***[Index](../#readme)*** 138 | -------------------------------------------------------------------------------- /1_hello_world/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "hello", 5 | "sources": [ "hello.cc" ], 6 | "include_dirs": [ 7 | " 2 | 3 | void Method(const Nan::FunctionCallbackInfo& info) { 4 | info.GetReturnValue().Set(Nan::New("world").ToLocalChecked()); 5 | } 6 | 7 | void Init(v8::Local exports) { 8 | exports->Set(Nan::New("hello").ToLocalChecked(), 9 | Nan::New(Method)->GetFunction()); 10 | } 11 | 12 | NODE_MODULE(hello, Init) 13 | -------------------------------------------------------------------------------- /1_hello_world/nan/hello.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('hello'); 2 | 3 | console.log(addon.hello()); // 'world' -------------------------------------------------------------------------------- /1_hello_world/nan/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_world", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #1", 5 | "main": "hello.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1", 9 | "nan": "^2.0.0" 10 | }, 11 | "scripts": { 12 | "test": "node hello.js" 13 | }, 14 | "gypfile": true 15 | } 16 | -------------------------------------------------------------------------------- /1_hello_world/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "hello", 5 | "sources": [ "hello.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /1_hello_world/napi/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | napi_value Method(napi_env env, napi_callback_info info) { 5 | napi_status status; 6 | napi_value world; 7 | status = napi_create_string_utf8(env, "world", 5, &world); 8 | assert(status == napi_ok); 9 | return world; 10 | } 11 | 12 | #define DECLARE_NAPI_METHOD(name, func) \ 13 | { name, 0, func, 0, 0, 0, napi_default, 0 } 14 | 15 | napi_value Init(napi_env env, napi_value exports) { 16 | napi_status status; 17 | napi_property_descriptor desc = DECLARE_NAPI_METHOD("hello", Method); 18 | status = napi_define_properties(env, exports, 1, &desc); 19 | assert(status == napi_ok); 20 | return exports; 21 | } 22 | 23 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 24 | -------------------------------------------------------------------------------- /1_hello_world/napi/hello.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('hello'); 2 | 3 | console.log(addon.hello()); // 'world' -------------------------------------------------------------------------------- /1_hello_world/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_world", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #1", 5 | "main": "hello.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1" 9 | }, 10 | "scripts": { 11 | "test": "node hello.js" 12 | }, 13 | "gypfile": true 14 | } 15 | -------------------------------------------------------------------------------- /1_hello_world/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "hello", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "hello.cc" ], 8 | "include_dirs": [ 9 | " 2 | 3 | Napi::String Method(const Napi::CallbackInfo& info) { 4 | Napi::Env env = info.Env(); 5 | return Napi::String::New(env, "world"); 6 | } 7 | 8 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 9 | exports.Set(Napi::String::New(env, "hello"), 10 | Napi::Function::New(env, Method)); 11 | return exports; 12 | } 13 | 14 | NODE_API_MODULE(hello, Init) 15 | -------------------------------------------------------------------------------- /1_hello_world/node-addon-api/hello.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('hello'); 2 | 3 | console.log(addon.hello()); // 'world' -------------------------------------------------------------------------------- /1_hello_world/node-addon-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_world", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #1", 5 | "main": "hello.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1", 9 | "node-addon-api": "^1.0.0" 10 | }, 11 | "scripts": { 12 | "test": "node hello.js" 13 | }, 14 | "gypfile": true 15 | } 16 | -------------------------------------------------------------------------------- /1_hello_world/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "hello", 5 | "sources": [ "hello.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /1_hello_world/node_0.10/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace v8; 5 | 6 | Handle Method(const Arguments& args) { 7 | HandleScope scope; 8 | return scope.Close(String::New("world")); 9 | } 10 | 11 | void Init(Handle exports) { 12 | exports->Set(String::NewSymbol("hello"), 13 | FunctionTemplate::New(Method)->GetFunction()); 14 | } 15 | 16 | NODE_MODULE(hello, Init) 17 | -------------------------------------------------------------------------------- /1_hello_world/node_0.10/hello.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('hello'); 2 | 3 | console.log(addon.hello()); // 'world' -------------------------------------------------------------------------------- /1_hello_world/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_world", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #1", 5 | "main": "hello.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "node hello.js" 9 | }, 10 | "gypfile": true, 11 | "dependencies": { 12 | "bindings": "~1.2.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /1_hello_world/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "hello", 5 | "sources": [ "hello.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /1_hello_world/node_0.12/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace v8; 5 | 6 | void Method(const v8::FunctionCallbackInfo& args) { 7 | Isolate* isolate = Isolate::GetCurrent(); 8 | HandleScope scope(isolate); 9 | args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); 10 | } 11 | 12 | void Init(Handle exports) { 13 | Isolate* isolate = Isolate::GetCurrent(); 14 | exports->Set(String::NewFromUtf8(isolate, "hello"), 15 | FunctionTemplate::New(isolate, Method)->GetFunction()); 16 | } 17 | 18 | NODE_MODULE(hello, Init) 19 | -------------------------------------------------------------------------------- /1_hello_world/node_0.12/hello.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('hello'); 2 | 3 | console.log(addon.hello()); // 'world' -------------------------------------------------------------------------------- /1_hello_world/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_world", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #1", 5 | "main": "hello.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "node hello.js" 9 | }, 10 | "gypfile": true, 11 | "dependencies": { 12 | "bindings": "~1.2.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /2_function_arguments/README.md: -------------------------------------------------------------------------------- 1 | ## Example 2: *Function arguments* 2 | 3 | -------------------------------------------------------------------------------- /2_function_arguments/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void Add(const Nan::FunctionCallbackInfo& info) { 4 | 5 | if (info.Length() < 2) { 6 | Nan::ThrowTypeError("Wrong number of arguments"); 7 | return; 8 | } 9 | 10 | if (!info[0]->IsNumber() || !info[1]->IsNumber()) { 11 | Nan::ThrowTypeError("Wrong arguments"); 12 | return; 13 | } 14 | 15 | double arg0 = info[0]->NumberValue(); 16 | double arg1 = info[1]->NumberValue(); 17 | v8::Local num = Nan::New(arg0 + arg1); 18 | 19 | info.GetReturnValue().Set(num); 20 | } 21 | 22 | void Init(v8::Local exports) { 23 | exports->Set(Nan::New("add").ToLocalChecked(), 24 | Nan::New(Add)->GetFunction()); 25 | } 26 | 27 | NODE_MODULE(addon, Init) 28 | -------------------------------------------------------------------------------- /2_function_arguments/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon.node') 2 | 3 | console.log('This should be eight:', addon.add(3, 5)) -------------------------------------------------------------------------------- /2_function_arguments/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ], 6 | "include_dirs": [ 7 | " 2 | #include 3 | #include 4 | napi_value Add(napi_env env, napi_callback_info info) { 5 | napi_status status; 6 | 7 | size_t argc = 2; 8 | napi_value args[2]; 9 | status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 10 | assert(status == napi_ok); 11 | 12 | if (argc < 2) { 13 | napi_throw_type_error(env, nullptr, "Wrong number of arguments"); 14 | return nullptr; 15 | } 16 | 17 | napi_valuetype valuetype0; 18 | status = napi_typeof(env, args[0], &valuetype0); 19 | assert(status == napi_ok); 20 | 21 | napi_valuetype valuetype1; 22 | status = napi_typeof(env, args[1], &valuetype1); 23 | assert(status == napi_ok); 24 | 25 | if (valuetype0 != napi_number || valuetype1 != napi_number) { 26 | napi_throw_type_error(env, nullptr, "Wrong arguments"); 27 | return nullptr; 28 | } 29 | 30 | double value0; 31 | status = napi_get_value_double(env, args[0], &value0); 32 | assert(status == napi_ok); 33 | 34 | double value1; 35 | status = napi_get_value_double(env, args[1], &value1); 36 | assert(status == napi_ok); 37 | 38 | napi_value sum; 39 | status = napi_create_double(env, value0 + value1, &sum); 40 | assert(status == napi_ok); 41 | 42 | return sum; 43 | } 44 | 45 | #define DECLARE_NAPI_METHOD(name, func) \ 46 | { name, 0, func, 0, 0, 0, napi_default, 0 } 47 | 48 | napi_value Init(napi_env env, napi_value exports) { 49 | napi_status status; 50 | napi_property_descriptor addDescriptor = DECLARE_NAPI_METHOD("add", Add); 51 | status = napi_define_properties(env, exports, 1, &addDescriptor); 52 | assert(status == napi_ok); 53 | return exports; 54 | } 55 | 56 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 57 | -------------------------------------------------------------------------------- /2_function_arguments/napi/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon.node') 2 | 3 | console.log('This should be eight:', addon.add(3, 5)) -------------------------------------------------------------------------------- /2_function_arguments/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /2_function_arguments/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function_arguments", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #2", 5 | "main": "addon.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1" 9 | }, 10 | "scripts": { 11 | "test": "node addon.js" 12 | }, 13 | "gypfile": true 14 | } 15 | -------------------------------------------------------------------------------- /2_function_arguments/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Napi::Value Add(const Napi::CallbackInfo& info) { 4 | Napi::Env env = info.Env(); 5 | 6 | if (info.Length() < 2) { 7 | Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 8 | return env.Null(); 9 | } 10 | 11 | if (!info[0].IsNumber() || !info[1].IsNumber()) { 12 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 13 | return env.Null(); 14 | } 15 | 16 | double arg0 = info[0].As().DoubleValue(); 17 | double arg1 = info[1].As().DoubleValue(); 18 | Napi::Number num = Napi::Number::New(env, arg0 + arg1); 19 | 20 | return num; 21 | } 22 | 23 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 24 | exports.Set(Napi::String::New(env, "add"), 25 | Napi::Function::New(env, Add)); 26 | return exports; 27 | } 28 | 29 | NODE_API_MODULE(addon, Init) 30 | -------------------------------------------------------------------------------- /2_function_arguments/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon.node') 2 | 3 | console.log('This should be eight:', addon.add(3, 5)) -------------------------------------------------------------------------------- /2_function_arguments/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "addon.cc" ], 8 | "include_dirs": [ 9 | " 2 | 3 | using namespace v8; 4 | 5 | Handle Add(const Arguments& args) { 6 | HandleScope scope; 7 | 8 | if (args.Length() < 2) { 9 | ThrowException(Exception::TypeError(String::New("Wrong number of arguments"))); 10 | return scope.Close(Undefined()); 11 | } 12 | 13 | if (!args[0]->IsNumber() || !args[1]->IsNumber()) { 14 | ThrowException(Exception::TypeError(String::New("Wrong arguments"))); 15 | return scope.Close(Undefined()); 16 | } 17 | 18 | double arg0 = args[0]->NumberValue(); 19 | double arg1 = args[1]->NumberValue(); 20 | Local num = Number::New(arg0 + arg1); 21 | 22 | return scope.Close(num); 23 | } 24 | 25 | void Init(Handle exports) { 26 | exports->Set(String::NewSymbol("add"), 27 | FunctionTemplate::New(Add)->GetFunction()); 28 | } 29 | 30 | NODE_MODULE(addon, Init) 31 | -------------------------------------------------------------------------------- /2_function_arguments/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon.node') 2 | 3 | console.log('This should be eight:', addon.add(3, 5)) -------------------------------------------------------------------------------- /2_function_arguments/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /2_function_arguments/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function_arguments", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #2", 5 | "main": "addon.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1" 9 | }, 10 | "scripts": { 11 | "test": "node addon.js" 12 | }, 13 | "gypfile": true 14 | } -------------------------------------------------------------------------------- /2_function_arguments/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace v8; 4 | 5 | void Add(const FunctionCallbackInfo& args) { 6 | Isolate* isolate = Isolate::GetCurrent(); 7 | HandleScope scope(isolate); 8 | 9 | if (args.Length() < 2) { 10 | isolate->ThrowException(Exception::TypeError( 11 | String::NewFromUtf8(isolate, "Wrong number of arguments"))); 12 | return; 13 | } 14 | 15 | if (!args[0]->IsNumber() || !args[1]->IsNumber()) { 16 | isolate->ThrowException(Exception::TypeError( 17 | String::NewFromUtf8(isolate, "Wrong arguments"))); 18 | return; 19 | } 20 | 21 | double value = args[0]->NumberValue() + args[1]->NumberValue(); 22 | Local num = Number::New(isolate, value); 23 | 24 | args.GetReturnValue().Set(num); 25 | } 26 | 27 | void Init(Handle exports) { 28 | NODE_SET_METHOD(exports, "add", Add); 29 | } 30 | 31 | NODE_MODULE(addon, Init) 32 | -------------------------------------------------------------------------------- /2_function_arguments/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon.node') 2 | 3 | console.log('This should be eight:', addon.add(3, 5)) -------------------------------------------------------------------------------- /2_function_arguments/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /2_function_arguments/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function_arguments", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #2", 5 | "main": "addon.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1", 9 | "nan": "~1.3.0" 10 | }, 11 | "scripts": { 12 | "test": "node addon.js" 13 | }, 14 | "gypfile": true 15 | } 16 | -------------------------------------------------------------------------------- /3_callbacks/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void RunCallback(const Nan::FunctionCallbackInfo& info) { 4 | v8::Local cb = info[0].As(); 5 | const unsigned argc = 1; 6 | v8::Local argv[argc] = { Nan::New("hello world").ToLocalChecked() }; 7 | Nan::MakeCallback(Nan::GetCurrentContext()->Global(), cb, argc, argv); 8 | } 9 | 10 | void Init(v8::Local exports, v8::Local module) { 11 | Nan::SetMethod(module, "exports", RunCallback); 12 | } 13 | 14 | NODE_MODULE(addon, Init) 15 | -------------------------------------------------------------------------------- /3_callbacks/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | addon(function(msg){ 4 | console.log(msg); // 'hello world' 5 | }); -------------------------------------------------------------------------------- /3_callbacks/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ], 6 | "include_dirs": [ 7 | " 2 | #include 3 | 4 | napi_value RunCallback(napi_env env, const napi_callback_info info) { 5 | napi_status status; 6 | 7 | size_t argc = 1; 8 | napi_value args[1]; 9 | status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 10 | assert(status == napi_ok); 11 | 12 | napi_value cb = args[0]; 13 | 14 | napi_value argv[1]; 15 | status = napi_create_string_utf8(env, "hello world", NAPI_AUTO_LENGTH, argv); 16 | assert(status == napi_ok); 17 | 18 | napi_value global; 19 | status = napi_get_global(env, &global); 20 | assert(status == napi_ok); 21 | 22 | napi_value result; 23 | status = napi_call_function(env, global, cb, 1, argv, &result); 24 | assert(status == napi_ok); 25 | 26 | return nullptr; 27 | } 28 | 29 | napi_value Init(napi_env env, napi_value exports) { 30 | napi_value new_exports; 31 | napi_status status = 32 | napi_create_function(env, "", NAPI_AUTO_LENGTH, RunCallback, nullptr, &new_exports); 33 | assert(status == napi_ok); 34 | return new_exports; 35 | } 36 | 37 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 38 | -------------------------------------------------------------------------------- /3_callbacks/napi/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | addon(function(msg){ 4 | console.log(msg); // 'hello world' 5 | }); 6 | -------------------------------------------------------------------------------- /3_callbacks/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /3_callbacks/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "napi_callbacks", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #3", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /3_callbacks/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void RunCallback(const Napi::CallbackInfo& info) { 4 | Napi::Env env = info.Env(); 5 | Napi::Function cb = info[0].As(); 6 | cb.Call(env.Global(), { Napi::String::New(env, "hello world") }); 7 | } 8 | 9 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 10 | return Napi::Function::New(env, RunCallback); 11 | } 12 | 13 | NODE_API_MODULE(addon, Init) 14 | -------------------------------------------------------------------------------- /3_callbacks/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | addon(function(msg){ 4 | console.log(msg); // 'hello world' 5 | }); -------------------------------------------------------------------------------- /3_callbacks/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "addon.cc" ], 8 | "include_dirs": [ 9 | " 2 | 3 | using namespace v8; 4 | 5 | Handle RunCallback(const Arguments& args) { 6 | HandleScope scope; 7 | 8 | Local cb = Local::Cast(args[0]); 9 | const unsigned argc = 1; 10 | Local argv[argc] = { Local::New(String::New("hello world")) }; 11 | cb->Call(Context::GetCurrent()->Global(), argc, argv); 12 | 13 | return scope.Close(Undefined()); 14 | } 15 | 16 | void Init(Handle exports, Handle module) { 17 | module->Set(String::NewSymbol("exports"), 18 | FunctionTemplate::New(RunCallback)->GetFunction()); 19 | } 20 | 21 | NODE_MODULE(addon, Init) 22 | -------------------------------------------------------------------------------- /3_callbacks/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | addon(function(msg){ 4 | console.log(msg); // 'hello world' 5 | }); -------------------------------------------------------------------------------- /3_callbacks/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /3_callbacks/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "callbacks", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #3", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "nan": "~1.3.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /3_callbacks/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace v8; 4 | 5 | void RunCallback(const FunctionCallbackInfo& args) { 6 | Isolate* isolate = Isolate::GetCurrent(); 7 | HandleScope scope(isolate); 8 | 9 | Local cb = Local::Cast(args[0]); 10 | const unsigned argc = 1; 11 | Local argv[argc] = { String::NewFromUtf8(isolate, "hello world") }; 12 | cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); 13 | } 14 | 15 | void Init(Handle exports, Handle module) { 16 | NODE_SET_METHOD(module, "exports", RunCallback); 17 | } 18 | 19 | NODE_MODULE(addon, Init) 20 | -------------------------------------------------------------------------------- /3_callbacks/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | addon(function(msg){ 4 | console.log(msg); // 'hello world' 5 | }); -------------------------------------------------------------------------------- /3_callbacks/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /3_callbacks/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "callbacks", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #3", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /4_object_factory/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void CreateObject(const Nan::FunctionCallbackInfo& info) { 4 | v8::Local obj = Nan::New(); 5 | obj->Set(Nan::New("msg").ToLocalChecked(), info[0]->ToString()); 6 | 7 | info.GetReturnValue().Set(obj); 8 | } 9 | 10 | void Init(v8::Local exports, v8::Local module) { 11 | module->Set(Nan::New("exports").ToLocalChecked(), 12 | Nan::New(CreateObject)->GetFunction()); 13 | } 14 | 15 | NODE_MODULE(addon, Init) 16 | -------------------------------------------------------------------------------- /4_object_factory/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon('hello'); 4 | var obj2 = addon('world'); 5 | console.log(obj1.msg+' '+obj2.msg); // 'hello world' -------------------------------------------------------------------------------- /4_object_factory/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ], 6 | "include_dirs": [ 7 | " 2 | #include 3 | 4 | napi_value CreateObject(napi_env env, const napi_callback_info info) { 5 | napi_status status; 6 | 7 | size_t argc = 1; 8 | napi_value args[1]; 9 | status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 10 | assert(status == napi_ok); 11 | 12 | napi_value obj; 13 | status = napi_create_object(env, &obj); 14 | assert(status == napi_ok); 15 | 16 | status = napi_set_named_property(env, obj, "msg", args[0]); 17 | assert(status == napi_ok); 18 | 19 | return obj; 20 | } 21 | 22 | napi_value Init(napi_env env, napi_value exports) { 23 | napi_value new_exports; 24 | napi_status status = 25 | napi_create_function(env, "", NAPI_AUTO_LENGTH, CreateObject, nullptr, &new_exports); 26 | assert(status == napi_ok); 27 | return new_exports; 28 | } 29 | 30 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 31 | -------------------------------------------------------------------------------- /4_object_factory/napi/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon('hello'); 4 | var obj2 = addon('world'); 5 | console.log(obj1.msg+' '+obj2.msg); // 'hello world' -------------------------------------------------------------------------------- /4_object_factory/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /4_object_factory/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_factory", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #4", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /4_object_factory/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Napi::Object CreateObject(const Napi::CallbackInfo& info) { 4 | Napi::Env env = info.Env(); 5 | Napi::Object obj = Napi::Object::New(env); 6 | obj.Set(Napi::String::New(env, "msg"), info[0].ToString()); 7 | 8 | return obj; 9 | } 10 | 11 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 12 | return Napi::Function::New(env, CreateObject, "createObject"); 13 | } 14 | 15 | NODE_API_MODULE(addon, Init) 16 | -------------------------------------------------------------------------------- /4_object_factory/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon('hello'); 4 | var obj2 = addon('world'); 5 | console.log(obj1.msg+' '+obj2.msg); // 'hello world' -------------------------------------------------------------------------------- /4_object_factory/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "addon.cc" ], 8 | "include_dirs": [ 9 | " 2 | 3 | using namespace v8; 4 | 5 | Handle CreateObject(const Arguments& args) { 6 | HandleScope scope; 7 | 8 | Local obj = Object::New(); 9 | obj->Set(String::NewSymbol("msg"), args[0]->ToString()); 10 | 11 | return scope.Close(obj); 12 | } 13 | 14 | void Init(Handle exports, Handle module) { 15 | module->Set(String::NewSymbol("exports"), 16 | FunctionTemplate::New(CreateObject)->GetFunction()); 17 | } 18 | 19 | NODE_MODULE(addon, Init) 20 | -------------------------------------------------------------------------------- /4_object_factory/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon('hello'); 4 | var obj2 = addon('world'); 5 | console.log(obj1.msg+' '+obj2.msg); // 'hello world' -------------------------------------------------------------------------------- /4_object_factory/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /4_object_factory/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_factory", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #4", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /4_object_factory/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace v8; 4 | 5 | void CreateObject(const FunctionCallbackInfo& args) { 6 | Isolate* isolate = Isolate::GetCurrent(); 7 | HandleScope scope(isolate); 8 | 9 | Local obj = Object::New(isolate); 10 | obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString()); 11 | 12 | args.GetReturnValue().Set(obj); 13 | } 14 | 15 | void Init(Handle exports, Handle module) { 16 | NODE_SET_METHOD(module, "exports", CreateObject); 17 | } 18 | 19 | NODE_MODULE(addon, Init) 20 | -------------------------------------------------------------------------------- /4_object_factory/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon('hello'); 4 | var obj2 = addon('world'); 5 | console.log(obj1.msg+' '+obj2.msg); // 'hello world' -------------------------------------------------------------------------------- /4_object_factory/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /4_object_factory/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_factory", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #4", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /5_function_factory/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void MyFunction(const Nan::FunctionCallbackInfo& info) { 4 | info.GetReturnValue().Set(Nan::New("hello world").ToLocalChecked()); 5 | } 6 | 7 | void CreateFunction(const Nan::FunctionCallbackInfo& info) { 8 | v8::Local tpl = Nan::New(MyFunction); 9 | v8::Local fn = tpl->GetFunction(); 10 | 11 | // omit this to make it anonymous 12 | fn->SetName(Nan::New("theFunction").ToLocalChecked()); 13 | 14 | info.GetReturnValue().Set(fn); 15 | } 16 | 17 | void Init(v8::Local exports, v8::Local module) { 18 | Nan::SetMethod(module, "exports", CreateFunction); 19 | } 20 | 21 | NODE_MODULE(addon, Init) 22 | -------------------------------------------------------------------------------- /5_function_factory/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var fn = addon(); 4 | console.log(fn()); // 'hello world' -------------------------------------------------------------------------------- /5_function_factory/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ], 6 | "include_dirs": [ 7 | " 2 | #include 3 | 4 | napi_value MyFunction(napi_env env, napi_callback_info info) { 5 | napi_status status; 6 | 7 | napi_value str; 8 | status = napi_create_string_utf8(env, "hello world", NAPI_AUTO_LENGTH, &str); 9 | assert(status == napi_ok); 10 | 11 | return str; 12 | } 13 | 14 | napi_value CreateFunction(napi_env env, napi_callback_info info) { 15 | napi_status status; 16 | 17 | napi_value fn; 18 | status = napi_create_function(env, "theFunction", NAPI_AUTO_LENGTH, MyFunction, nullptr, &fn); 19 | assert(status == napi_ok); 20 | 21 | return fn; 22 | } 23 | 24 | napi_value Init(napi_env env, napi_value exports) { 25 | napi_value new_exports; 26 | napi_status status = 27 | napi_create_function(env, "", NAPI_AUTO_LENGTH, CreateFunction, nullptr, &new_exports); 28 | assert(status == napi_ok); 29 | return new_exports; 30 | } 31 | 32 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 33 | -------------------------------------------------------------------------------- /5_function_factory/napi/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var fn = addon(); 4 | console.log(fn()); // 'hello world' 5 | -------------------------------------------------------------------------------- /5_function_factory/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /5_function_factory/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function_factory", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #5", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /5_function_factory/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Napi::String MyFunction(const Napi::CallbackInfo& info) { 4 | Napi::Env env = info.Env(); 5 | return Napi::String::New(env, "hello world"); 6 | } 7 | 8 | Napi::Function CreateFunction(const Napi::CallbackInfo& info) { 9 | Napi::Env env = info.Env(); 10 | Napi::Function fn = Napi::Function::New(env, MyFunction, "theFunction"); 11 | return fn; 12 | } 13 | 14 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 15 | return Napi::Function::New(env, CreateFunction, "createObject"); 16 | } 17 | 18 | NODE_API_MODULE(addon, Init) 19 | -------------------------------------------------------------------------------- /5_function_factory/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var fn = addon(); 4 | console.log(fn()); // 'hello world' -------------------------------------------------------------------------------- /5_function_factory/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "addon.cc" ], 8 | "include_dirs": [ 9 | " 2 | 3 | using namespace v8; 4 | 5 | Handle MyFunction(const Arguments& args) { 6 | HandleScope scope; 7 | return scope.Close(String::New("hello world")); 8 | } 9 | 10 | Handle CreateFunction(const Arguments& args) { 11 | HandleScope scope; 12 | 13 | Local tpl = FunctionTemplate::New(MyFunction); 14 | Local fn = tpl->GetFunction(); 15 | fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous 16 | 17 | return scope.Close(fn); 18 | } 19 | 20 | void Init(Handle exports, Handle module) { 21 | module->Set(String::NewSymbol("exports"), 22 | FunctionTemplate::New(CreateFunction)->GetFunction()); 23 | } 24 | 25 | NODE_MODULE(addon, Init) 26 | -------------------------------------------------------------------------------- /5_function_factory/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var fn = addon(); 4 | console.log(fn()); // 'hello world' -------------------------------------------------------------------------------- /5_function_factory/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /5_function_factory/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function_factory", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #5", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /5_function_factory/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace v8; 4 | 5 | void MyFunction(const FunctionCallbackInfo& args) { 6 | Isolate* isolate = Isolate::GetCurrent(); 7 | HandleScope scope(isolate); 8 | args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world")); 9 | } 10 | 11 | void CreateFunction(const FunctionCallbackInfo& args) { 12 | Isolate* isolate = Isolate::GetCurrent(); 13 | HandleScope scope(isolate); 14 | 15 | Local tpl = FunctionTemplate::New(isolate, MyFunction); 16 | Local fn = tpl->GetFunction(); 17 | 18 | // omit this to make it anonymous 19 | fn->SetName(String::NewFromUtf8(isolate, "theFunction")); 20 | 21 | args.GetReturnValue().Set(fn); 22 | } 23 | 24 | void Init(Handle exports, Handle module) { 25 | NODE_SET_METHOD(module, "exports", CreateFunction); 26 | } 27 | 28 | NODE_MODULE(addon, Init) 29 | -------------------------------------------------------------------------------- /5_function_factory/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var fn = addon(); 4 | console.log(fn()); // 'hello world' -------------------------------------------------------------------------------- /5_function_factory/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /5_function_factory/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function_factory", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #5", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /6_object_wrap/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | void InitAll(v8::Local exports) { 5 | MyObject::Init(exports); 6 | } 7 | 8 | NODE_MODULE(addon, InitAll) 9 | -------------------------------------------------------------------------------- /6_object_wrap/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj = new addon.MyObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | console.log( obj.multiply().value() ); // 13 9 | console.log( obj.multiply(10).value() ); // 130 10 | 11 | var newobj = obj.multiply(-1); 12 | console.log( newobj.value() ); // -13 13 | console.log( obj === newobj ); // false 14 | -------------------------------------------------------------------------------- /6_object_wrap/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ], 6 | "include_dirs": [ 7 | " MyObject::constructor; 4 | 5 | MyObject::MyObject(double value) : value_(value) { 6 | } 7 | 8 | MyObject::~MyObject() { 9 | } 10 | 11 | void MyObject::Init(v8::Local exports) { 12 | Nan::HandleScope scope; 13 | 14 | // Prepare constructor template 15 | v8::Local tpl = Nan::New(New); 16 | tpl->SetClassName(Nan::New("MyObject").ToLocalChecked()); 17 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 18 | 19 | // Prototype 20 | Nan::SetPrototypeMethod(tpl, "value", GetValue); 21 | Nan::SetPrototypeMethod(tpl, "plusOne", PlusOne); 22 | Nan::SetPrototypeMethod(tpl, "multiply", Multiply); 23 | 24 | constructor.Reset(tpl->GetFunction()); 25 | exports->Set(Nan::New("MyObject").ToLocalChecked(), tpl->GetFunction()); 26 | } 27 | 28 | void MyObject::New(const Nan::FunctionCallbackInfo& info) { 29 | if (info.IsConstructCall()) { 30 | // Invoked as constructor: `new MyObject(...)` 31 | double value = info[0]->IsUndefined() ? 0 : info[0]->NumberValue(); 32 | MyObject* obj = new MyObject(value); 33 | obj->Wrap(info.This()); 34 | info.GetReturnValue().Set(info.This()); 35 | } else { 36 | // Invoked as plain function `MyObject(...)`, turn into construct call. 37 | const int argc = 1; 38 | v8::Local argv[argc] = { info[0] }; 39 | v8::Local cons = Nan::New(constructor); 40 | info.GetReturnValue().Set(cons->NewInstance(argc, argv)); 41 | } 42 | } 43 | 44 | void MyObject::GetValue(const Nan::FunctionCallbackInfo& info) { 45 | MyObject* obj = ObjectWrap::Unwrap(info.Holder()); 46 | info.GetReturnValue().Set(Nan::New(obj->value_)); 47 | } 48 | 49 | void MyObject::PlusOne(const Nan::FunctionCallbackInfo& info) { 50 | MyObject* obj = ObjectWrap::Unwrap(info.Holder()); 51 | obj->value_ += 1; 52 | info.GetReturnValue().Set(Nan::New(obj->value_)); 53 | } 54 | 55 | void MyObject::Multiply(const Nan::FunctionCallbackInfo& info) { 56 | MyObject* obj = ObjectWrap::Unwrap(info.Holder()); 57 | double multiple = info[0]->IsUndefined() ? 1 : info[0]->NumberValue(); 58 | 59 | v8::Local cons = Nan::New(constructor); 60 | 61 | const int argc = 1; 62 | v8::Local argv[argc] = { Nan::New(obj->value_ * multiple) }; 63 | 64 | info.GetReturnValue().Set(cons->NewInstance(argc, argv)); 65 | } 66 | -------------------------------------------------------------------------------- /6_object_wrap/nan/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public Nan::ObjectWrap { 7 | public: 8 | static void Init(v8::Local exports); 9 | 10 | private: 11 | explicit MyObject(double value = 0); 12 | ~MyObject(); 13 | 14 | static void New(const Nan::FunctionCallbackInfo& info); 15 | static void GetValue(const Nan::FunctionCallbackInfo& info); 16 | static void PlusOne(const Nan::FunctionCallbackInfo& info); 17 | static void Multiply(const Nan::FunctionCallbackInfo& info); 18 | static Nan::Persistent constructor; 19 | double value_; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /6_object_wrap/nan/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #6", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "nan": "^2.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /6_object_wrap/napi/addon.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | 3 | napi_value Init(napi_env env, napi_value exports) { 4 | return MyObject::Init(env, exports); 5 | } 6 | 7 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 8 | -------------------------------------------------------------------------------- /6_object_wrap/napi/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj = new addon.MyObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | console.log( obj.multiply().value ); // 13 9 | console.log( obj.multiply(10).value ); // 130 10 | 11 | var newobj = obj.multiply(-1); 12 | console.log( newobj.value ); // -13 13 | console.log( obj === newobj ); // false 14 | -------------------------------------------------------------------------------- /6_object_wrap/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /6_object_wrap/napi/myobject.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include 3 | 4 | napi_ref MyObject::constructor; 5 | 6 | MyObject::MyObject(double value) 7 | : value_(value), env_(nullptr), wrapper_(nullptr) {} 8 | 9 | MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } 10 | 11 | void MyObject::Destructor(napi_env env, void* nativeObject, void* /*finalize_hint*/) { 12 | reinterpret_cast(nativeObject)->~MyObject(); 13 | } 14 | 15 | #define DECLARE_NAPI_METHOD(name, func) \ 16 | { name, 0, func, 0, 0, 0, napi_default, 0 } 17 | 18 | napi_value MyObject::Init(napi_env env, napi_value exports) { 19 | napi_status status; 20 | napi_property_descriptor properties[] = { 21 | { "value", 0, 0, GetValue, SetValue, 0, napi_default, 0 }, 22 | DECLARE_NAPI_METHOD("plusOne", PlusOne), 23 | DECLARE_NAPI_METHOD("multiply", Multiply), 24 | }; 25 | 26 | napi_value cons; 27 | status = 28 | napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 3, properties, &cons); 29 | assert(status == napi_ok); 30 | 31 | status = napi_create_reference(env, cons, 1, &constructor); 32 | assert(status == napi_ok); 33 | 34 | status = napi_set_named_property(env, exports, "MyObject", cons); 35 | assert(status == napi_ok); 36 | return exports; 37 | } 38 | 39 | napi_value MyObject::New(napi_env env, napi_callback_info info) { 40 | napi_status status; 41 | 42 | napi_value target; 43 | status = napi_get_new_target(env, info, &target); 44 | assert(status == napi_ok); 45 | bool is_constructor = target != nullptr; 46 | 47 | if (is_constructor) { 48 | // Invoked as constructor: `new MyObject(...)` 49 | size_t argc = 1; 50 | napi_value args[1]; 51 | napi_value jsthis; 52 | status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); 53 | assert(status == napi_ok); 54 | 55 | double value = 0; 56 | 57 | napi_valuetype valuetype; 58 | status = napi_typeof(env, args[0], &valuetype); 59 | assert(status == napi_ok); 60 | 61 | if (valuetype != napi_undefined) { 62 | status = napi_get_value_double(env, args[0], &value); 63 | assert(status == napi_ok); 64 | } 65 | 66 | MyObject* obj = new MyObject(value); 67 | 68 | obj->env_ = env; 69 | status = napi_wrap(env, 70 | jsthis, 71 | reinterpret_cast(obj), 72 | MyObject::Destructor, 73 | nullptr, // finalize_hint 74 | &obj->wrapper_); 75 | assert(status == napi_ok); 76 | 77 | return jsthis; 78 | } else { 79 | // Invoked as plain function `MyObject(...)`, turn into construct call. 80 | size_t argc_ = 1; 81 | napi_value args[1]; 82 | status = napi_get_cb_info(env, info, &argc_, args, nullptr, nullptr); 83 | assert(status == napi_ok); 84 | 85 | const size_t argc = 1; 86 | napi_value argv[argc] = {args[0]}; 87 | 88 | napi_value cons; 89 | status = napi_get_reference_value(env, constructor, &cons); 90 | assert(status == napi_ok); 91 | 92 | napi_value instance; 93 | status = napi_new_instance(env, cons, argc, argv, &instance); 94 | assert(status == napi_ok); 95 | 96 | return instance; 97 | } 98 | } 99 | 100 | napi_value MyObject::GetValue(napi_env env, napi_callback_info info) { 101 | napi_status status; 102 | 103 | napi_value jsthis; 104 | status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr); 105 | assert(status == napi_ok); 106 | 107 | MyObject* obj; 108 | status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); 109 | assert(status == napi_ok); 110 | 111 | napi_value num; 112 | status = napi_create_double(env, obj->value_, &num); 113 | assert(status == napi_ok); 114 | 115 | return num; 116 | } 117 | 118 | napi_value MyObject::SetValue(napi_env env, napi_callback_info info) { 119 | napi_status status; 120 | 121 | size_t argc = 1; 122 | napi_value value; 123 | napi_value jsthis; 124 | status = napi_get_cb_info(env, info, &argc, &value, &jsthis, nullptr); 125 | assert(status == napi_ok); 126 | 127 | 128 | MyObject* obj; 129 | status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); 130 | assert(status == napi_ok); 131 | 132 | status = napi_get_value_double(env, value, &obj->value_); 133 | assert(status == napi_ok); 134 | 135 | return nullptr; 136 | } 137 | 138 | napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) { 139 | napi_status status; 140 | 141 | napi_value jsthis; 142 | status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr); 143 | assert(status == napi_ok); 144 | 145 | MyObject* obj; 146 | status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); 147 | assert(status == napi_ok); 148 | 149 | obj->value_ += 1; 150 | 151 | napi_value num; 152 | status = napi_create_double(env, obj->value_, &num); 153 | assert(status == napi_ok); 154 | 155 | return num; 156 | } 157 | 158 | napi_value MyObject::Multiply(napi_env env, napi_callback_info info) { 159 | napi_status status; 160 | 161 | size_t argc = 1; 162 | napi_value args[1]; 163 | napi_value jsthis; 164 | status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); 165 | assert(status == napi_ok); 166 | 167 | napi_valuetype valuetype; 168 | status = napi_typeof(env, args[0], &valuetype); 169 | assert(status == napi_ok); 170 | 171 | double multiple = 1; 172 | if (valuetype != napi_undefined) { 173 | status = napi_get_value_double(env, args[0], &multiple); 174 | assert(status == napi_ok); 175 | } 176 | 177 | MyObject* obj; 178 | status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); 179 | assert(status == napi_ok); 180 | 181 | napi_value cons; 182 | status = napi_get_reference_value(env, constructor, &cons); 183 | assert(status == napi_ok); 184 | 185 | const int kArgCount = 1; 186 | napi_value argv[kArgCount]; 187 | status = napi_create_double(env, obj->value_ * multiple, argv); 188 | assert(status == napi_ok); 189 | 190 | napi_value instance; 191 | status = napi_new_instance(env, cons, kArgCount, argv, &instance); 192 | assert(status == napi_ok); 193 | 194 | return instance; 195 | } 196 | -------------------------------------------------------------------------------- /6_object_wrap/napi/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_ADDONS_NAPI_6_OBJECT_WRAP_MYOBJECT_H_ 2 | #define TEST_ADDONS_NAPI_6_OBJECT_WRAP_MYOBJECT_H_ 3 | 4 | #include 5 | 6 | class MyObject { 7 | public: 8 | static napi_value Init(napi_env env, napi_value exports); 9 | static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 10 | 11 | private: 12 | explicit MyObject(double value_ = 0); 13 | ~MyObject(); 14 | 15 | static napi_value New(napi_env env, napi_callback_info info); 16 | static napi_value GetValue(napi_env env, napi_callback_info info); 17 | static napi_value SetValue(napi_env env, napi_callback_info info); 18 | static napi_value PlusOne(napi_env env, napi_callback_info info); 19 | static napi_value Multiply(napi_env env, napi_callback_info info); 20 | static napi_ref constructor; 21 | double value_; 22 | napi_env env_; 23 | napi_ref wrapper_; 24 | }; 25 | 26 | #endif // TEST_ADDONS_NAPI_6_OBJECT_WRAP_MYOBJECT_H_ 27 | -------------------------------------------------------------------------------- /6_object_wrap/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #6", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /6_object_wrap/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | Napi::Object InitAll(Napi::Env env, Napi::Object exports) { 5 | return MyObject::Init(env, exports); 6 | } 7 | 8 | NODE_API_MODULE(addon, InitAll) 9 | -------------------------------------------------------------------------------- /6_object_wrap/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj = new addon.MyObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | console.log( obj.multiply().value() ); // 13 9 | console.log( obj.multiply(10).value() ); // 130 10 | 11 | var newobj = obj.multiply(-1); 12 | console.log( newobj.value() ); // -13 13 | console.log( obj === newobj ); // false 14 | -------------------------------------------------------------------------------- /6_object_wrap/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "addon.cc", "myobject.cc" ], 8 | "include_dirs": [ 9 | "(info) { 22 | Napi::Env env = info.Env(); 23 | Napi::HandleScope scope(env); 24 | 25 | int length = info.Length(); 26 | 27 | if (length <= 0 || !info[0].IsNumber()) { 28 | Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); 29 | } 30 | 31 | Napi::Number value = info[0].As(); 32 | this->value_ = value.DoubleValue(); 33 | } 34 | 35 | Napi::Value MyObject::GetValue(const Napi::CallbackInfo& info) { 36 | double num = this->value_; 37 | 38 | return Napi::Number::New(info.Env(), num); 39 | } 40 | 41 | Napi::Value MyObject::PlusOne(const Napi::CallbackInfo& info) { 42 | this->value_ = this->value_ + 1; 43 | 44 | return MyObject::GetValue(info); 45 | } 46 | 47 | Napi::Value MyObject::Multiply(const Napi::CallbackInfo& info) { 48 | Napi::Number multiple; 49 | if (info.Length() <= 0 || !info[0].IsNumber()) { 50 | multiple = Napi::Number::New(info.Env(), 1); 51 | } else { 52 | multiple = info[0].As(); 53 | } 54 | 55 | Napi::Object obj = constructor.New({ Napi::Number::New(info.Env(), this->value_ * multiple.DoubleValue()) }); 56 | 57 | return obj; 58 | } 59 | -------------------------------------------------------------------------------- /6_object_wrap/node-addon-api/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public Napi::ObjectWrap { 7 | public: 8 | static Napi::Object Init(Napi::Env env, Napi::Object exports); 9 | MyObject(const Napi::CallbackInfo& info); 10 | 11 | private: 12 | static Napi::FunctionReference constructor; 13 | 14 | Napi::Value GetValue(const Napi::CallbackInfo& info); 15 | Napi::Value PlusOne(const Napi::CallbackInfo& info); 16 | Napi::Value Multiply(const Napi::CallbackInfo& info); 17 | 18 | double value_; 19 | 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /6_object_wrap/node-addon-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #6", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "node-addon-api": "^1.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.10/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | void InitAll(Handle exports) { 7 | MyObject::Init(exports); 8 | } 9 | 10 | NODE_MODULE(addon, InitAll) 11 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj = new addon.MyObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | console.log( obj.multiply().value() ); // 13 9 | console.log( obj.multiply(10).value() ); // 130 10 | 11 | var newobj = obj.multiply(-1); 12 | console.log( newobj.value() ); // -13 13 | console.log( obj === newobj ); // false 14 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.10/myobject.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | Persistent MyObject::constructor; 7 | 8 | MyObject::MyObject() {}; 9 | MyObject::~MyObject() {}; 10 | 11 | void MyObject::Init(Handle target) { 12 | // Prepare constructor template 13 | Local tpl = FunctionTemplate::New(New); 14 | tpl->SetClassName(String::NewSymbol("MyObject")); 15 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 16 | // Prototype 17 | NODE_SET_PROTOTYPE_METHOD(tpl, "value", GetValue); 18 | NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); 19 | NODE_SET_PROTOTYPE_METHOD(tpl, "multiply", Multiply); 20 | 21 | constructor = Persistent::New(tpl->GetFunction()); 22 | target->Set(String::NewSymbol("MyObject"), constructor); 23 | } 24 | 25 | Handle MyObject::New(const Arguments& args) { 26 | HandleScope scope; 27 | 28 | MyObject* obj = new MyObject(); 29 | obj->value_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 30 | obj->Wrap(args.This()); 31 | 32 | return args.This(); 33 | } 34 | 35 | Handle MyObject::GetValue(const Arguments& args) { 36 | HandleScope scope; 37 | 38 | MyObject* obj = ObjectWrap::Unwrap(args.Holder()); 39 | 40 | return scope.Close(Number::New(obj->value_)); 41 | } 42 | 43 | Handle MyObject::PlusOne(const Arguments& args) { 44 | HandleScope scope; 45 | 46 | MyObject* obj = ObjectWrap::Unwrap(args.This()); 47 | obj->value_ += 1; 48 | 49 | return scope.Close(Number::New(obj->value_)); 50 | } 51 | 52 | Handle MyObject::Multiply(const Arguments& args) { 53 | HandleScope scope; 54 | 55 | MyObject* obj = ObjectWrap::Unwrap(args.This()); 56 | double multiple = args[0]->IsUndefined() ? 1 : args[0]->NumberValue(); 57 | 58 | const int argc = 1; 59 | Local argv[argc] = { Number::New(obj->value_ * multiple) }; 60 | 61 | return scope.Close(constructor->NewInstance(argc, argv)); 62 | } 63 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.10/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public node::ObjectWrap { 7 | public: 8 | static void Init(v8::Handle target); 9 | 10 | private: 11 | MyObject(); 12 | ~MyObject(); 13 | 14 | static v8::Handle New(const v8::Arguments& args); 15 | static v8::Handle GetValue(const v8::Arguments& args); 16 | static v8::Handle PlusOne(const v8::Arguments& args); 17 | static v8::Handle Multiply(const v8::Arguments& args); 18 | static v8::Persistent constructor; 19 | double value_; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #6", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | void InitAll(Handle exports) { 7 | MyObject::Init(exports); 8 | } 9 | 10 | NODE_MODULE(addon, InitAll) 11 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj = new addon.MyObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 -------------------------------------------------------------------------------- /6_object_wrap/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.12/myobject.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | 3 | using namespace v8; 4 | 5 | Persistent MyObject::constructor; 6 | 7 | MyObject::MyObject(double value) : value_(value) { 8 | } 9 | 10 | MyObject::~MyObject() { 11 | } 12 | 13 | void MyObject::Init(Handle exports) { 14 | Isolate* isolate = Isolate::GetCurrent(); 15 | 16 | // Prepare constructor template 17 | Local tpl = FunctionTemplate::New(isolate, New); 18 | tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); 19 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 20 | 21 | // Prototype 22 | NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); 23 | 24 | constructor.Reset(isolate, tpl->GetFunction()); 25 | exports->Set(String::NewFromUtf8(isolate, "MyObject"), 26 | tpl->GetFunction()); 27 | } 28 | 29 | void MyObject::New(const FunctionCallbackInfo& args) { 30 | Isolate* isolate = Isolate::GetCurrent(); 31 | HandleScope scope(isolate); 32 | 33 | if (args.IsConstructCall()) { 34 | // Invoked as constructor: `new MyObject(...)` 35 | double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 36 | MyObject* obj = new MyObject(value); 37 | obj->Wrap(args.This()); 38 | args.GetReturnValue().Set(args.This()); 39 | } else { 40 | // Invoked as plain function `MyObject(...)`, turn into construct call. 41 | const int argc = 1; 42 | Local argv[argc] = { args[0] }; 43 | Local cons = Local::New(isolate, constructor); 44 | args.GetReturnValue().Set(cons->NewInstance(argc, argv)); 45 | } 46 | } 47 | 48 | void MyObject::GetValue(const FunctionCallbackInfo& args) { 49 | Isolate* isolate = Isolate::GetCurrent(); 50 | HandleScope scope(isolate); 51 | MyObject* obj = ObjectWrap::Unwrap(args.Holder()); 52 | args.GetReturnValue().Set(Number::New(isolate, obj->value_)); 53 | } 54 | 55 | void MyObject::PlusOne(const FunctionCallbackInfo& args) { 56 | Isolate* isolate = Isolate::GetCurrent(); 57 | HandleScope scope(isolate); 58 | 59 | MyObject* obj = ObjectWrap::Unwrap(args.Holder()); 60 | obj->value_ += 1; 61 | 62 | args.GetReturnValue().Set(Number::New(isolate, obj->value_)); 63 | } 64 | 65 | void MyObject::Multiply(const FunctionCallbackInfo& args) { 66 | Isolate* isolate = Isolate::GetCurrent(); 67 | HandleScope scope(isolate); 68 | 69 | MyObject* obj = ObjectWrap::Unwrap(args.Holder()); 70 | double multiple = args[0]->IsUndefined() ? 1 : args[0]->NumberValue(); 71 | 72 | const int argc = 1; 73 | Local argv[argc] = { Number::New(isolate, obj->value_ * multiple) }; 74 | 75 | Local cons = Local::New(isolate, constructor); 76 | args.GetReturnValue().Set(cons->NewInstance(argc, argv)); 77 | } 78 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.12/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | #include 6 | 7 | class MyObject : public node::ObjectWrap { 8 | public: 9 | static void Init(v8::Handle exports); 10 | 11 | private: 12 | explicit MyObject(double value = 0); 13 | ~MyObject(); 14 | 15 | static void New(const v8::FunctionCallbackInfo& args); 16 | static void GetValue(const v8::FunctionCallbackInfo& args); 17 | static void PlusOne(const v8::FunctionCallbackInfo& args); 18 | static void Multiply(const v8::FunctionCallbackInfo& args); 19 | static v8::Persistent constructor; 20 | double value_; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /6_object_wrap/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "object_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #6", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /7_factory_wrap/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | void CreateObject(const Nan::FunctionCallbackInfo& info) { 5 | info.GetReturnValue().Set(MyObject::NewInstance(info[0])); 6 | } 7 | 8 | void InitAll(v8::Local exports, v8::Local module) { 9 | Nan::HandleScope scope; 10 | 11 | MyObject::Init(); 12 | 13 | module->Set(Nan::New("exports").ToLocalChecked(), 14 | Nan::New(CreateObject)->GetFunction()); 15 | } 16 | 17 | NODE_MODULE(addon, InitAll) 18 | -------------------------------------------------------------------------------- /7_factory_wrap/nan/addon.js: -------------------------------------------------------------------------------- 1 | var createObject = require('bindings')('addon'); 2 | 3 | var obj = createObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | var obj2 = createObject(20); 9 | console.log( obj2.plusOne() ); // 21 10 | console.log( obj2.plusOne() ); // 22 11 | console.log( obj2.plusOne() ); // 23 12 | -------------------------------------------------------------------------------- /7_factory_wrap/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ], 6 | "include_dirs": [ 7 | " 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | MyObject::MyObject() {}; 7 | MyObject::~MyObject() {}; 8 | 9 | Nan::Persistent MyObject::constructor; 10 | 11 | void MyObject::Init() { 12 | Nan::HandleScope scope; 13 | 14 | // Prepare constructor template 15 | v8::Local tpl = Nan::New(New); 16 | tpl->SetClassName(Nan::New("MyObject").ToLocalChecked()); 17 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 18 | // Prototype 19 | tpl->PrototypeTemplate()->Set(Nan::New("plusOne").ToLocalChecked(), 20 | Nan::New(PlusOne)->GetFunction()); 21 | 22 | constructor.Reset(tpl->GetFunction()); 23 | } 24 | 25 | void MyObject::New(const Nan::FunctionCallbackInfo& info) { 26 | MyObject* obj = new MyObject(); 27 | obj->counter_ = info[0]->IsUndefined() ? 0 : info[0]->NumberValue(); 28 | obj->Wrap(info.This()); 29 | 30 | info.GetReturnValue().Set(info.This()); 31 | } 32 | 33 | 34 | v8::Local MyObject::NewInstance(v8::Local arg) { 35 | Nan::EscapableHandleScope scope; 36 | 37 | const unsigned argc = 1; 38 | v8::Local argv[argc] = { arg }; 39 | v8::Local cons = Nan::New(constructor); 40 | v8::Local instance = cons->NewInstance(argc, argv); 41 | 42 | return scope.Escape(instance); 43 | } 44 | 45 | void MyObject::PlusOne(const Nan::FunctionCallbackInfo& info) { 46 | MyObject* obj = ObjectWrap::Unwrap(info.This()); 47 | obj->counter_ += 1; 48 | 49 | info.GetReturnValue().Set(Nan::New(obj->counter_)); 50 | } 51 | -------------------------------------------------------------------------------- /7_factory_wrap/nan/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public Nan::ObjectWrap { 7 | public: 8 | static void Init(); 9 | static v8::Local NewInstance(v8::Local arg); 10 | 11 | private: 12 | MyObject(); 13 | ~MyObject(); 14 | 15 | static Nan::Persistent constructor; 16 | static void New(const Nan::FunctionCallbackInfo& info); 17 | static void PlusOne(const Nan::FunctionCallbackInfo& info); 18 | double counter_; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /7_factory_wrap/nan/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "factory_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #7", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "nan": "^2.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /7_factory_wrap/napi/addon.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include 3 | 4 | napi_value CreateObject(napi_env env, napi_callback_info info) { 5 | napi_status status; 6 | 7 | size_t argc = 1; 8 | napi_value args[1]; 9 | status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 10 | assert(status == napi_ok); 11 | 12 | napi_value instance; 13 | status = MyObject::NewInstance(env, args[0], &instance); 14 | assert(status == napi_ok); 15 | 16 | return instance; 17 | } 18 | 19 | napi_value Init(napi_env env, napi_value exports) { 20 | napi_status status = MyObject::Init(env); 21 | assert(status == napi_ok); 22 | 23 | napi_value new_exports; 24 | status = 25 | napi_create_function(env, "", NAPI_AUTO_LENGTH, CreateObject, nullptr, &new_exports); 26 | assert(status == napi_ok); 27 | return new_exports; 28 | } 29 | 30 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 31 | -------------------------------------------------------------------------------- /7_factory_wrap/napi/addon.js: -------------------------------------------------------------------------------- 1 | var createObject = require('bindings')('addon'); 2 | 3 | var obj = createObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | var obj2 = createObject(20); 9 | console.log( obj2.plusOne() ); // 21 10 | console.log( obj2.plusOne() ); // 22 11 | console.log( obj2.plusOne() ); // 23 12 | -------------------------------------------------------------------------------- /7_factory_wrap/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /7_factory_wrap/napi/myobject.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include 3 | 4 | MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} 5 | 6 | MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } 7 | 8 | void MyObject::Destructor(napi_env env, void* nativeObject, void* /*finalize_hint*/) { 9 | reinterpret_cast(nativeObject)->~MyObject(); 10 | } 11 | 12 | #define DECLARE_NAPI_METHOD(name, func) \ 13 | { name, 0, func, 0, 0, 0, napi_default, 0 } 14 | 15 | napi_ref MyObject::constructor; 16 | 17 | napi_status MyObject::Init(napi_env env) { 18 | napi_status status; 19 | napi_property_descriptor properties[] = { 20 | DECLARE_NAPI_METHOD("plusOne", PlusOne), 21 | }; 22 | 23 | napi_value cons; 24 | status = 25 | napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 1, properties, &cons); 26 | if (status != napi_ok) return status; 27 | 28 | status = napi_create_reference(env, cons, 1, &constructor); 29 | if (status != napi_ok) return status; 30 | 31 | return napi_ok; 32 | } 33 | 34 | napi_value MyObject::New(napi_env env, napi_callback_info info) { 35 | napi_status status; 36 | 37 | size_t argc = 1; 38 | napi_value args[1]; 39 | napi_value jsthis; 40 | status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); 41 | assert(status == napi_ok); 42 | 43 | napi_valuetype valuetype; 44 | status = napi_typeof(env, args[0], &valuetype); 45 | assert(status == napi_ok); 46 | 47 | MyObject* obj = new MyObject(); 48 | 49 | if (valuetype == napi_undefined) { 50 | obj->counter_ = 0; 51 | } else { 52 | status = napi_get_value_double(env, args[0], &obj->counter_); 53 | assert(status == napi_ok); 54 | } 55 | 56 | obj->env_ = env; 57 | status = napi_wrap(env, 58 | jsthis, 59 | reinterpret_cast(obj), 60 | MyObject::Destructor, 61 | nullptr, /* finalize_hint */ 62 | &obj->wrapper_); 63 | assert(status == napi_ok); 64 | 65 | return jsthis; 66 | } 67 | 68 | napi_status MyObject::NewInstance(napi_env env, 69 | napi_value arg, 70 | napi_value* instance) { 71 | napi_status status; 72 | 73 | const int argc = 1; 74 | napi_value argv[argc] = {arg}; 75 | 76 | napi_value cons; 77 | status = napi_get_reference_value(env, constructor, &cons); 78 | if (status != napi_ok) return status; 79 | 80 | status = napi_new_instance(env, cons, argc, argv, instance); 81 | if (status != napi_ok) return status; 82 | 83 | return napi_ok; 84 | } 85 | 86 | napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) { 87 | napi_status status; 88 | 89 | napi_value jsthis; 90 | status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr); 91 | assert(status == napi_ok); 92 | 93 | MyObject* obj; 94 | status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); 95 | assert(status == napi_ok); 96 | 97 | obj->counter_ += 1; 98 | 99 | napi_value num; 100 | status = napi_create_double(env, obj->counter_, &num); 101 | assert(status == napi_ok); 102 | 103 | return num; 104 | } 105 | -------------------------------------------------------------------------------- /7_factory_wrap/napi/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_ADDONS_NAPI_7_FACTORY_WRAP_MYOBJECT_H_ 2 | #define TEST_ADDONS_NAPI_7_FACTORY_WRAP_MYOBJECT_H_ 3 | 4 | #include 5 | 6 | class MyObject { 7 | public: 8 | static napi_status Init(napi_env env); 9 | static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 10 | static napi_status NewInstance(napi_env env, 11 | napi_value arg, 12 | napi_value* instance); 13 | 14 | private: 15 | MyObject(); 16 | ~MyObject(); 17 | 18 | static napi_ref constructor; 19 | static napi_value New(napi_env env, napi_callback_info info); 20 | static napi_value PlusOne(napi_env env, napi_callback_info info); 21 | double counter_; 22 | napi_env env_; 23 | napi_ref wrapper_; 24 | }; 25 | 26 | #endif // TEST_ADDONS_NAPI_7_FACTORY_WRAP_MYOBJECT_H_ 27 | -------------------------------------------------------------------------------- /7_factory_wrap/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "factory_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #7", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /7_factory_wrap/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | Napi::Object CreateObject(const Napi::CallbackInfo& info) { 5 | return MyObject::NewInstance(info.Env(), info[0]); 6 | } 7 | 8 | Napi::Object InitAll(Napi::Env env, Napi::Object exports) { 9 | Napi::Object new_exports = Napi::Function::New(env, CreateObject, "CreateObject"); 10 | return MyObject::Init(env, new_exports); 11 | } 12 | 13 | NODE_API_MODULE(addon, InitAll) 14 | -------------------------------------------------------------------------------- /7_factory_wrap/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var createObject = require('bindings')('addon'); 2 | 3 | var obj = createObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | var obj2 = createObject(20); 9 | console.log( obj2.plusOne() ); // 21 10 | console.log( obj2.plusOne() ); // 22 11 | console.log( obj2.plusOne() ); // 23 12 | -------------------------------------------------------------------------------- /7_factory_wrap/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "sources": [ "addon.cc", "myobject.cc" ], 8 | "include_dirs": [ 9 | " 2 | #include 3 | #include "myobject.h" 4 | 5 | using namespace Napi; 6 | 7 | Napi::FunctionReference MyObject::constructor; 8 | 9 | Napi::Object MyObject::Init(Napi::Env env, Napi::Object exports) { 10 | Napi::HandleScope scope(env); 11 | 12 | Napi::Function func = DefineClass(env, "MyObject", { 13 | InstanceMethod("plusOne", &MyObject::PlusOne) 14 | }); 15 | 16 | constructor = Napi::Persistent(func); 17 | constructor.SuppressDestruct(); 18 | 19 | exports.Set("MyObject", func); 20 | return exports; 21 | } 22 | 23 | MyObject::MyObject(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { 24 | Napi::Env env = info.Env(); 25 | Napi::HandleScope scope(env); 26 | 27 | this->counter_ = info[0].As().DoubleValue(); 28 | }; 29 | 30 | Napi::Object MyObject::NewInstance(Napi::Env env, Napi::Value arg) { 31 | Napi::EscapableHandleScope scope(env); 32 | Napi::Object obj = constructor.New({ arg }); 33 | return scope.Escape(napi_value(obj)).ToObject(); 34 | } 35 | 36 | Napi::Value MyObject::PlusOne(const Napi::CallbackInfo& info) { 37 | Napi::Env env = info.Env(); 38 | this->counter_ = this->counter_ + 1; 39 | 40 | return Napi::Number::New(env, this->counter_); 41 | } 42 | -------------------------------------------------------------------------------- /7_factory_wrap/node-addon-api/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public Napi::ObjectWrap { 7 | public: 8 | static Napi::Object Init(Napi::Env env, Napi::Object exports); 9 | static Napi::Object NewInstance(Napi::Env env, Napi::Value arg); 10 | MyObject(const Napi::CallbackInfo& info); 11 | 12 | private: 13 | static Napi::FunctionReference constructor; 14 | Napi::Value PlusOne(const Napi::CallbackInfo& info); 15 | double counter_; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /7_factory_wrap/node-addon-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "factory_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #7", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "node-addon-api": "^1.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.10/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | Handle CreateObject(const Arguments& args) { 7 | HandleScope scope; 8 | return scope.Close(MyObject::NewInstance(args)); 9 | } 10 | 11 | void InitAll(Handle exports, Handle module) { 12 | MyObject::Init(); 13 | 14 | module->Set(String::NewSymbol("exports"), 15 | FunctionTemplate::New(CreateObject)->GetFunction()); 16 | } 17 | 18 | NODE_MODULE(addon, InitAll) 19 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var createObject = require('bindings')('addon'); 2 | 3 | var obj = createObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | var obj2 = createObject(20); 9 | console.log( obj2.plusOne() ); // 21 10 | console.log( obj2.plusOne() ); // 22 11 | console.log( obj2.plusOne() ); // 23 12 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.10/myobject.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | MyObject::MyObject() {}; 7 | MyObject::~MyObject() {}; 8 | 9 | Persistent MyObject::constructor; 10 | 11 | void MyObject::Init() { 12 | // Prepare constructor template 13 | Local tpl = FunctionTemplate::New(New); 14 | tpl->SetClassName(String::NewSymbol("MyObject")); 15 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 16 | // Prototype 17 | tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), 18 | FunctionTemplate::New(PlusOne)->GetFunction()); 19 | 20 | constructor = Persistent::New(tpl->GetFunction()); 21 | } 22 | 23 | Handle MyObject::New(const Arguments& args) { 24 | HandleScope scope; 25 | 26 | MyObject* obj = new MyObject(); 27 | obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 28 | obj->Wrap(args.This()); 29 | 30 | return args.This(); 31 | } 32 | 33 | Handle MyObject::NewInstance(const Arguments& args) { 34 | HandleScope scope; 35 | 36 | const unsigned argc = 1; 37 | Handle argv[argc] = { args[0] }; 38 | Local instance = constructor->NewInstance(argc, argv); 39 | 40 | return scope.Close(instance); 41 | } 42 | 43 | Handle MyObject::PlusOne(const Arguments& args) { 44 | HandleScope scope; 45 | 46 | MyObject* obj = ObjectWrap::Unwrap(args.This()); 47 | obj->counter_ += 1; 48 | 49 | return scope.Close(Number::New(obj->counter_)); 50 | } 51 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.10/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public node::ObjectWrap { 7 | public: 8 | static void Init(); 9 | static v8::Handle NewInstance(const v8::Arguments& args); 10 | 11 | private: 12 | MyObject(); 13 | ~MyObject(); 14 | 15 | static v8::Persistent constructor; 16 | static v8::Handle New(const v8::Arguments& args); 17 | static v8::Handle PlusOne(const v8::Arguments& args); 18 | double counter_; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "factory_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #7", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | void CreateObject(const FunctionCallbackInfo& args) { 7 | Isolate* isolate = Isolate::GetCurrent(); 8 | HandleScope scope(isolate); 9 | MyObject::NewInstance(args); 10 | } 11 | 12 | void InitAll(Handle exports, Handle module) { 13 | MyObject::Init(); 14 | 15 | NODE_SET_METHOD(module, "exports", CreateObject); 16 | } 17 | 18 | NODE_MODULE(addon, InitAll) 19 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var createObject = require('bindings')('addon'); 2 | 3 | var obj = createObject(10); 4 | console.log( obj.plusOne() ); // 11 5 | console.log( obj.plusOne() ); // 12 6 | console.log( obj.plusOne() ); // 13 7 | 8 | var obj2 = createObject(20); 9 | console.log( obj2.plusOne() ); // 21 10 | console.log( obj2.plusOne() ); // 22 11 | console.log( obj2.plusOne() ); // 23 12 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.12/myobject.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | Persistent MyObject::constructor; 7 | 8 | MyObject::MyObject(double value) : value_(value) { 9 | } 10 | 11 | MyObject::~MyObject() { 12 | } 13 | 14 | void MyObject::Init() { 15 | Isolate* isolate = Isolate::GetCurrent(); 16 | // Prepare constructor template 17 | Local tpl = FunctionTemplate::New(isolate, New); 18 | tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); 19 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 20 | 21 | // Prototype 22 | NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); 23 | 24 | constructor.Reset(isolate, tpl->GetFunction()); 25 | } 26 | 27 | void MyObject::New(const FunctionCallbackInfo& args) { 28 | Isolate* isolate = Isolate::GetCurrent(); 29 | HandleScope scope(isolate); 30 | 31 | if (args.IsConstructCall()) { 32 | // Invoked as constructor: `new MyObject(...)` 33 | double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 34 | MyObject* obj = new MyObject(value); 35 | obj->Wrap(args.This()); 36 | args.GetReturnValue().Set(args.This()); 37 | } else { 38 | // Invoked as plain function `MyObject(...)`, turn into construct call. 39 | const int argc = 1; 40 | Local argv[argc] = { args[0] }; 41 | Local cons = Local::New(isolate, constructor); 42 | args.GetReturnValue().Set(cons->NewInstance(argc, argv)); 43 | } 44 | } 45 | 46 | void MyObject::NewInstance(const FunctionCallbackInfo& args) { 47 | Isolate* isolate = Isolate::GetCurrent(); 48 | HandleScope scope(isolate); 49 | 50 | const unsigned argc = 1; 51 | Handle argv[argc] = { args[0] }; 52 | Local cons = Local::New(isolate, constructor); 53 | Local instance = cons->NewInstance(argc, argv); 54 | 55 | args.GetReturnValue().Set(instance); 56 | } 57 | 58 | void MyObject::PlusOne(const FunctionCallbackInfo& args) { 59 | Isolate* isolate = Isolate::GetCurrent(); 60 | HandleScope scope(isolate); 61 | 62 | MyObject* obj = ObjectWrap::Unwrap(args.Holder()); 63 | obj->value_ += 1; 64 | 65 | args.GetReturnValue().Set(Number::New(isolate, obj->value_)); 66 | } 67 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.12/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | #include 6 | 7 | class MyObject : public node::ObjectWrap { 8 | public: 9 | static void Init(); 10 | static void NewInstance(const v8::FunctionCallbackInfo& args); 11 | 12 | private: 13 | explicit MyObject(double value = 0); 14 | ~MyObject(); 15 | 16 | static void New(const v8::FunctionCallbackInfo& args); 17 | static void PlusOne(const v8::FunctionCallbackInfo& args); 18 | static v8::Persistent constructor; 19 | double value_; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /7_factory_wrap/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "factory_wrap", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #7", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /8_passing_wrapped/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | void CreateObject(const Nan::FunctionCallbackInfo& info) { 7 | info.GetReturnValue().Set(MyObject::NewInstance(info[0])); 8 | } 9 | 10 | void Add(const Nan::FunctionCallbackInfo& info) { 11 | MyObject* obj1 = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); 12 | MyObject* obj2 = Nan::ObjectWrap::Unwrap(info[1]->ToObject()); 13 | double sum = obj1->Val() + obj2->Val(); 14 | info.GetReturnValue().Set(Nan::New(sum)); 15 | } 16 | 17 | void InitAll(v8::Local exports) { 18 | MyObject::Init(); 19 | 20 | exports->Set(Nan::New("createObject").ToLocalChecked(), 21 | Nan::New(CreateObject)->GetFunction()); 22 | 23 | exports->Set(Nan::New("add").ToLocalChecked(), 24 | Nan::New(Add)->GetFunction()); 25 | } 26 | 27 | NODE_MODULE(addon, InitAll) 28 | -------------------------------------------------------------------------------- /8_passing_wrapped/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon.createObject(10); 4 | var obj2 = addon.createObject(20); 5 | var result = addon.add(obj1, obj2); 6 | 7 | console.log(result); // 30 8 | -------------------------------------------------------------------------------- /8_passing_wrapped/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ], 6 | "include_dirs": [ 7 | " 2 | #include "myobject.h" 3 | 4 | MyObject::MyObject() {}; 5 | MyObject::~MyObject() {}; 6 | 7 | Nan::Persistent MyObject::constructor; 8 | 9 | void MyObject::Init() { 10 | Nan::HandleScope scope; 11 | 12 | // Prepare constructor template 13 | v8::Local tpl = Nan::New(New); 14 | tpl->SetClassName(Nan::New("MyObject").ToLocalChecked()); 15 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 16 | 17 | constructor.Reset(tpl->GetFunction()); 18 | } 19 | 20 | void MyObject::New(const Nan::FunctionCallbackInfo& info) { 21 | MyObject* obj = new MyObject(); 22 | obj->val_ = info[0]->IsUndefined() ? 0 : info[0]->NumberValue(); 23 | obj->Wrap(info.This()); 24 | 25 | info.GetReturnValue().Set(info.This()); 26 | } 27 | 28 | v8::Local MyObject::NewInstance(v8::Local arg) { 29 | Nan::EscapableHandleScope scope; 30 | 31 | const unsigned argc = 1; 32 | v8::Local argv[argc] = { arg }; 33 | v8::Local cons = Nan::New(constructor); 34 | v8::Local instance = cons->NewInstance(argc, argv); 35 | 36 | return scope.Escape(instance); 37 | } 38 | -------------------------------------------------------------------------------- /8_passing_wrapped/nan/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public Nan::ObjectWrap { 7 | public: 8 | static void Init(); 9 | static v8::Local NewInstance(v8::Local arg); 10 | double Val() const { return val_; } 11 | 12 | private: 13 | MyObject(); 14 | ~MyObject(); 15 | 16 | static Nan::Persistent constructor; 17 | static void New(const Nan::FunctionCallbackInfo& info); 18 | double val_; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /8_passing_wrapped/nan/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passing_wrapped", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #8", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "nan": "^2.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /8_passing_wrapped/napi/addon.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include 3 | 4 | napi_value CreateObject(napi_env env, napi_callback_info info) { 5 | napi_status status; 6 | 7 | size_t argc = 1; 8 | napi_value args[1]; 9 | status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 10 | assert(status == napi_ok); 11 | 12 | napi_value instance; 13 | status = MyObject::NewInstance(env, args[0], &instance); 14 | 15 | return instance; 16 | } 17 | 18 | napi_value Add(napi_env env, napi_callback_info info) { 19 | napi_status status; 20 | 21 | size_t argc = 2; 22 | napi_value args[2]; 23 | status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 24 | assert(status == napi_ok); 25 | 26 | MyObject* obj1; 27 | status = napi_unwrap(env, args[0], reinterpret_cast(&obj1)); 28 | assert(status == napi_ok); 29 | 30 | MyObject* obj2; 31 | status = napi_unwrap(env, args[1], reinterpret_cast(&obj2)); 32 | assert(status == napi_ok); 33 | 34 | napi_value sum; 35 | status = napi_create_double(env, obj1->Val() + obj2->Val(), &sum); 36 | assert(status == napi_ok); 37 | 38 | return sum; 39 | } 40 | 41 | #define DECLARE_NAPI_METHOD(name, func) \ 42 | { name, 0, func, 0, 0, 0, napi_default, 0 } 43 | 44 | napi_value Init(napi_env env, napi_value exports) { 45 | napi_status status; 46 | 47 | MyObject::Init(env); 48 | 49 | napi_property_descriptor desc[] = { 50 | DECLARE_NAPI_METHOD("createObject", CreateObject), 51 | DECLARE_NAPI_METHOD("add", Add), 52 | }; 53 | status = 54 | napi_define_properties(env, exports, sizeof(desc) / sizeof(*desc), desc); 55 | assert(status == napi_ok); 56 | return exports; 57 | } 58 | 59 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 60 | -------------------------------------------------------------------------------- /8_passing_wrapped/napi/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon.createObject(10); 4 | var obj2 = addon.createObject(20); 5 | var result = addon.add(obj1, obj2); 6 | 7 | console.log(result); // 30 8 | -------------------------------------------------------------------------------- /8_passing_wrapped/napi/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /8_passing_wrapped/napi/myobject.cc: -------------------------------------------------------------------------------- 1 | #include "myobject.h" 2 | #include 3 | 4 | MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} 5 | 6 | MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } 7 | 8 | void MyObject::Destructor(napi_env env, void* nativeObject, void* /*finalize_hint*/) { 9 | reinterpret_cast(nativeObject)->~MyObject(); 10 | } 11 | 12 | napi_ref MyObject::constructor; 13 | 14 | napi_status MyObject::Init(napi_env env) { 15 | napi_status status; 16 | 17 | napi_value cons; 18 | status = napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 0, nullptr, &cons); 19 | if (status != napi_ok) return status; 20 | 21 | status = napi_create_reference(env, cons, 1, &constructor); 22 | if (status != napi_ok) return status; 23 | 24 | return napi_ok; 25 | } 26 | 27 | napi_value MyObject::New(napi_env env, napi_callback_info info) { 28 | napi_status status; 29 | 30 | size_t argc = 1; 31 | napi_value args[1]; 32 | napi_value jsthis; 33 | status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); 34 | assert(status == napi_ok); 35 | 36 | MyObject* obj = new MyObject(); 37 | 38 | napi_valuetype valuetype; 39 | status = napi_typeof(env, args[0], &valuetype); 40 | assert(status == napi_ok); 41 | 42 | if (valuetype == napi_undefined) { 43 | obj->val_ = 0; 44 | } else { 45 | status = napi_get_value_double(env, args[0], &obj->val_); 46 | assert(status == napi_ok); 47 | } 48 | 49 | obj->env_ = env; 50 | status = napi_wrap(env, 51 | jsthis, 52 | reinterpret_cast(obj), 53 | MyObject::Destructor, 54 | nullptr, // finalize_hint 55 | &obj->wrapper_); 56 | assert(status == napi_ok); 57 | 58 | return jsthis; 59 | } 60 | 61 | napi_status MyObject::NewInstance(napi_env env, 62 | napi_value arg, 63 | napi_value* instance) { 64 | napi_status status; 65 | 66 | const int argc = 1; 67 | napi_value argv[argc] = {arg}; 68 | 69 | napi_value cons; 70 | status = napi_get_reference_value(env, constructor, &cons); 71 | if (status != napi_ok) return status; 72 | 73 | status = napi_new_instance(env, cons, argc, argv, instance); 74 | if (status != napi_ok) return status; 75 | 76 | return napi_ok; 77 | } 78 | -------------------------------------------------------------------------------- /8_passing_wrapped/napi/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_ADDONS_NAPI_8_PASSING_WRAPPED_MYOBJECT_H_ 2 | #define TEST_ADDONS_NAPI_8_PASSING_WRAPPED_MYOBJECT_H_ 3 | 4 | #include 5 | 6 | class MyObject { 7 | public: 8 | static napi_status Init(napi_env env); 9 | static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 10 | static napi_status NewInstance(napi_env env, 11 | napi_value arg, 12 | napi_value* instance); 13 | double Val() const { return val_; } 14 | 15 | private: 16 | MyObject(); 17 | ~MyObject(); 18 | 19 | static napi_ref constructor; 20 | static napi_value New(napi_env env, napi_callback_info info); 21 | double val_; 22 | napi_env env_; 23 | napi_ref wrapper_; 24 | }; 25 | 26 | #endif // TEST_ADDONS_NAPI_8_PASSING_WRAPPED_MYOBJECT_H_ 27 | -------------------------------------------------------------------------------- /8_passing_wrapped/napi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passing_wrapped", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #8", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /8_passing_wrapped/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace Napi; 5 | 6 | Napi::Object CreateObject(const Napi::CallbackInfo& info) { 7 | return MyObject::NewInstance(info[0]); 8 | } 9 | 10 | Napi::Number Add(const Napi::CallbackInfo& info) { 11 | Napi::Env env = info.Env(); 12 | MyObject* obj1 = Napi::ObjectWrap::Unwrap(info[0].As()); 13 | MyObject* obj2 = Napi::ObjectWrap::Unwrap(info[1].As()); 14 | double sum = obj1->Val() + obj2->Val(); 15 | return Napi::Number::New(env, sum); 16 | } 17 | 18 | 19 | Napi::Object InitAll(Napi::Env env, Napi::Object exports) { 20 | MyObject::Init(env, exports); 21 | 22 | exports.Set(Napi::String::New(env, "createObject"), 23 | Napi::Function::New(env, CreateObject)); 24 | 25 | exports.Set(Napi::String::New(env, "add"), 26 | Napi::Function::New(env, Add)); 27 | 28 | return exports; 29 | } 30 | 31 | NODE_API_MODULE(addon, InitAll) 32 | -------------------------------------------------------------------------------- /8_passing_wrapped/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon.createObject(10); 4 | var obj2 = addon.createObject(20); 5 | var result = addon.add(obj1, obj2); 6 | 7 | console.log(result); // 30 8 | -------------------------------------------------------------------------------- /8_passing_wrapped/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "cflags!": [ "-fno-exceptions" ], 6 | "cflags_cc!": [ "-fno-exceptions" ], 7 | "cflags!": [ "-fno-exceptions" ], 8 | "cflags_cc!": [ "-fno-exceptions" ], 9 | "sources": [ "addon.cc", "myobject.cc" ], 10 | "include_dirs": [ 11 | " 2 | #include 3 | #include "myobject.h" 4 | 5 | MyObject::MyObject(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { 6 | Napi::Env env = info.Env(); 7 | Napi::HandleScope scope(env); 8 | 9 | this->val_ = info[0].As().DoubleValue(); 10 | }; 11 | 12 | Napi::FunctionReference MyObject::constructor; 13 | 14 | void MyObject::Init(Napi::Env env, Napi::Object exports) { 15 | Napi::HandleScope scope(env); 16 | 17 | Napi::Function func = DefineClass(env, "MyObject", {}); 18 | 19 | constructor = Napi::Persistent(func); 20 | constructor.SuppressDestruct(); 21 | 22 | exports.Set("MyObject", func); 23 | } 24 | 25 | Napi::Object MyObject::NewInstance(Napi::Value arg) { 26 | Napi::Object obj = constructor.New({ arg }); 27 | return obj; 28 | } 29 | -------------------------------------------------------------------------------- /8_passing_wrapped/node-addon-api/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public Napi::ObjectWrap { 7 | public: 8 | static void Init(Napi::Env env, Napi::Object exports); 9 | static Napi::Object NewInstance(Napi::Value arg); 10 | double Val() const { return val_; } 11 | MyObject(const Napi::CallbackInfo& info); 12 | 13 | private: 14 | static Napi::FunctionReference constructor; 15 | double val_; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /8_passing_wrapped/node-addon-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passing_wrapped", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #8", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1", 10 | "node-addon-api": "^1.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.10/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | Handle CreateObject(const Arguments& args) { 7 | HandleScope scope; 8 | return scope.Close(MyObject::NewInstance(args)); 9 | } 10 | 11 | Handle Add(const Arguments& args) { 12 | HandleScope scope; 13 | 14 | MyObject* obj1 = node::ObjectWrap::Unwrap( 15 | args[0]->ToObject()); 16 | MyObject* obj2 = node::ObjectWrap::Unwrap( 17 | args[1]->ToObject()); 18 | 19 | double sum = obj1->Val() + obj2->Val(); 20 | return scope.Close(Number::New(sum)); 21 | } 22 | 23 | void InitAll(Handle exports) { 24 | MyObject::Init(); 25 | 26 | exports->Set(String::NewSymbol("createObject"), 27 | FunctionTemplate::New(CreateObject)->GetFunction()); 28 | 29 | exports->Set(String::NewSymbol("add"), 30 | FunctionTemplate::New(Add)->GetFunction()); 31 | } 32 | 33 | NODE_MODULE(addon, InitAll) 34 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.10/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon.createObject(10); 4 | var obj2 = addon.createObject(20); 5 | var result = addon.add(obj1, obj2); 6 | 7 | console.log(result); // 30 8 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.10/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.10/myobject.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | MyObject::MyObject() {}; 7 | MyObject::~MyObject() {}; 8 | 9 | Persistent MyObject::constructor; 10 | 11 | void MyObject::Init() { 12 | // Prepare constructor template 13 | Local tpl = FunctionTemplate::New(New); 14 | tpl->SetClassName(String::NewSymbol("MyObject")); 15 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 16 | 17 | constructor = Persistent::New(tpl->GetFunction()); 18 | } 19 | 20 | Handle MyObject::New(const Arguments& args) { 21 | HandleScope scope; 22 | 23 | MyObject* obj = new MyObject(); 24 | obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 25 | obj->Wrap(args.This()); 26 | 27 | return args.This(); 28 | } 29 | 30 | Handle MyObject::NewInstance(const Arguments& args) { 31 | HandleScope scope; 32 | 33 | const unsigned argc = 1; 34 | Handle argv[argc] = { args[0] }; 35 | Local instance = constructor->NewInstance(argc, argv); 36 | 37 | return scope.Close(instance); 38 | } 39 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.10/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | 6 | class MyObject : public node::ObjectWrap { 7 | public: 8 | static void Init(); 9 | static v8::Handle NewInstance(const v8::Arguments& args); 10 | double Val() const { return val_; } 11 | 12 | private: 13 | MyObject(); 14 | ~MyObject(); 15 | 16 | static v8::Persistent constructor; 17 | static v8::Handle New(const v8::Arguments& args); 18 | double val_; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passing_wrapped", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #8", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.12/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "myobject.h" 4 | 5 | using namespace v8; 6 | 7 | void CreateObject(const FunctionCallbackInfo& args) { 8 | Isolate* isolate = Isolate::GetCurrent(); 9 | HandleScope scope(isolate); 10 | MyObject::NewInstance(args); 11 | } 12 | 13 | void Add(const FunctionCallbackInfo& args) { 14 | Isolate* isolate = Isolate::GetCurrent(); 15 | HandleScope scope(isolate); 16 | 17 | MyObject* obj1 = node::ObjectWrap::Unwrap( 18 | args[0]->ToObject()); 19 | MyObject* obj2 = node::ObjectWrap::Unwrap( 20 | args[1]->ToObject()); 21 | 22 | double sum = obj1->value() + obj2->value(); 23 | args.GetReturnValue().Set(Number::New(isolate, sum)); 24 | } 25 | 26 | void InitAll(Handle exports) { 27 | MyObject::Init(); 28 | 29 | NODE_SET_METHOD(exports, "createObject", CreateObject); 30 | NODE_SET_METHOD(exports, "add", Add); 31 | } 32 | 33 | NODE_MODULE(addon, InitAll) 34 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.12/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | 3 | var obj1 = addon.createObject(10); 4 | var obj2 = addon.createObject(20); 5 | var result = addon.add(obj1, obj2); 6 | 7 | console.log(result); // 30 8 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.12/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ "addon.cc", "myobject.cc" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.12/myobject.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "myobject.h" 3 | 4 | using namespace v8; 5 | 6 | Persistent MyObject::constructor; 7 | 8 | MyObject::MyObject(double value) : value_(value) { 9 | } 10 | 11 | MyObject::~MyObject() { 12 | } 13 | 14 | void MyObject::Init() { 15 | Isolate* isolate = Isolate::GetCurrent(); 16 | 17 | // Prepare constructor template 18 | Local tpl = FunctionTemplate::New(isolate, New); 19 | tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); 20 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 21 | 22 | constructor.Reset(isolate, tpl->GetFunction()); 23 | } 24 | 25 | void MyObject::New(const FunctionCallbackInfo& args) { 26 | Isolate* isolate = Isolate::GetCurrent(); 27 | HandleScope scope(isolate); 28 | 29 | if (args.IsConstructCall()) { 30 | // Invoked as constructor: `new MyObject(...)` 31 | double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 32 | MyObject* obj = new MyObject(value); 33 | obj->Wrap(args.This()); 34 | args.GetReturnValue().Set(args.This()); 35 | } else { 36 | // Invoked as plain function `MyObject(...)`, turn into construct call. 37 | const int argc = 1; 38 | Local argv[argc] = { args[0] }; 39 | Local cons = Local::New(isolate, constructor); 40 | args.GetReturnValue().Set(cons->NewInstance(argc, argv)); 41 | } 42 | } 43 | 44 | void MyObject::NewInstance(const FunctionCallbackInfo& args) { 45 | Isolate* isolate = Isolate::GetCurrent(); 46 | HandleScope scope(isolate); 47 | 48 | const unsigned argc = 1; 49 | Handle argv[argc] = { args[0] }; 50 | Local cons = Local::New(isolate, constructor); 51 | Local instance = cons->NewInstance(argc, argv); 52 | 53 | args.GetReturnValue().Set(instance); 54 | } 55 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.12/myobject.h: -------------------------------------------------------------------------------- 1 | #ifndef MYOBJECT_H 2 | #define MYOBJECT_H 3 | 4 | #include 5 | #include 6 | 7 | class MyObject : public node::ObjectWrap { 8 | public: 9 | static void Init(); 10 | static void NewInstance(const v8::FunctionCallbackInfo& args); 11 | inline double value() const { return value_; } 12 | 13 | private: 14 | explicit MyObject(double value = 0); 15 | ~MyObject(); 16 | 17 | static void New(const v8::FunctionCallbackInfo& args); 18 | static v8::Persistent constructor; 19 | double value_; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /8_passing_wrapped/node_0.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passing_wrapped", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons Example #8", 5 | "main": "addon.js", 6 | "private": true, 7 | "gypfile": true, 8 | "dependencies": { 9 | "bindings": "~1.2.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Node.js Addon Examples - ABI Stable PoC 2 | ========================================= 3 | 4 | This repository is the home of the Addon Examples as extended 5 | for the proof of concept work being done to develop an ABI 6 | stable API for use my node modules. 7 | 8 | For more details please read the node-eps covering this effort. 9 | The current PR for the eps is: https://github.com/nodejs/node-eps/pull/20 10 | 11 | ```text 12 | $ sudo npm install node-gyp -g 13 | ``` 14 | 15 | In each example directory, run: 16 | 17 | ```text 18 | $ npm install 19 | $ node-gyp rebuild 20 | $ node ./ 21 | ``` 22 | -------------------------------------------------------------------------------- /async_pi_estimate/nan/README.md: -------------------------------------------------------------------------------- 1 | In this directory run `node-gyp rebuild` and then `node ./addon.js` -------------------------------------------------------------------------------- /async_pi_estimate/nan/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sync.h" // NOLINT(build/include) 3 | #include "async.h" // NOLINT(build/include) 4 | 5 | using v8::FunctionTemplate; 6 | using v8::Handle; 7 | using v8::Object; 8 | using v8::String; 9 | using Nan::GetFunction; 10 | using Nan::New; 11 | using Nan::Set; 12 | 13 | // Expose synchronous and asynchronous access to our 14 | // Estimate() function 15 | NAN_MODULE_INIT(InitAll) { 16 | Set(target, New("calculateSync").ToLocalChecked(), 17 | GetFunction(New(CalculateSync)).ToLocalChecked()); 18 | 19 | Set(target, New("calculateAsync").ToLocalChecked(), 20 | GetFunction(New(CalculateAsync)).ToLocalChecked()); 21 | } 22 | 23 | NODE_MODULE(addon, InitAll) -------------------------------------------------------------------------------- /async_pi_estimate/nan/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('./build/Release/addon'); 2 | var calculations = process.argv[2] || 100000000; 3 | 4 | function printResult(type, pi, ms) { 5 | console.log(type, 'method:'); 6 | console.log('\tπ ≈ ' + pi + 7 | ' (' + Math.abs(pi - Math.PI) + ' away from actual)'); 8 | console.log('\tTook ' + ms + 'ms'); 9 | console.log(); 10 | } 11 | 12 | function runSync() { 13 | var start = Date.now(); 14 | // Estimate() will execute in the current thread, 15 | // the next line won't return until it is finished 16 | var result = addon.calculateSync(calculations); 17 | printResult('Sync', result, Date.now() - start); 18 | } 19 | 20 | function runAsync() { 21 | // how many batches should we split the work in to? 22 | var batches = process.argv[3] || 16; 23 | var ended = 0; 24 | var total = 0; 25 | var start = Date.now(); 26 | 27 | function done (err, result) { 28 | total += result; 29 | 30 | // have all the batches finished executing? 31 | if (++ended === batches) { 32 | printResult('Async', total / batches, Date.now() - start); 33 | } 34 | } 35 | 36 | // for each batch of work, request an async Estimate() for 37 | // a portion of the total number of calculations 38 | for (var i = 0; i < batches; i++) { 39 | addon.calculateAsync(calculations / batches, done); 40 | } 41 | } 42 | 43 | runSync(); 44 | runAsync(); -------------------------------------------------------------------------------- /async_pi_estimate/nan/async.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pi_est.h" // NOLINT(build/include) 3 | #include "async.h" // NOLINT(build/include) 4 | 5 | using v8::Function; 6 | using v8::Local; 7 | using v8::Number; 8 | using v8::Value; 9 | using Nan::AsyncQueueWorker; 10 | using Nan::AsyncWorker; 11 | using Nan::Callback; 12 | using Nan::HandleScope; 13 | using Nan::New; 14 | using Nan::Null; 15 | using Nan::To; 16 | 17 | class PiWorker : public AsyncWorker { 18 | public: 19 | PiWorker(Callback *callback, int points) 20 | : AsyncWorker(callback), points(points), estimate(0) {} 21 | ~PiWorker() {} 22 | 23 | // Executed inside the worker-thread. 24 | // It is not safe to access V8, or V8 data structures 25 | // here, so everything we need for input and output 26 | // should go on `this`. 27 | void Execute () { 28 | estimate = Estimate(points); 29 | } 30 | 31 | // Executed when the async work is complete 32 | // this function will be run inside the main event loop 33 | // so it is safe to use V8 again 34 | void HandleOKCallback () { 35 | HandleScope scope; 36 | 37 | Local argv[] = { 38 | Null() 39 | , New(estimate) 40 | }; 41 | 42 | callback->Call(2, argv, async_resource); 43 | } 44 | 45 | private: 46 | int points; 47 | double estimate; 48 | }; 49 | 50 | // Asynchronous access to the `Estimate()` function 51 | NAN_METHOD(CalculateAsync) { 52 | int points = To(info[0]).FromJust(); 53 | Callback *callback = new Callback(To(info[1]).ToLocalChecked()); 54 | 55 | AsyncQueueWorker(new PiWorker(callback, points)); 56 | } 57 | -------------------------------------------------------------------------------- /async_pi_estimate/nan/async.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ 2 | #define EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ 3 | 4 | #include 5 | 6 | NAN_METHOD(CalculateAsync); 7 | 8 | #endif // EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ 9 | -------------------------------------------------------------------------------- /async_pi_estimate/nan/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ 6 | "addon.cc", 7 | "pi_est.cc", 8 | "sync.cc", 9 | "async.cc" 10 | ], 11 | "include_dirs": [" 2 | #include "pi_est.h" // NOLINT(build/include) 3 | 4 | /* 5 | Estimate the value of π by using a Monte Carlo method. 6 | Take `points` samples of random x and y values on a 7 | [0,1][0,1] plane. Calculating the length of the diagonal 8 | tells us whether the point lies inside, or outside a 9 | quarter circle running from 0,1 to 1,0. The ratio of the 10 | number of points inside to outside gives us an 11 | approximation of π/4. 12 | 13 | See https://en.wikipedia.org/wiki/File:Pi_30K.gif 14 | for a visualization of how this works. 15 | */ 16 | 17 | inline int randall(unsigned int *p_seed) { 18 | // windows has thread safe rand() 19 | #ifdef _WIN32 20 | return rand(); // NOLINT(runtime/threadsafe_fn) 21 | #else 22 | return rand_r(p_seed); 23 | #endif 24 | } 25 | 26 | double Estimate (int points) { 27 | int i = points; 28 | int inside = 0; 29 | unsigned int randseed = 1; 30 | 31 | #ifdef _WIN32 32 | srand(randseed); 33 | #endif 34 | 35 | // unique seed for each run, for threaded use 36 | unsigned int seed = randall(&randseed); 37 | 38 | #ifdef _WIN32 39 | srand(seed); 40 | #endif 41 | 42 | while (i-- > 0) { 43 | double x = randall(&seed) / static_cast(RAND_MAX); 44 | double y = randall(&seed) / static_cast(RAND_MAX); 45 | 46 | // x & y and now values between 0 and 1 47 | // now do a pythagorean diagonal calculation 48 | // `1` represents our 1/4 circle 49 | if ((x * x) + (y * y) <= 1) 50 | inside++; 51 | } 52 | 53 | // calculate ratio and multiply by 4 for π 54 | return (inside / static_cast(points)) * 4; 55 | } 56 | -------------------------------------------------------------------------------- /async_pi_estimate/nan/pi_est.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ 2 | #define EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ 3 | 4 | double Estimate(int points); 5 | 6 | #endif // EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ 7 | -------------------------------------------------------------------------------- /async_pi_estimate/nan/sync.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pi_est.h" // NOLINT(build/include) 3 | #include "sync.h" // NOLINT(build/include) 4 | 5 | // Simple synchronous access to the `Estimate()` function 6 | NAN_METHOD(CalculateSync) { 7 | // expect a number as the first argument 8 | int points = info[0]->Uint32Value(); 9 | double est = Estimate(points); 10 | 11 | info.GetReturnValue().Set(est); 12 | } 13 | -------------------------------------------------------------------------------- /async_pi_estimate/nan/sync.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ 2 | #define EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ 3 | 4 | #include 5 | 6 | NAN_METHOD(CalculateSync); 7 | 8 | #endif // EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ 9 | -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/README.md: -------------------------------------------------------------------------------- 1 | In this directory run `node-gyp rebuild` and then `node ./addon.js` -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/addon.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sync.h" // NOLINT(build/include) 3 | #include "async.h" // NOLINT(build/include) 4 | 5 | // Expose synchronous and asynchronous access to our 6 | // Estimate() function 7 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 8 | exports.Set(Napi::String::New(env, "calculateSync"), Napi::Function::New(env, CalculateSync)); 9 | exports.Set(Napi::String::New(env, "calculateAsync"), Napi::Function::New(env, CalculateAsync)); 10 | return exports; 11 | } 12 | 13 | NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/addon.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('addon'); 2 | var calculations = process.argv[2] || 100000000; 3 | 4 | function printResult(type, pi, ms) { 5 | console.log(type, 'method:'); 6 | console.log('\tπ ≈ ' + pi + 7 | ' (' + Math.abs(pi - Math.PI) + ' away from actual)'); 8 | console.log('\tTook ' + ms + 'ms'); 9 | console.log(); 10 | } 11 | 12 | function runSync() { 13 | var start = Date.now(); 14 | // Estimate() will execute in the current thread, 15 | // the next line won't return until it is finished 16 | var result = addon.calculateSync(calculations); 17 | printResult('Sync', result, Date.now() - start); 18 | } 19 | 20 | function runAsync() { 21 | // how many batches should we split the work in to? 22 | var batches = process.argv[3] || 16; 23 | var ended = 0; 24 | var total = 0; 25 | var start = Date.now(); 26 | 27 | function done (err, result) { 28 | total += result; 29 | 30 | // have all the batches finished executing? 31 | if (++ended === batches) { 32 | printResult('Async', total / batches, Date.now() - start); 33 | } 34 | } 35 | 36 | // for each batch of work, request an async Estimate() for 37 | // a portion of the total number of calculations 38 | for (var i = 0; i < batches; i++) { 39 | addon.calculateAsync(calculations / batches, done); 40 | } 41 | } 42 | 43 | runSync(); 44 | runAsync(); 45 | -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/async.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pi_est.h" // NOLINT(build/include) 3 | #include "async.h" // NOLINT(build/include) 4 | 5 | class PiWorker : public Napi::AsyncWorker { 6 | public: 7 | PiWorker(Napi::Function& callback, int points) 8 | : Napi::AsyncWorker(callback), points(points), estimate(0) {} 9 | ~PiWorker() {} 10 | 11 | // Executed inside the worker-thread. 12 | // It is not safe to access JS engine data structure 13 | // here, so everything we need for input and output 14 | // should go on `this`. 15 | void Execute () { 16 | estimate = Estimate(points); 17 | } 18 | 19 | // Executed when the async work is complete 20 | // this function will be run inside the main event loop 21 | // so it is safe to use JS engine data again 22 | void OnOK() { 23 | Napi::HandleScope scope(Env()); 24 | Callback().Call({Env().Undefined(), Napi::Number::New(Env(), estimate)}); 25 | } 26 | 27 | private: 28 | int points; 29 | double estimate; 30 | }; 31 | 32 | // Asynchronous access to the `Estimate()` function 33 | Napi::Value CalculateAsync(const Napi::CallbackInfo& info) { 34 | int points = info[0].As().Uint32Value(); 35 | Napi::Function callback = info[1].As(); 36 | PiWorker* piWorker = new PiWorker(callback, points); 37 | piWorker->Queue(); 38 | return info.Env().Undefined(); 39 | } -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/async.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ 2 | #define EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ 3 | 4 | #include 5 | 6 | Napi::Value CalculateAsync(const Napi::CallbackInfo& info); 7 | 8 | #endif // EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ 9 | -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "addon", 5 | "sources": [ 6 | "addon.cc", 7 | "pi_est.cc", 8 | "sync.cc", 9 | "async.cc" 10 | ], 11 | 'cflags!': [ '-fno-exceptions' ], 12 | 'cflags_cc!': [ '-fno-exceptions' ], 13 | 'include_dirs': [" 2 | #include "pi_est.h" // NOLINT(build/include) 3 | 4 | /* 5 | Estimate the value of π by using a Monte Carlo method. 6 | Take `points` samples of random x and y values on a 7 | [0,1][0,1] plane. Calculating the length of the diagonal 8 | tells us whether the point lies inside, or outside a 9 | quarter circle running from 0,1 to 1,0. The ratio of the 10 | number of points inside to outside gives us an 11 | approximation of π/4. 12 | 13 | See https://en.wikipedia.org/wiki/File:Pi_30K.gif 14 | for a visualization of how this works. 15 | */ 16 | 17 | inline int randall(unsigned int *p_seed) { 18 | // windows has thread safe rand() 19 | #ifdef _WIN32 20 | return rand(); // NOLINT(runtime/threadsafe_fn) 21 | #else 22 | return rand_r(p_seed); 23 | #endif 24 | } 25 | 26 | double Estimate (int points) { 27 | int i = points; 28 | int inside = 0; 29 | unsigned int randseed = 1; 30 | 31 | #ifdef _WIN32 32 | srand(randseed); 33 | #endif 34 | 35 | // unique seed for each run, for threaded use 36 | unsigned int seed = randall(&randseed); 37 | 38 | #ifdef _WIN32 39 | srand(seed); 40 | #endif 41 | 42 | while (i-- > 0) { 43 | double x = randall(&seed) / static_cast(RAND_MAX); 44 | double y = randall(&seed) / static_cast(RAND_MAX); 45 | 46 | // x & y and now values between 0 and 1 47 | // now do a pythagorean diagonal calculation 48 | // `1` represents our 1/4 circle 49 | if ((x * x) + (y * y) <= 1) 50 | inside++; 51 | } 52 | 53 | // calculate ratio and multiply by 4 for π 54 | return (inside / static_cast(points)) * 4; 55 | } -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/pi_est.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ 2 | #define EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ 3 | 4 | double Estimate(int points); 5 | 6 | #endif // EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ 7 | -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/sync.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pi_est.h" // NOLINT(build/include) 3 | #include "sync.h" // NOLINT(build/include) 4 | 5 | // Simple synchronous access to the `Estimate()` function 6 | Napi::Value CalculateSync(const Napi::CallbackInfo& info) { 7 | // expect a number as the first argument 8 | int points = info[0].As().Uint32Value(); 9 | double est = Estimate(points); 10 | 11 | return Napi::Number::New(info.Env(), est); 12 | } 13 | -------------------------------------------------------------------------------- /async_pi_estimate/node-addon-api/sync.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ 2 | #define EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ 3 | 4 | #include 5 | 6 | Napi::Value CalculateSync(const Napi::CallbackInfo& info); 7 | 8 | #endif // EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ 9 | -------------------------------------------------------------------------------- /emit_event_from_cpp/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "emit_from_cpp", 5 | "sources": [ 6 | "src/emit-from-cpp.cc" 7 | ], 8 | 'cflags!': [ '-fno-exceptions' ], 9 | 'cflags_cc!': [ '-fno-exceptions' ], 10 | 'include_dirs': [" { 9 | console.log('### START ...') 10 | }) 11 | emitter.on('data', (evt) => { 12 | console.log(evt); 13 | }) 14 | 15 | emitter.on('end', () => { 16 | console.log('### END ###') 17 | }) 18 | 19 | addon.callEmit(emitter.emit.bind(emitter)) -------------------------------------------------------------------------------- /emit_event_from_cpp/node-addon-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emit-event-from-cpp-example", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons - emit event from C++ to JS", 5 | "main": "index.js", 6 | "private": true, 7 | "gypfile": true, 8 | "scripts": { 9 | "start": "node index.js" 10 | }, 11 | "dependencies": { 12 | "node-addon-api": "*", 13 | "bindings": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /emit_event_from_cpp/node-addon-api/src/emit-from-cpp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | Napi::Value CallEmit(const Napi::CallbackInfo& info) { 8 | Napi::Env env = info.Env(); 9 | Napi::Function emit = info[0].As(); 10 | emit.Call({Napi::String::New(env, "start")}); 11 | for(int i = 0; i < 3; i++) { 12 | std::this_thread::sleep_for(std::chrono::seconds(3)); 13 | emit.Call({Napi::String::New(env, "data"), 14 | Napi::String::New(env, "data ...")}); 15 | } 16 | emit.Call({Napi::String::New(env, "end")}); 17 | return Napi::String::New(env, "OK"); 18 | } 19 | 20 | // Init 21 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 22 | exports.Set(Napi::String::New(env, "callEmit"), 23 | Napi::Function::New(env, CallEmit)); 24 | return exports; 25 | } 26 | 27 | NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init); -------------------------------------------------------------------------------- /inherits_from_event_emitter/node-addon-api/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "native_emitter", 5 | "sources": [ 6 | "src/binding.cc", 7 | "src/native-emitter.cc" 8 | ], 9 | 'cflags!': [ '-fno-exceptions' ], 10 | 'cflags_cc!': [ '-fno-exceptions' ], 11 | 'include_dirs': [" { 12 | console.log('### START ...') 13 | }) 14 | 15 | emitter.on('data', (evt) => { 16 | console.log(evt) 17 | }) 18 | 19 | emitter.on('end', () => { 20 | console.log('### END ###') 21 | }) 22 | 23 | emitter.callAndEmit() -------------------------------------------------------------------------------- /inherits_from_event_emitter/node-addon-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inherits-from-event-emitter-example", 3 | "version": "0.0.0", 4 | "description": "Node.js Addons - inherits from event emitter", 5 | "main": "index.js", 6 | "private": true, 7 | "gypfile": true, 8 | "scripts": { 9 | "start": "node index.js" 10 | }, 11 | "dependencies": { 12 | "node-addon-api": "*", 13 | "bindings": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /inherits_from_event_emitter/node-addon-api/src/binding.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "native-emitter.h" 3 | 4 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 5 | NativeEmitter::Init(env, exports); 6 | return exports; 7 | } 8 | 9 | NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) -------------------------------------------------------------------------------- /inherits_from_event_emitter/node-addon-api/src/native-emitter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "native-emitter.h" 6 | 7 | Napi::FunctionReference NativeEmitter::constructor; 8 | 9 | Napi::Object NativeEmitter::Init(Napi::Env env, Napi::Object exports) { 10 | Napi::HandleScope scope(env); 11 | 12 | Napi::Function func = DefineClass(env, "NativeEmitter", { 13 | InstanceMethod("callAndEmit", &NativeEmitter::CallAndEmit) 14 | }); 15 | 16 | constructor = Napi::Persistent(func); 17 | constructor.SuppressDestruct(); 18 | 19 | exports.Set("NativeEmitter", func); 20 | return exports; 21 | } 22 | 23 | NativeEmitter::NativeEmitter(const Napi::CallbackInfo& info) 24 | : Napi::ObjectWrap(info) { 25 | // NOOP 26 | } 27 | 28 | Napi::Value NativeEmitter::CallAndEmit(const Napi::CallbackInfo& info) { 29 | Napi::Env env = info.Env(); 30 | Napi::Function emit = info.This().As() 31 | .Get("emit").As(); 32 | emit.Call(info.This(), { Napi::String::New(env, "start") }); 33 | for(int i = 0; i < 3; i++) { 34 | std::this_thread::sleep_for(std::chrono::seconds(1)); 35 | emit.Call(info.This(), { Napi::String::New(env, "data"), 36 | Napi::String::New(env, "data ...") }); 37 | } 38 | emit.Call(info.This(), { Napi::String::New(env, "end") }); 39 | return Napi::String::New(env, "OK"); 40 | } -------------------------------------------------------------------------------- /inherits_from_event_emitter/node-addon-api/src/native-emitter.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class NativeEmitter : public Napi::ObjectWrap { 4 | public: 5 | static Napi::Object Init(Napi::Env env, Napi::Object exports); 6 | NativeEmitter(const Napi::CallbackInfo& info); 7 | 8 | private: 9 | static Napi::FunctionReference constructor; 10 | 11 | Napi::Value CallAndEmit(const Napi::CallbackInfo& info); 12 | }; -------------------------------------------------------------------------------- /original_docs_source.md: -------------------------------------------------------------------------------- 1 | *This is the original document from the [joyent/node](https://github.com/joyent/node) repository as docs/api/addons.markdown. This documentation was used as a foundation for some of the documentation and code found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples) repository.* 2 | 3 | *This documentation targets Node 0.10 and prior and is not relevant for Node 0.11 onwards due mainly to major V8 changes.* 4 | 5 | *This document is Copyright Joyent, Inc, Node.js is a trademark of Joyent, Inc. [LICENCE](https://raw.github.com/joyent/node/v0.10.22/LICENSE)* 6 | 7 | # Addons 8 | 9 | Addons are dynamically linked shared objects. They can provide glue to C and 10 | C++ libraries. The API (at the moment) is rather complex, involving 11 | knowledge of several libraries: 12 | 13 | - V8 JavaScript, a C++ library. Used for interfacing with JavaScript: 14 | creating objects, calling functions, etc. Documented mostly in the 15 | `v8.h` header file (`deps/v8/include/v8.h` in the Node source 16 | tree), which is also available 17 | [online](http://izs.me/v8-docs/main.html). 18 | 19 | - [libuv](https://github.com/libuv/libuv), C event loop library. 20 | Anytime one needs to wait for a file descriptor to become readable, 21 | wait for a timer, or wait for a signal to be received one will need 22 | to interface with libuv. That is, if you perform any I/O, libuv will 23 | need to be used. 24 | 25 | - Internal Node libraries. Most importantly is the `node::ObjectWrap` 26 | class which you will likely want to derive from. 27 | 28 | - Others. Look in `deps/` for what else is available. 29 | 30 | Node statically compiles all its dependencies into the executable. 31 | When compiling your module, you don't need to worry about linking to 32 | any of these libraries. 33 | 34 | All of the following examples are available for 35 | [download](https://github.com/rvagg/node-addon-examples) and may be 36 | used as a starting-point for your own Addon. 37 | 38 | ## Hello world 39 | 40 | To get started let's make a small Addon which is the C++ equivalent of 41 | the following JavaScript code: 42 | 43 | module.exports.hello = function() { return 'world'; }; 44 | 45 | First we create a file `hello.cc`: 46 | 47 | #include 48 | #include 49 | 50 | using namespace v8; 51 | 52 | Handle Method(const Arguments& args) { 53 | HandleScope scope; 54 | return scope.Close(String::New("world")); 55 | } 56 | 57 | void init(Handle exports) { 58 | exports->Set(String::NewSymbol("hello"), 59 | FunctionTemplate::New(Method)->GetFunction()); 60 | } 61 | 62 | NODE_MODULE(hello, init) 63 | 64 | Note that all Node addons must export an initialization function: 65 | 66 | void Initialize (Handle exports); 67 | NODE_MODULE(module_name, Initialize) 68 | 69 | There is no semi-colon after `NODE_MODULE` as it's not a function (see `node.h`). 70 | 71 | The `module_name` needs to match the filename of the final binary (minus the 72 | .node suffix). 73 | 74 | The source code needs to be built into `hello.node`, the binary Addon. To 75 | do this we create a file called `binding.gyp` which describes the configuration 76 | to build your module in a JSON-like format. This file gets compiled by 77 | [node-gyp](https://github.com/TooTallNate/node-gyp). 78 | 79 | { 80 | "targets": [ 81 | { 82 | "target_name": "hello", 83 | "sources": [ "hello.cc" ] 84 | } 85 | ] 86 | } 87 | 88 | The next step is to generate the appropriate project build files for the 89 | current platform. Use `node-gyp configure` for that. 90 | 91 | Now you will have either a `Makefile` (on Unix platforms) or a `vcxproj` file 92 | (on Windows) in the `build/` directory. Next invoke the `node-gyp build` 93 | command. 94 | 95 | Now you have your compiled `.node` bindings file! The compiled bindings end up 96 | in `build/Release/`. 97 | 98 | You can now use the binary addon in a Node project `hello.js` by pointing `require` to 99 | the recently built `hello.node` module: 100 | 101 | var addon = require('./build/Release/hello'); 102 | 103 | console.log(addon.hello()); // 'world' 104 | 105 | Please see patterns below for further information or 106 | for an example in production. 107 | 108 | 109 | ## Addon patterns 110 | 111 | Below are some addon patterns to help you get started. Consult the online 112 | [v8 reference](http://izs.me/v8-docs/main.html) for help with the various v8 113 | calls, and v8's [Embedder's Guide](http://code.google.com/apis/v8/embed.html) 114 | for an explanation of several concepts used such as handles, scopes, 115 | function templates, etc. 116 | 117 | In order to use these examples you need to compile them using `node-gyp`. 118 | Create the following `binding.gyp` file: 119 | 120 | { 121 | "targets": [ 122 | { 123 | "target_name": "addon", 124 | "sources": [ "addon.cc" ] 125 | } 126 | ] 127 | } 128 | 129 | In cases where there is more than one `.cc` file, simply add the file name to the 130 | `sources` array, e.g.: 131 | 132 | "sources": ["addon.cc", "myexample.cc"] 133 | 134 | Now that you have your `binding.gyp` ready, you can configure and build the 135 | addon: 136 | 137 | $ node-gyp configure build 138 | 139 | 140 | ### Function arguments 141 | 142 | The following pattern illustrates how to read arguments from JavaScript 143 | function calls and return a result. This is the main and only needed source 144 | `addon.cc`: 145 | 146 | #define BUILDING_NODE_EXTENSION 147 | #include 148 | 149 | using namespace v8; 150 | 151 | Handle Add(const Arguments& args) { 152 | HandleScope scope; 153 | 154 | if (args.Length() < 2) { 155 | ThrowException(Exception::TypeError(String::New("Wrong number of arguments"))); 156 | return scope.Close(Undefined()); 157 | } 158 | 159 | if (!args[0]->IsNumber() || !args[1]->IsNumber()) { 160 | ThrowException(Exception::TypeError(String::New("Wrong arguments"))); 161 | return scope.Close(Undefined()); 162 | } 163 | 164 | Local num = Number::New(args[0]->NumberValue() + 165 | args[1]->NumberValue()); 166 | return scope.Close(num); 167 | } 168 | 169 | void Init(Handle exports) { 170 | exports->Set(String::NewSymbol("add"), 171 | FunctionTemplate::New(Add)->GetFunction()); 172 | } 173 | 174 | NODE_MODULE(addon, Init) 175 | 176 | You can test it with the following JavaScript snippet: 177 | 178 | var addon = require('./build/Release/addon'); 179 | 180 | console.log( 'This should be eight:', addon.add(3,5) ); 181 | 182 | 183 | ### Callbacks 184 | 185 | You can pass JavaScript functions to a C++ function and execute them from 186 | there. Here's `addon.cc`: 187 | 188 | #define BUILDING_NODE_EXTENSION 189 | #include 190 | 191 | using namespace v8; 192 | 193 | Handle RunCallback(const Arguments& args) { 194 | HandleScope scope; 195 | 196 | Local cb = Local::Cast(args[0]); 197 | const unsigned argc = 1; 198 | Local argv[argc] = { Local::New(String::New("hello world")) }; 199 | cb->Call(Context::GetCurrent()->Global(), argc, argv); 200 | 201 | return scope.Close(Undefined()); 202 | } 203 | 204 | void Init(Handle exports, Handle module) { 205 | module->Set(String::NewSymbol("exports"), 206 | FunctionTemplate::New(RunCallback)->GetFunction()); 207 | } 208 | 209 | NODE_MODULE(addon, Init) 210 | 211 | Note that this example uses a two-argument form of `Init()` that receives 212 | the full `module` object as the second argument. This allows the addon 213 | to completely overwrite `exports` with a single function instead of 214 | adding the function as a property of `exports`. 215 | 216 | To test it run the following JavaScript snippet: 217 | 218 | var addon = require('./build/Release/addon'); 219 | 220 | addon(function(msg){ 221 | console.log(msg); // 'hello world' 222 | }); 223 | 224 | 225 | ### Object factory 226 | 227 | You can create and return new objects from within a C++ function with this 228 | `addon.cc` pattern, which returns an object with property `msg` that echoes 229 | the string passed to `createObject()`: 230 | 231 | #define BUILDING_NODE_EXTENSION 232 | #include 233 | 234 | using namespace v8; 235 | 236 | Handle CreateObject(const Arguments& args) { 237 | HandleScope scope; 238 | 239 | Local obj = Object::New(); 240 | obj->Set(String::NewSymbol("msg"), args[0]->ToString()); 241 | 242 | return scope.Close(obj); 243 | } 244 | 245 | void Init(Handle exports, Handle module) { 246 | module->Set(String::NewSymbol("exports"), 247 | FunctionTemplate::New(CreateObject)->GetFunction()); 248 | } 249 | 250 | NODE_MODULE(addon, Init) 251 | 252 | To test it in JavaScript: 253 | 254 | var addon = require('./build/Release/addon'); 255 | 256 | var obj1 = addon('hello'); 257 | var obj2 = addon('world'); 258 | console.log(obj1.msg+' '+obj2.msg); // 'hello world' 259 | 260 | 261 | ### Function factory 262 | 263 | This pattern illustrates how to create and return a JavaScript function that 264 | wraps a C++ function: 265 | 266 | #define BUILDING_NODE_EXTENSION 267 | #include 268 | 269 | using namespace v8; 270 | 271 | Handle MyFunction(const Arguments& args) { 272 | HandleScope scope; 273 | return scope.Close(String::New("hello world")); 274 | } 275 | 276 | Handle CreateFunction(const Arguments& args) { 277 | HandleScope scope; 278 | 279 | Local tpl = FunctionTemplate::New(MyFunction); 280 | Local fn = tpl->GetFunction(); 281 | fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous 282 | 283 | return scope.Close(fn); 284 | } 285 | 286 | void Init(Handle exports, Handle module) { 287 | module->Set(String::NewSymbol("exports"), 288 | FunctionTemplate::New(CreateFunction)->GetFunction()); 289 | } 290 | 291 | NODE_MODULE(addon, Init) 292 | 293 | 294 | To test: 295 | 296 | var addon = require('./build/Release/addon'); 297 | 298 | var fn = addon(); 299 | console.log(fn()); // 'hello world' 300 | 301 | 302 | ### Wrapping C++ objects 303 | 304 | Here we will create a wrapper for a C++ object/class `MyObject` that can be 305 | instantiated in JavaScript through the `new` operator. First prepare the main 306 | module `addon.cc`: 307 | 308 | #define BUILDING_NODE_EXTENSION 309 | #include 310 | #include "myobject.h" 311 | 312 | using namespace v8; 313 | 314 | void InitAll(Handle exports) { 315 | MyObject::Init(exports); 316 | } 317 | 318 | NODE_MODULE(addon, InitAll) 319 | 320 | Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`: 321 | 322 | #ifndef MYOBJECT_H 323 | #define MYOBJECT_H 324 | 325 | #include 326 | 327 | class MyObject : public node::ObjectWrap { 328 | public: 329 | static void Init(v8::Handle exports); 330 | 331 | private: 332 | explicit MyObject(double value = 0); 333 | ~MyObject(); 334 | 335 | static v8::Handle New(const v8::Arguments& args); 336 | static v8::Handle PlusOne(const v8::Arguments& args); 337 | static v8::Persistent constructor; 338 | double value_; 339 | }; 340 | 341 | #endif 342 | 343 | And in `myobject.cc` implement the various methods that you want to expose. 344 | Here we expose the method `plusOne` by adding it to the constructor's 345 | prototype: 346 | 347 | #define BUILDING_NODE_EXTENSION 348 | #include 349 | #include "myobject.h" 350 | 351 | using namespace v8; 352 | 353 | Persistent MyObject::constructor; 354 | 355 | MyObject::MyObject(double value) : value_(value) { 356 | } 357 | 358 | MyObject::~MyObject() { 359 | } 360 | 361 | void MyObject::Init(Handle exports) { 362 | // Prepare constructor template 363 | Local tpl = FunctionTemplate::New(New); 364 | tpl->SetClassName(String::NewSymbol("MyObject")); 365 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 366 | // Prototype 367 | tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), 368 | FunctionTemplate::New(PlusOne)->GetFunction()); 369 | constructor = Persistent::New(tpl->GetFunction()); 370 | exports->Set(String::NewSymbol("MyObject"), constructor); 371 | } 372 | 373 | Handle MyObject::New(const Arguments& args) { 374 | HandleScope scope; 375 | 376 | if (args.IsConstructCall()) { 377 | // Invoked as constructor: `new MyObject(...)` 378 | double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 379 | MyObject* obj = new MyObject(value); 380 | obj->Wrap(args.This()); 381 | return args.This(); 382 | } else { 383 | // Invoked as plain function `MyObject(...)`, turn into construct call. 384 | const int argc = 1; 385 | Local argv[argc] = { args[0] }; 386 | return scope.Close(constructor->NewInstance(argc, argv)); 387 | } 388 | } 389 | 390 | Handle MyObject::PlusOne(const Arguments& args) { 391 | HandleScope scope; 392 | 393 | MyObject* obj = ObjectWrap::Unwrap(args.This()); 394 | obj->value_ += 1; 395 | 396 | return scope.Close(Number::New(obj->value_)); 397 | } 398 | 399 | Test it with: 400 | 401 | var addon = require('./build/Release/addon'); 402 | 403 | var obj = new addon.MyObject(10); 404 | console.log( obj.plusOne() ); // 11 405 | console.log( obj.plusOne() ); // 12 406 | console.log( obj.plusOne() ); // 13 407 | 408 | 409 | ### Factory of wrapped objects 410 | 411 | This is useful when you want to be able to create native objects without 412 | explicitly instantiating them with the `new` operator in JavaScript, e.g. 413 | 414 | var obj = addon.createObject(); 415 | // instead of: 416 | // var obj = new addon.Object(); 417 | 418 | Let's register our `createObject` method in `addon.cc`: 419 | 420 | #define BUILDING_NODE_EXTENSION 421 | #include 422 | #include "myobject.h" 423 | 424 | using namespace v8; 425 | 426 | Handle CreateObject(const Arguments& args) { 427 | HandleScope scope; 428 | return scope.Close(MyObject::NewInstance(args)); 429 | } 430 | 431 | void InitAll(Handle exports, Handle module) { 432 | MyObject::Init(); 433 | 434 | module->Set(String::NewSymbol("exports"), 435 | FunctionTemplate::New(CreateObject)->GetFunction()); 436 | } 437 | 438 | NODE_MODULE(addon, InitAll) 439 | 440 | In `myobject.h` we now introduce the static method `NewInstance` that takes 441 | care of instantiating the object (i.e. it does the job of `new` in JavaScript): 442 | 443 | #define BUILDING_NODE_EXTENSION 444 | #ifndef MYOBJECT_H 445 | #define MYOBJECT_H 446 | 447 | #include 448 | 449 | class MyObject : public node::ObjectWrap { 450 | public: 451 | static void Init(); 452 | static v8::Handle NewInstance(const v8::Arguments& args); 453 | 454 | private: 455 | explicit MyObject(double value = 0); 456 | ~MyObject(); 457 | 458 | static v8::Handle New(const v8::Arguments& args); 459 | static v8::Handle PlusOne(const v8::Arguments& args); 460 | static v8::Persistent constructor; 461 | double value_; 462 | }; 463 | 464 | #endif 465 | 466 | The implementation is similar to the above in `myobject.cc`: 467 | 468 | #define BUILDING_NODE_EXTENSION 469 | #include 470 | #include "myobject.h" 471 | 472 | using namespace v8; 473 | 474 | Persistent MyObject::constructor; 475 | 476 | MyObject::MyObject(double value) : value_(value) { 477 | } 478 | 479 | MyObject::~MyObject() { 480 | } 481 | 482 | void MyObject::Init() { 483 | // Prepare constructor template 484 | Local tpl = FunctionTemplate::New(New); 485 | tpl->SetClassName(String::NewSymbol("MyObject")); 486 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 487 | // Prototype 488 | tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), 489 | FunctionTemplate::New(PlusOne)->GetFunction()); 490 | constructor = Persistent::New(tpl->GetFunction()); 491 | } 492 | 493 | Handle MyObject::New(const Arguments& args) { 494 | HandleScope scope; 495 | 496 | if (args.IsConstructCall()) { 497 | // Invoked as constructor: `new MyObject(...)` 498 | double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 499 | MyObject* obj = new MyObject(value); 500 | obj->Wrap(args.This()); 501 | return args.This(); 502 | } else { 503 | // Invoked as plain function `MyObject(...)`, turn into construct call. 504 | const int argc = 1; 505 | Local argv[argc] = { args[0] }; 506 | return scope.Close(constructor->NewInstance(argc, argv)); 507 | } 508 | } 509 | 510 | Handle MyObject::NewInstance(const Arguments& args) { 511 | HandleScope scope; 512 | 513 | const unsigned argc = 1; 514 | Handle argv[argc] = { args[0] }; 515 | Local instance = constructor->NewInstance(argc, argv); 516 | 517 | return scope.Close(instance); 518 | } 519 | 520 | Handle MyObject::PlusOne(const Arguments& args) { 521 | HandleScope scope; 522 | 523 | MyObject* obj = ObjectWrap::Unwrap(args.This()); 524 | obj->value_ += 1; 525 | 526 | return scope.Close(Number::New(obj->value_)); 527 | } 528 | 529 | Test it with: 530 | 531 | var createObject = require('./build/Release/addon'); 532 | 533 | var obj = createObject(10); 534 | console.log( obj.plusOne() ); // 11 535 | console.log( obj.plusOne() ); // 12 536 | console.log( obj.plusOne() ); // 13 537 | 538 | var obj2 = createObject(20); 539 | console.log( obj2.plusOne() ); // 21 540 | console.log( obj2.plusOne() ); // 22 541 | console.log( obj2.plusOne() ); // 23 542 | 543 | 544 | ### Passing wrapped objects around 545 | 546 | In addition to wrapping and returning C++ objects, you can pass them around 547 | by unwrapping them with Node's `node::ObjectWrap::Unwrap` helper function. 548 | In the following `addon.cc` we introduce a function `add()` that can take on two 549 | `MyObject` objects: 550 | 551 | #define BUILDING_NODE_EXTENSION 552 | #include 553 | #include "myobject.h" 554 | 555 | using namespace v8; 556 | 557 | Handle CreateObject(const Arguments& args) { 558 | HandleScope scope; 559 | return scope.Close(MyObject::NewInstance(args)); 560 | } 561 | 562 | Handle Add(const Arguments& args) { 563 | HandleScope scope; 564 | 565 | MyObject* obj1 = node::ObjectWrap::Unwrap( 566 | args[0]->ToObject()); 567 | MyObject* obj2 = node::ObjectWrap::Unwrap( 568 | args[1]->ToObject()); 569 | 570 | double sum = obj1->Value() + obj2->Value(); 571 | return scope.Close(Number::New(sum)); 572 | } 573 | 574 | void InitAll(Handle exports) { 575 | MyObject::Init(); 576 | 577 | exports->Set(String::NewSymbol("createObject"), 578 | FunctionTemplate::New(CreateObject)->GetFunction()); 579 | 580 | exports->Set(String::NewSymbol("add"), 581 | FunctionTemplate::New(Add)->GetFunction()); 582 | } 583 | 584 | NODE_MODULE(addon, InitAll) 585 | 586 | To make things interesting we introduce a public method in `myobject.h` so we 587 | can probe private values after unwrapping the object: 588 | 589 | #define BUILDING_NODE_EXTENSION 590 | #ifndef MYOBJECT_H 591 | #define MYOBJECT_H 592 | 593 | #include 594 | 595 | class MyObject : public node::ObjectWrap { 596 | public: 597 | static void Init(); 598 | static v8::Handle NewInstance(const v8::Arguments& args); 599 | double Value() const { return value_; } 600 | 601 | private: 602 | explicit MyObject(double value = 0); 603 | ~MyObject(); 604 | 605 | static v8::Handle New(const v8::Arguments& args); 606 | static v8::Persistent constructor; 607 | double value_; 608 | }; 609 | 610 | #endif 611 | 612 | The implementation of `myobject.cc` is similar as before: 613 | 614 | #define BUILDING_NODE_EXTENSION 615 | #include 616 | #include "myobject.h" 617 | 618 | using namespace v8; 619 | 620 | Persistent MyObject::constructor; 621 | 622 | MyObject::MyObject(double value) : value_(value) { 623 | } 624 | 625 | MyObject::~MyObject() { 626 | } 627 | 628 | void MyObject::Init() { 629 | // Prepare constructor template 630 | Local tpl = FunctionTemplate::New(New); 631 | tpl->SetClassName(String::NewSymbol("MyObject")); 632 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 633 | constructor = Persistent::New(tpl->GetFunction()); 634 | } 635 | 636 | Handle MyObject::New(const Arguments& args) { 637 | HandleScope scope; 638 | 639 | if (args.IsConstructCall()) { 640 | // Invoked as constructor: `new MyObject(...)` 641 | double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 642 | MyObject* obj = new MyObject(value); 643 | obj->Wrap(args.This()); 644 | return args.This(); 645 | } else { 646 | // Invoked as plain function `MyObject(...)`, turn into construct call. 647 | const int argc = 1; 648 | Local argv[argc] = { args[0] }; 649 | return scope.Close(constructor->NewInstance(argc, argv)); 650 | } 651 | } 652 | 653 | Handle MyObject::NewInstance(const Arguments& args) { 654 | HandleScope scope; 655 | 656 | const unsigned argc = 1; 657 | Handle argv[argc] = { args[0] }; 658 | Local instance = constructor->NewInstance(argc, argv); 659 | 660 | return scope.Close(instance); 661 | } 662 | 663 | Test it with: 664 | 665 | var addon = require('./build/Release/addon'); 666 | 667 | var obj1 = addon.createObject(10); 668 | var obj2 = addon.createObject(20); 669 | var result = addon.add(obj1, obj2); 670 | 671 | console.log(result); // 30 672 | --------------------------------------------------------------------------------