From: Nick Downing Date: Mon, 3 Jan 2022 02:26:46 +0000 (+1100) Subject: Change to node-addon-api X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?p=node_zettair.git;a=commitdiff_plain;h=e766792c988c937051ff6531fda1f722b51702a4 Change to node-addon-api --- diff --git a/binding.gyp b/binding.gyp index 9dfa2f8..136e15b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -2,9 +2,18 @@ "targets": [ { "target_name": "zettair", + "cflags!": ["-fno-exceptions"], + "cflags_cc!": ["-fno-exceptions"], "sources": ["zettair.cpp"], - "include_dirs": ["/home/nick/include"], - "libraries": ["-L/home/nick/lib -lzet"] + "defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"], + "include_dirs": [ + " + * Copyright (C) 2022 Nick Downing * SPDX-License-Identifier: MIT - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -21,4 +21,5 @@ * IN THE SOFTWARE. */ -module.exports = require('./build/Release/zettair.node'); +let bindings = require('bindings') +module.exports = bindings('zettair') diff --git a/package.json b/package.json index f2f65fe..e2687bf 100644 --- a/package.json +++ b/package.json @@ -19,15 +19,11 @@ "email": "nick@ndcode.org" }, "main": "index.js", - "directories": {}, - "dependencies": { - "node-gyp": "^3.6.2" - }, - "devDependencies": {}, - "scripts": { - "install": "node-gyp rebuild" - }, "author": "Nick Downing ", "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^4.2.0" + }, "gypfile": true } diff --git a/test.js b/test.js index ae19228..a7b458e 100755 --- a/test.js +++ b/test.js @@ -23,7 +23,8 @@ * IN THE SOFTWARE. */ -const zettair = require('./build/Release/zettair.node'); +let bindings = require('bindings') +let zettair = bindings('zettair') -const obj = new zettair.Index(); -console.log(obj.search('moby', 0, 10)); +let index = new zettair.Index('site') +console.log(index.search('checkout', 0, 10)) diff --git a/zettair.cpp b/zettair.cpp index 38e8812..1c67960 100644 --- a/zettair.cpp +++ b/zettair.cpp @@ -1,17 +1,17 @@ /* - * Copyright (C) 2018 Nick Downing + * Copyright (C) 2022 Nick Downing * SPDX-License-Identifier: MIT - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -21,8 +21,7 @@ * IN THE SOFTWARE. */ -#include -#include +#include #include #include #include @@ -30,172 +29,128 @@ namespace zettair { -static v8::Local index_result_to_object( - v8::Isolate* isolate, +static Napi::Object result_to_object( + Napi::Env env, struct index_result* result ); -static v8::Local index_results_to_object( - v8::Isolate* isolate, +static Napi::Object results_to_object( + Napi::Env env, struct index_result* results, - unsigned int num_results, + unsigned int n_results, double/*unsigned long int*/ total_results ); -class IndexObject : public node::ObjectWrap { +class Index : public Napi::ObjectWrap { public: - static void Init(v8::Local exports); + Index(const Napi::CallbackInfo& info); + Napi::Value search(const Napi::CallbackInfo& info); -private: struct index* idx; - - explicit IndexObject(struct index* idx0); - ~IndexObject(); - - static void New(const v8::FunctionCallbackInfo& args); - static void Search(const v8::FunctionCallbackInfo& args); - static v8::Persistent constructor; }; -v8::Persistent IndexObject::constructor; +Index::Index(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::String prefix = info[0].As(); -IndexObject::IndexObject(struct index* idx0) : idx(idx0) { -} + int lopts = INDEX_LOAD_NOOPT; + struct index_load_opt lopt; + memset(&lopt, 0, sizeof(struct index_load_opt)); -IndexObject::~IndexObject() { + lopts |= INDEX_LOAD_IGNORE_VERSION; /* quick hack */ + idx = index_load(prefix.Utf8Value().c_str(), MEMORY_DEFAULT, lopts, &lopt); + if (idx == NULL) + Napi::Error::New( + env, + "Unable to load index" + ).ThrowAsJavaScriptException(); } -void IndexObject::Init(v8::Local exports) { - v8::Isolate* isolate = exports->GetIsolate(); - - // Prepare constructor template - v8::Local tpl = - v8::FunctionTemplate::New(isolate, New); - tpl->SetClassName(v8::String::NewFromUtf8(isolate, "Index")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); +Napi::Value Index::search(const Napi::CallbackInfo& info){ + Napi::Env env = info.Env(); + std::string query = info[0].As().Utf8Value(); + uint32_t startdoc = info[1].As().Uint32Value(); + uint32_t len = info[2].As().Uint32Value(); + std::string opt_type = + info[3] == env.Undefined() ? + std::string() : + info[3].As().Utf8Value(); + Napi::Array opt_args_tuple = + info[4] == env.Undefined() ? + Napi::Array::New(env) : + info[4].As(); + uint32_t accumulator_limit = + info[5] == env.Undefined() ? + 0 : + info[5].As().Uint32Value(); - // Prototype - NODE_SET_PROTOTYPE_METHOD(tpl, "search", Search); - - constructor.Reset(isolate, tpl->GetFunction()); - exports->Set( - v8::String::NewFromUtf8(isolate, "Index"), - tpl->GetFunction() + struct index_result* results = (struct index_result*)malloc( + len * sizeof(struct index_result) ); -} - -void IndexObject::New(const v8::FunctionCallbackInfo& args) { - v8::Isolate* isolate = args.GetIsolate(); - - if (args.IsConstructCall()) { - // Invoked as constructor: `new Index(...)` - v8::String::Utf8Value prefix(args[0]); - struct index* idx = NULL;; - int lopts = INDEX_LOAD_NOOPT; - struct index_load_opt lopt; - - lopts |= INDEX_LOAD_IGNORE_VERSION; /* quick hack */ - if ( - ( - idx = index_load( - args[0]->IsString() ? *prefix : "index", - MEMORY_DEFAULT, - lopts, - &lopt - ) - ) == NULL - ) { - isolate->ThrowException( - v8::String::NewFromUtf8(isolate, "Unable to load index") - ); - return; - } - IndexObject* obj = new IndexObject(idx); - obj->Wrap(args.This()); - args.GetReturnValue().Set(args.This()); - } else { - // Invoked as plain function `Index(...)`, turn into construct call. - const int argc = 1; - v8::Local argv[argc] = { args[0] }; - v8::Local context = isolate->GetCurrentContext(); - v8::Local cons = - v8::Local::New(isolate, constructor); - v8::Local result = - cons->NewInstance(context, argc, argv).ToLocalChecked(); - args.GetReturnValue().Set(result); + if (results == NULL) { + Napi::Error::New( + env, + "Unable to allocate results" + ).ThrowAsJavaScriptException(); + return env.Null(); } -} - -void IndexObject::Search(const v8::FunctionCallbackInfo& args) { - v8::Isolate* isolate = args.GetIsolate(); - v8::String::Utf8Value query(args[0]); - v8::String::Utf8Value optType(args[3]); - v8::Local optArgsTuple; - if (args[4]->IsArray()) - optArgsTuple = args[4].As(); - unsigned long startdoc = args[1]->IntegerValue(); - unsigned long len = args[2]->IntegerValue(); - IndexObject* Index = node::ObjectWrap::Unwrap(args.Holder()); - struct index_result* result; - unsigned int results; + unsigned int n_results; double/*unsigned long int*/ total_results; int est; - unsigned int accumulator_limit = args[5]->Uint32Value(); int opts = INDEX_SEARCH_NOOPT; struct index_search_opt opt; + memset(&opt, 0, sizeof(struct index_search_opt)); opt.u.okapi_k3.k1 = 1.2; opt.u.okapi_k3.k3 = 1e10; opt.u.okapi_k3.b = 0.75; - if ( - (result = (struct index_result*)malloc(sizeof(*result) * len)) == NULL - ) { - isolate->ThrowException( - v8::String::NewFromUtf8(isolate, "Unable to allocate results") - ); - return; - } - if (args[3]->IsString()) { - if (strcmp(*optType, "COSINE") == 0) { + if (info[3] != env.Undefined()) { + if (opt_type == "COSINE") opts = INDEX_SEARCH_COSINE_RANK; - } else if (strcmp(*optType, "OKAPI") == 0) { + else if (opt_type == "OKAPI") opts = INDEX_SEARCH_OKAPI_RANK; - } else if (strcmp(*optType, "OKAPI_K3") == 0) { - if (optArgsTuple.IsEmpty()) { - isolate->ThrowException( - v8::String::NewFromUtf8(isolate, "Must supply args to search type") - ); - free(result); - return; + else if (opt_type == "OKAPI_K3") { + if (opt_args_tuple.Length() < 3U) { + Napi::Error::New( + env, + "Must supply args to search type" + ).ThrowAsJavaScriptException(); + free(results); + return env.Null(); } opts = INDEX_SEARCH_OKAPI_RANK; - opt.u.okapi_k3.k1 = optArgsTuple->Get(0)->IntegerValue(); - opt.u.okapi_k3.k3 = optArgsTuple->Get(1)->IntegerValue(); - opt.u.okapi_k3.b = optArgsTuple->Get(2)->IntegerValue(); - } else if (strcmp(*optType, "HAWKAPI") == 0) { - if (optArgsTuple.IsEmpty()) { - isolate->ThrowException( - v8::String::NewFromUtf8(isolate, "Must supply args to search type") - ); - free(result); - return; + opt.u.okapi_k3.k1 = opt_args_tuple.Get(0U).As().FloatValue(); + opt.u.okapi_k3.k3 = opt_args_tuple.Get(1U).As().FloatValue(); + opt.u.okapi_k3.b = opt_args_tuple.Get(2U).As().FloatValue(); + } + else if (opt_type == "HAWKAPI") { + if (opt_args_tuple.Length() < 2U) { + Napi::Error::New( + env, + "Must supply args to search type" + ).ThrowAsJavaScriptException(); + free(results); + return env.Null(); } opts = INDEX_SEARCH_HAWKAPI_RANK; - opt.u.hawkapi.alpha = optArgsTuple->Get(0)->IntegerValue(); - opt.u.hawkapi.k3 = optArgsTuple->Get(1)->IntegerValue(); - } else if (strcmp(*optType, "DIRICHLET") == 0) { + opt.u.hawkapi.alpha = opt_args_tuple.Get(0U).As().FloatValue(); + opt.u.hawkapi.k3 = opt_args_tuple.Get(1U).As().FloatValue(); + } + else if (opt_type == "DIRICHLET") { opts = INDEX_SEARCH_DIRICHLET_RANK; - if (optArgsTuple.IsEmpty() || optArgsTuple->Length() == 0) - opt.u.dirichlet.mu = 2500.0; - else - opt.u.dirichlet.mu = optArgsTuple->Get(0)->NumberValue(); - } else { - isolate->ThrowException( - v8::String::NewFromUtf8(isolate, "Unknown search type") - ); - free(result); - return; + opt.u.dirichlet.mu = + opt_args_tuple.Length() < 1U ? + 2500.0 : + opt_args_tuple.Get(0U).As().FloatValue(); + } + else { + Napi::Error::New( + env, + "Unknown search type" + ).ThrowAsJavaScriptException(); + free(results); + return env.Null(); } } if (accumulator_limit != 0) { @@ -206,79 +161,106 @@ void IndexObject::Search(const v8::FunctionCallbackInfo& args) { opts |= INDEX_SEARCH_SUMMARY_TYPE; opt.summary_type = INDEX_SUMMARISE_TAG; #endif - if (!index_search(Index->idx, *query, startdoc, len, - result, &results, &total_results, &est, opts, &opt)) { + if ( + !index_search( + idx, + query.c_str(), + startdoc, + len, + results, + &n_results, + &total_results, + &est, + opts, + &opt + ) + ) { char err_buf[1024]; - snprintf(err_buf, 1024, "Unable to perform search for query '%s'; " - "system error is '%s'\n", *query, strerror(errno)); - isolate->ThrowException( - v8::String::NewFromUtf8(isolate, err_buf) + snprintf( + err_buf, + sizeof(err_buf), + "Unable to perform search for query '%s'; system error is '%s'\n", + query.c_str(), + strerror(errno) ); - free(result); - return; + Napi::Error::New(env, err_buf).ThrowAsJavaScriptException(); + free(results); + return env.Null(); } - args.GetReturnValue().Set( - index_results_to_object(isolate, result, results, total_results) - ); - free(result); - return; + Napi::Object object = + results_to_object(env, results, n_results, total_results); + free(results); + return object; } -static v8::Local index_result_to_object( - v8::Isolate* isolate, +static Napi::Object result_to_object( + Napi::Env env, struct index_result* result ) { - v8::EscapableHandleScope handle_scope(isolate); - v8::Local result_object = v8::Object::New(isolate); - result_object->Set( - v8::String::NewFromUtf8(isolate, "docno"), - v8::Integer::New(isolate, result->docno) + Napi::Object object = Napi::Object::New(env); + object.Set( + Napi::String::New(env, "docno"), + Napi::Number::New(env, result->docno) ); - result_object->Set( - v8::String::NewFromUtf8(isolate, "score"), - v8::Number::New(isolate, result->score) + object.Set( + Napi::String::New(env, "score"), + Napi::Number::New(env, result->score) ); - result_object->Set( - v8::String::NewFromUtf8(isolate, "summary"), - v8::String::NewFromUtf8(isolate, result->summary) + object.Set( + Napi::String::New(env, "summary"), + Napi::String::New(env, result->summary) ); - result_object->Set( - v8::String::NewFromUtf8(isolate, "title"), - v8::String::NewFromUtf8(isolate, result->title) + object.Set( + Napi::String::New(env, "title"), + Napi::String::New(env, result->title) ); - result_object->Set( - v8::String::NewFromUtf8(isolate, "auxiliary"), - v8::String::NewFromUtf8(isolate, result->auxilliary) + object.Set( + Napi::String::New(env, "auxiliary"), + Napi::String::New(env, result->auxilliary) ); - return handle_scope.Escape(result_object); + return object; } -static v8::Local index_results_to_object( - v8::Isolate* isolate, +static Napi::Object results_to_object( + Napi::Env env, struct index_result* results, - unsigned int num_results, + unsigned int n_results, double/*unsigned long int*/ total_results ) { - v8::EscapableHandleScope handle_scope(isolate); - v8::Local results_object = v8::Object::New(isolate); - v8::Local results_array = v8::Array::New(isolate, num_results); - for (unsigned int i = 0; i < num_results; ++i) - results_array->Set(i, index_result_to_object(isolate, results + i)); - results_object->Set( - v8::String::NewFromUtf8(isolate, "results"), - results_array + Napi::Object object = Napi::Object::New(env); + Napi::Array array = Napi::Array::New(env, n_results); + for (unsigned int i = 0; i < n_results; ++i) + array.Set(i, result_to_object(env, results + i)); + object.Set( + Napi::String::New(env, "results"), + array ); - results_object->Set( - v8::String::NewFromUtf8(isolate, "total_results"), - v8::Number::New(isolate, total_results) + object.Set( + Napi::String::New(env, "total_results"), + Napi::Number::New(env, total_results) ); - return handle_scope.Escape(results_object); + return object; } -void InitAll(v8::Local exports) { - IndexObject::Init(exports); +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set( + "Index", + Napi::ObjectWrap::DefineClass( + env, + "Index", + { + Napi::ObjectWrap::InstanceMethod<&Index::search>( + "search", + static_cast( + napi_writable | napi_configurable + ) + ) + } + ) + ); + return exports; } -NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll) +NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) }