Я строю модуль узла для взаимодействия с 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 в основном цикле событий. С таким же успехом я мог бы начать все это синхронно. Поскольку список пакетов может быть длиной около 30000 строк, я не хочу делать это в цикле событий javascript. Как я могу создать большой массив строк асинхронно?
Задача ещё не решена.