C++ Addon Async 非同步機制
阿新 • • 發佈:2018-11-08
執行緒佇列: libuv,window 可在libuv官網下載相應版本
opencv: 編譯的時候opencv的位數要和 node的bit 一致
相容electron : node-gyp rebuild --version --Debug/--Release --archs=x64/ia32
#include <node.h> #include <v8.h> #include <uv.h> #include <windows.h> #include<string.h> #include <string> #include <iostream> #include <thread> #include <opencv/cv.h> #include <opencv2/opencv.hpp> using namespace v8; // 傳入了兩個引數,args[0] 字串,args[1] 回撥函式s struct SImageData { int status = -1; int width = 0; int height = 0; int channels = 0; int size = 0; int step = 0; std::vector<int> data; std::string msg; //msg }; void hello(const FunctionCallbackInfo<Value>& args) { // 使用 HandleScope 來管理生命週期s Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); // 判斷引數格式和格式s if (args.Length() < 2|| !args[0]->IsString()) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "Wrong arguments"))); return; } // callback, 使用Cast方法來轉換s Local<Function> callback = Local<Function>::Cast(args[1]); Local<Value> argv[1] = { // 拼接String String::Concat(Local<String>::Cast(args[0]), String::NewFromUtf8(isolate, " world")) }; // 呼叫回撥, 引數: 當前上下文,引數個數,引數列表s callback->Call(isolate->GetCurrentContext()->Global(), 1, argv); } //三個引數 圖片路徑,目標圖片寬度, 返回值: 影象引數,資料流s void getImageData(const FunctionCallbackInfo<Value>& args){ Isolate* isolate = args.GetIsolate(); SImageData sData; // 引數長度判斷s /* if (args.Length() < 3) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "Wrong params of arguments"))); return ; } */ // js String 型別轉換成 v8 String 型別s Local<String> filepath = Local<String>::Cast(args[0]); String::Utf8Value filePath(filepath); // js Number 型別轉換成 v8 Number 型別s Local<Number> dstWidth = Local<Number>::Cast(args[1]); printf("%s %f\n", *filePath, dstWidth->NumberValue()); cv::Mat srcImg = cv::imread(std::string(*filePath)); cv::Mat img; int width = srcImg.cols; int height = srcImg.rows; //圖片壓縮s int r_width = width; int r_height = r_width * height / width; resize(srcImg, img, cv::Size(r_width, r_height), 0, 0, 3); // 獲取圖片流資訊 int channels = img.channels(); uchar* buffer = img.data; width = img.cols; height = img.rows; //printf("width = %d\n;height = %d\n;channels = %d\n;step = %d\n",width, height, channels, step); int size = width * channels * height; sData.data.clear(); /* for (int i = 0; i < size; i += channels) { int r = buffer[i]; int g = buffer[i + 1]; int b = buffer[i + 2]; sData.data.push_back(r); sData.data.push_back(g); sData.data.push_back(b); } */ sData.status = 1; sData.width = img.cols; sData.height = img.rows; sData.size = size; sData.step = img.step; sData.channels = channels; //c++ -> js Local<Object> obj = Object::New(isolate); // Number type Local<Number> jsStatus = Number::New(isolate, sData.status); Local<Number> jsWidth = Number::New(isolate, sData.width); Local<Number> jsHeight = Number::New(isolate, sData.height); Local<Number> jsSize = Number::New(isolate, sData.size); Local<Number> jsStep = Number::New(isolate, sData.step); Local<Number> jsChannels = Number::New(isolate, sData.channels); obj->Set(String::NewFromUtf8(isolate, "status"), jsStatus); obj->Set(String::NewFromUtf8(isolate, "width"), jsWidth); obj->Set(String::NewFromUtf8(isolate, "height"), jsHeight); obj->Set(String::NewFromUtf8(isolate, "size"), jsSize); obj->Set(String::NewFromUtf8(isolate, "step"), jsStep); obj->Set(String::NewFromUtf8(isolate, "channels"), jsChannels); //args.GetReturnValue().Set(obj); // callback, 使用Cast方法來轉換s Local<Function> callback = Local<Function>::Cast(args[2]); const unsigned argc = 1; Local<Value> argv[argc] = { obj }; //cb->Call(Null(isolate), argc, argv); // 呼叫回撥, 引數: 當前上下文,引數個數,引數列表s callback->Call(isolate->GetCurrentContext()->Global(), argc, argv); } //async //在AddOn中,定義一個結構體在非同步呼叫中傳遞資料s struct LookupIpCountryBaton { uv_work_t work; //libuv Persistent<Function> callback; //javascript callback <heap> int type; }; void lookupIpCountryAsync(uv_work_t * work){ LookupIpCountryBaton * baton = (LookupIpCountryBaton*)work->data; // block thread for 3 seconds Sleep(3000); // save the result baton->type = 100002; } void lookupIpCountryCompleted(uv_work_t * work, int){ LookupIpCountryBaton * baton = (LookupIpCountryBaton*)work->data; Isolate * isolate = Isolate::GetCurrent(); HandleScope handleScope(isolate); const unsigned argc = 1; Local<Value> argv[argc] = {String::NewFromUtf8(isolate, "HHEE")}; Local<Function>::New(isolate, baton->callback)->Call(isolate->GetCurrentContext()->Global(), argc, argv); baton->callback.Reset(); delete baton; } //匯出方法首先儲存回撥函式,並驗證和解析傳入引數s // lookup country by ip // 1st argument is ip address // 2nd argument is the callback function void lookupIpCountry(const FunctionCallbackInfo<Value>& args) { Isolate *isolate = args.GetIsolate(); Local<Context> context = isolate->GetCurrentContext(); HandleScope scope(isolate); if (args.Length() < 2) { isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong params of arguments"))); return ; } LookupIpCountryBaton * baton = new LookupIpCountryBaton(); baton->work.data = baton; baton->type = 200; //baton->callback = Persistent<Function>::New(Handle<Function>::Cast(args[1])); baton->callback.Reset(isolate, Local<Function>::Cast(args[1])); uv_queue_work( uv_default_loop(), &baton->work, lookupIpCountryAsync, lookupIpCountryCompleted); return ; } // 相當於在 exports 物件中新增 { hello: hello } void init(Handle<Object> exports) { NODE_SET_METHOD(exports, "hello", hello); NODE_SET_METHOD(exports, "getImageData", getImageData); NODE_SET_METHOD(exports, "delay", lookupIpCountry); } // 將 export 物件暴露出去s // 原型 `NODE_MODULE(module_name, Initialize)`s NODE_MODULE(opencv_image, init);