我正在构建一个要与之交互的节点模块,libapt
以便我可以列出和控制已安装的包。我通过实现一个函数来获取每个已安装包的名称开始简单。我已经撞墙了。
我目前有这个代码:
#include <apt-pkg/init.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/pkgcache.h>
#include <node.h>
#include <v8.h>
using namespace v8;
typedef struct AsyncData {
Persistent<Function> callback; // callback function
Handle<Array> packageList; // array of package names
} AsyncData;
void AsyncWork(uv_work_t *req) {
AsyncData *asyncData = (AsyncData *)req->data;
asyncData->packageList = Array::New();
size_t i = 0;
for (pkgCache::PkgIterator package = cache->PkgBegin(); !package.end(); package++) {
if(package->CurrentVer == 0) continue;
asyncData->packageList->Set(i++, String::New(package.Name()));
}
}
void AsyncAfter(uv_work_t *req) {
HandleScope scope;
AsyncData *asyncData = (AsyncData *)req->data;
Handle<Value> argv[] = {
Null(),
asyncData->packageList
};
TryCatch try_catch;
asyncData->callback->Call(Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught())
node::FatalException(try_catch);
asyncData->callback.Dispose();
delete asyncData;
delete req;
}
Handle<Value> InstalledPackages(const Arguments& args) {
HandleScope scope;
uv_work_t *req = new uv_work_t;
AsyncData *asyncData = new AsyncData;
req->data = asyncData;
asyncData->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
uv_queue_work(
uv_default_loop(),
req, // work token
AsyncWork, // work function
(uv_after_work_cb)AsyncAfter // function to run when complete
);
return scope.Close(Undefined());
}
void Initialize(Handle<Object> exports) {
pkgInitConfig(*_config);
pkgInitSystem(*_config, _system);
// function hello();
exports->Set(String::NewSymbol("getInstalledPackages"), FunctionTemplate::New(InstalledPackages)->GetFunction());
}
NODE_MODULE(apt, Initialize)
这样做的主要问题是您不能在主事件循环以外的线程中使用任何 V8 对象。这意味着我在上面的代码中遇到了段错误。所以我修改了我的代码如下:
#include <apt-pkg/init.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/pkgcache.h>
#include <node.h>
#include <v8.h>
using namespace std;
using namespace v8;
typedef struct AsyncData {
Persistent<Function> callback; // callback function
vector<string> packageList; // array of package names
} AsyncData;
void AsyncWork(uv_work_t *req) {
AsyncData *asyncData = (AsyncData *)req->data;
pkgCacheFile cache_file;
pkgCache* cache = cache_file.GetPkgCache();
for (pkgCache::PkgIterator package = cache->PkgBegin(); !package.end(); package++) {
// If the current package has Version of 0, its no installed
if(package->CurrentVer == 0)
continue;
asyncData->packageList.push_back(package.Name());
}
}
void AsyncAfter(uv_work_t *req) {
HandleScope scope;
AsyncData *asyncData = (AsyncData *)req->data;
Handle<Array> packageArray = Array::New(asyncData->packageList.size());
for(size_t i = 0; i < asyncData->packageList.size(); i++) {
packageArray->Set(i, String::New(asyncData->packageList[i].c_str()));
}
Handle<Value> argv[] = {
Null(),
packageArray
};
TryCatch try_catch;
asyncData->callback->Call(Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught())
node::FatalException(try_catch);
asyncData->callback.Dispose();
delete asyncData;
delete req;
}
Handle<Value> InstalledPackages(const Arguments& args) {
HandleScope scope;
uv_work_t *req = new uv_work_t;
AsyncData *asyncData = new AsyncData;
req->data = asyncData;
asyncData->callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));
uv_queue_work(
uv_default_loop(),
req, // work token
AsyncWork, // work function
(uv_after_work_cb)AsyncAfter // function to run when complete
);
return scope.Close(Undefined());
}
void Initialize(Handle<Object> exports) {
pkgInitConfig(*_config);
pkgInitSystem(*_config, _system);
// function hello();
exports->Set(String::NewSymbol("getInstalledPackages"), FunctionTemplate::New(InstalledPackages)->GetFunction());
}
NODE_MODULE(apt, Initialize)
这段代码现在可以工作了,但是我现在正在遍历字符串列表并在主事件循环中使用它们制作新的 V8 字符串。我不妨一开始就同步完成这一切。由于包列表的长度可能类似于 30,000 个字符串,因此我不想在 javascript 事件循环中执行此操作。如何异步创建大型字符串数组?