我正在构建一个与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事件循环中执行此操作。如何异步创建大型字符串数组?