qbolt/qbolt/boltdb.cpp

168 lines
4.6 KiB
C++

#include "boltdb.h"
#include <QtEndian>
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<void(QByteArray, int64_t)> 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<qint64>(b.mid(0, 8));
cb(b.mid(8), dataLen);
});
}
bool BoltDB::getData(QStringList bucketPath, QByteArray key, std::function<void(QByteArray)> onSuccess, std::function<void(QString)> 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<void(QByteArray)> onSuccess, std::function<void(QString)> 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<void(QByteArray)> onSuccess, std::function<void(QString)> 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);
}
}