Last active
February 22, 2019 21:36
-
-
Save gabrielschulhof/df079c9a89fe05dfa740b7171e0aa760 to your computer and use it in GitHub Desktop.
Example of an addon conf file stored in the addon's build directory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <napi.h> | |
#include <stdio.h> | |
namespace { | |
// Per-instance addon data. An instance of this class is passed to every binding | |
// and makes it possible to avoid setting global static variables. | |
class AddonData { | |
public: | |
AddonData(std::string config_file): config_file(config_file) {} | |
std::string config_file; | |
static void Delete(napi_env env, void* data, void* hint) { | |
delete reinterpret_cast<AddonData*>(data); | |
} | |
}; | |
// The actual binding. | |
Napi::Value DoSomethingUseful(const Napi::CallbackInfo& info) { | |
// Retrieve the addon data. | |
AddonData* addon_data = reinterpret_cast<AddonData*>(info.Data()); | |
char* data = nullptr; | |
size_t length = 0; | |
// Open the configuration file. | |
FILE* file = fopen(addon_data->config_file.c_str(), "r"); | |
if (file == nullptr) { | |
Napi::Error::New(info.Env(), "Failed to open config file") | |
.ThrowAsJavaScriptException(); | |
return info.Env().Undefined(); | |
} | |
// Seek to the end so we can gauge its size. | |
if (fseek(file, 0L, SEEK_END) != 0) { | |
Napi::Error::New(info.Env(), "Failed to seek to the end of the config file") | |
.ThrowAsJavaScriptException(); | |
fclose(file); | |
return info.Env().Undefined(); | |
} | |
// Retrieve the size of the file. | |
length = ftell(file); | |
// Seek back to the beginning. | |
if (fseek(file, 0L, SEEK_SET) != 0) { | |
Napi::Error::New(info.Env(), | |
"Failed to seek to the beginning of the config file") | |
.ThrowAsJavaScriptException(); | |
fclose(file); | |
return info.Env().Undefined(); | |
} | |
// Allocate a buffer to receive the contents of the file. | |
data = new char[length + 1]; | |
// Read the file into the buffer. | |
if (fread(data, length, 1, file) != 1) { | |
Napi::Error::New(info.Env(), "Failed to read the config file") | |
.ThrowAsJavaScriptException(); | |
fclose(file); | |
return info.Env().Undefined(); | |
} | |
// Close the file. | |
fclose(file); | |
// Make sure the buffer is null-terminated, and construct a JavaScript string | |
// wherein we return the contents of the file to JavaScript. | |
data[length] = 0; | |
Napi::String result = Napi::String::New(info.Env(), | |
std::string("---8<------\n") + data + "---8<------\n"); | |
// Delete the buffer that held the contents of the file. | |
delete[] data; | |
// Return the string we constructed to JavaScript. | |
return result; | |
} | |
// The real addon initialization function. It receives the addon's exports nad | |
// the path to the configuration file. | |
Napi::Value Initialize(const Napi::CallbackInfo& info) { | |
// Make sure the first parameter is an object, so we can attach the bindings | |
// as its properties. | |
if (!info[0].IsObject()) { | |
Napi::Error::New(info.Env(), "First parameter must be an object") | |
.ThrowAsJavaScriptException(); | |
return info.Env().Undefined(); | |
} | |
// Make sure the second parameter is a string, so we can use it as the config | |
// file path. | |
if (!info[1].IsString()) { | |
Napi::Error::New(info.Env(), "Second parameter must be a string") | |
.ThrowAsJavaScriptException(); | |
return info.Env().Undefined(); | |
} | |
// Allocate and initialize a new instance of the per-addon data. | |
AddonData* addon_data = new AddonData(info[1].As<Napi::String>()); | |
// Cast the second parameter as a `Napi::Object`. | |
Napi::Object exports = info[0].As<Napi::Object>(); | |
// Weakly associate the per-addon data with the exports object. This will | |
// ensure that the per-addon data will be deleted when the addon itself is | |
// deleted, at environment cleanup time. | |
if (napi_wrap(info.Env(), | |
exports, | |
addon_data, | |
AddonData::Delete, | |
nullptr, | |
nullptr) != napi_ok) { | |
Napi::Error::New(info.Env(), "Failed to initialize addon data") | |
.ThrowAsJavaScriptException(); | |
delete addon_data; | |
return info.Env().Undefined(); | |
} | |
// Save the config file path in the addon data. | |
addon_data->config_file = info[1].As<Napi::String>(); | |
// Decorate the exports object with the actual bindings. | |
exports["doSomethingUseful"] = | |
Napi::Function::New(info.Env(), DoSomethingUseful, nullptr, addon_data); | |
// Return the exports object. This enables chaining on the JavaScript side. | |
return exports; | |
} | |
// The addon initialization function. | |
Napi::Object Init(Napi::Env env, Napi::Object exports) { | |
// Expose the actual initialization function to JavaScript. | |
exports["initialize"] = Napi::Function::New(env, Initialize); | |
return exports; | |
} | |
} // end of anonymous namespace | |
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[config] | |
some_key = some_value |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
'targets': [ | |
{ | |
'target_name': 'addon', | |
'sources': [ 'addon.cc' ], | |
'include_dirs': ["<!@(node -p \"require('node-addon-api').include\")"], | |
'dependencies': ["<!(node -p \"require('node-addon-api').gyp\")"], | |
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ], | |
'cflags': [ '-fno-exceptions' ], | |
'cflags_cc': [ '-fno-exceptions' ], | |
'msvs_settings': { | |
'VCCLCompilerTool': { | |
'ExceptionHandling': 0, | |
'EnablePREfast': 'true', | |
}, | |
}, | |
'xcode_settings': { | |
'CLANG_CXX_LIBRARY': 'libc++', | |
'MACOSX_DEPLOYMENT_TARGET': '10.7', | |
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', | |
}, | |
}, | |
{ | |
'target_name': 'config_file', | |
'type': 'none', | |
'copies': [ | |
{ | |
'destination': '<(PRODUCT_DIR)', | |
'files': [ 'addon.conf' ] | |
} | |
] | |
} | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require('path'); | |
// Load the addon in a two-step process. First, use bindings to locate it, and | |
// then call its `initialize()` method, passing in the path to its configuration | |
// file. The addon returns itself from `initialize()`, decorated with its actual | |
// bindings. The result becomes the exports of this package. | |
module.exports = ((addon) => addon.initialize(addon, | |
path.join(path.dirname(addon.path), 'addon.conf'))) | |
(require('bindings')('addon')); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "module-with-config-file", | |
"version": "1.0.0", | |
"description": "", | |
"main": "index.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1", | |
"install": "node-gyp rebuild" | |
}, | |
"author": "", | |
"license": "Apache-2.0", | |
"gypfile": true, | |
"dependencies": { | |
"bindings": "^1.4.0", | |
"node-addon-api": "^1.6.2" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment