220 lines
6.4 KiB
C++
220 lines
6.4 KiB
C++
#include "boltdb.h"
|
|
|
|
#include <QtEndian>
|
|
|
|
BoltDB::BoltDB()
|
|
{
|
|
|
|
}
|
|
|
|
BoltDB* BoltDB::createFrom(QString filePath, bool readOnly, QString &errorOut)
|
|
{
|
|
QByteArray filePathBytes(filePath.toUtf8());
|
|
GoString filePathGS = Interop::toGoString_WeakRef(&filePathBytes);
|
|
|
|
auto open_ret = ::Bolt_Open(readOnly, filePathGS);
|
|
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;
|
|
|
|
static bool handleTriple(int r0, char* r1, int64_t r2, QString& errorOut) {
|
|
if (r0 == ERROR_AND_STOP_CALLING) {
|
|
errorOut = QString::fromUtf8(r1, r2);
|
|
free(r1);
|
|
return false;
|
|
|
|
} else if (r0 == FINISHED_OK) {
|
|
return true;
|
|
|
|
} else {
|
|
// ?? unreachable
|
|
return false;
|
|
|
|
}
|
|
}
|
|
|
|
bool BoltDB::addBucket(const QList<QByteArray>& bucketPath, QByteArray bucketName, QString& errorOut)
|
|
{
|
|
GoSliceManagedWrapper browse(bucketPath);
|
|
GoString bucketNameGS = Interop::toGoString_WeakRef(&bucketName);
|
|
auto resp = ::Bolt_CreateBucket(this->gmsDbRef, browse.slice, bucketNameGS);
|
|
|
|
return handleTriple(resp.r0, resp.r1, resp.r2, errorOut);
|
|
}
|
|
|
|
bool BoltDB::deleteBucket(const QList<QByteArray>& bucketPath, QByteArray bucketName, QString& errorOut)
|
|
{
|
|
GoSliceManagedWrapper browse(bucketPath);
|
|
GoString bucketNameGS = Interop::toGoString_WeakRef(&bucketName);
|
|
auto resp = ::Bolt_DeleteBucket(this->gmsDbRef, browse.slice, bucketNameGS);
|
|
|
|
return handleTriple(resp.r0, resp.r1, resp.r2, errorOut);
|
|
}
|
|
|
|
bool BoltDB::setItem(const QList<QByteArray>& bucketPath, QByteArray keyName, QByteArray value, QString& errorOut)
|
|
{
|
|
GoSliceManagedWrapper browse(bucketPath);
|
|
GoString keyNameGS = Interop::toGoString_WeakRef(&keyName);
|
|
GoString valueGS = Interop::toGoString_WeakRef(&value);
|
|
auto resp = ::Bolt_SetItem(this->gmsDbRef, browse.slice, keyNameGS, valueGS);
|
|
|
|
return handleTriple(resp.r0, resp.r1, resp.r2, errorOut);
|
|
}
|
|
|
|
bool BoltDB::deleteItem(const QList<QByteArray>& bucketPath, QByteArray keyName, QString& errorOut)
|
|
{
|
|
GoSliceManagedWrapper browse(bucketPath);
|
|
GoString keyNameGS = Interop::toGoString_WeakRef(&keyName);
|
|
auto resp = ::Bolt_DeleteItem(this->gmsDbRef, browse.slice, keyNameGS);
|
|
|
|
return handleTriple(resp.r0, resp.r1, resp.r2, errorOut);
|
|
}
|
|
|
|
|
|
bool BoltDB::listBucketsAtRoot(QString& errorOut, NameReciever cb)
|
|
{
|
|
auto listJob = ::Bolt_ListBucketsAtRoot(this->gmsDbRef);
|
|
return pumpNext(listJob, errorOut, cb);
|
|
}
|
|
|
|
bool BoltDB::listBuckets(const QList<QByteArray>& 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(const QList<QByteArray>& 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(const QList<QByteArray>& 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(const QList<QByteArray>& 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);
|
|
}
|
|
}
|