#include "boltdb.h" #include BoltDB::BoltDB() { } BoltDB* BoltDB::createFrom(QString filePath, QString &errorOut) { auto opts = ::Bolt_Options_New_Readonly(); QByteArray filePathBytes(filePath.toUtf8()); GoString filePathGS = Interop::toGoString_WeakRef(&filePathBytes); auto open_ret = ::Bolt_Open(filePathGS, 0444, opts); if (open_ret.r2 != 0) { errorOut = QString::fromUtf8(open_ret.r1, open_ret.r2); free(open_ret.r1); return nullptr; } BoltDB *ret = new BoltDB(); ret->gmsDbRef = open_ret.r0; return ret; } static const int ERROR_AND_STOP_CALLING = 100; static const int ERROR_AND_KEEP_CALLING = 101; static const int FINISHED_OK = 102; static const int REAL_MESSAGE = 103; bool BoltDB::listBucketsAtRoot(QString& errorOut, NameReciever cb) { auto listJob = ::Bolt_ListBucketsAtRoot(this->gmsDbRef); return pumpNext(listJob, errorOut, cb); } bool BoltDB::listBuckets(QStringList bucketPath, QString& errorOut, NameReciever cb) { if (bucketPath.size() == 0) { return listBucketsAtRoot(errorOut, cb); } GoSliceManagedWrapper browse(&bucketPath); auto listJob = ::Bolt_ListBuckets(this->gmsDbRef, browse.slice); return pumpNext(listJob, errorOut, cb); } bool BoltDB::listKeys(QStringList bucketPath, QString& errorOut, std::function cb) { GoSliceManagedWrapper browse(&bucketPath); auto listJob = ::Bolt_ListItems(this->gmsDbRef, browse.slice); return pumpNext(listJob, errorOut, [=](QByteArray b) { // First 8 bytes are little-endian uint64 len int64_t dataLen = qFromLittleEndian(b.mid(0, 8)); cb(b.mid(8), dataLen); }); } bool BoltDB::getData(QStringList bucketPath, QByteArray key, std::function onSuccess, std::function onError) { GoSliceManagedWrapper browse(&bucketPath); GoString keyGS = Interop::toGoString_WeakRef(&key); auto resp = ::Bolt_GetItem(this->gmsDbRef, browse.slice, keyGS); if (resp.r0 == ERROR_AND_STOP_CALLING) { onError(QString::fromUtf8(resp.r1, resp.r2)); free(resp.r1); return false; } else if (resp.r0 == REAL_MESSAGE) { onSuccess(QByteArray(resp.r1, resp.r2)); free(resp.r1); return true; } else { // ?? unreachable return false; } } bool BoltDB::pumpNext(GoInt64 jobRef, QString& errorOut, NameReciever cb) { errorOut.clear(); for(;;) { auto gnr = ::GetNext(jobRef); if (gnr.r0 == ERROR_AND_STOP_CALLING) { errorOut.append(QString::fromUtf8(gnr.r1, gnr.r2)); // log error free(gnr.r1); break; // done } else if (gnr.r0 == ERROR_AND_KEEP_CALLING) { errorOut.append(QString::fromUtf8(gnr.r1, gnr.r2)); // log error free(gnr.r1); continue; } else if (gnr.r0 == FINISHED_OK) { // Once we hit this, the go-side will clean up the channel / associated goroutines break; } else if (gnr.r0 == REAL_MESSAGE) { cb(QByteArray(gnr.r1, gnr.r2)); free(gnr.r1); continue; } } return (errorOut.length() == 0); } bool BoltDB::getStatsJSON(std::function onSuccess, std::function onError) { auto statresp = Bolt_DBStats(this->gmsDbRef); if (statresp.r0 == ERROR_AND_STOP_CALLING) { onError(QString::fromUtf8(statresp.r1, statresp.r2)); free(statresp.r1); return false; } else if (statresp.r0 == REAL_MESSAGE) { onSuccess(QByteArray(statresp.r1, statresp.r2)); free(statresp.r1); return true; } else { // ?? shouldn't be reachable return false; } } bool BoltDB::getBucketStatsJSON(QStringList bucketPath, std::function onSuccess, std::function onError) { GoSliceManagedWrapper sliceWrapper(&bucketPath); auto statresp = Bolt_BucketStats(this->gmsDbRef, sliceWrapper.slice); if (statresp.r0 == ERROR_AND_STOP_CALLING) { QString err = QString::fromUtf8(statresp.r1, statresp.r2); free(statresp.r1); onError(err); return false; } else if (statresp.r0 == REAL_MESSAGE) { onSuccess(QByteArray(statresp.r1, statresp.r2)); free(statresp.r1); return true; } else { // ?? shouldn't be reachable return false; } } BoltDB::~BoltDB() { auto err = ::Bolt_Close(this->gmsDbRef); if (err.r1 != 0) { // Error closing database! // Need to display an alert... somewhere free(err.r0); } }