Merge branch 'main' into openssl3_1_3

This commit is contained in:
Andrei Yankovich 2023-07-21 20:11:00 +02:00
commit e668d5762c
48 changed files with 916 additions and 158 deletions

View File

@ -24,7 +24,7 @@ if (DEFINED TARGET_PLATFORM_TOOLCHAIN)
endif()
updateGitVars()
set(HEART_VERSION 1.2.${GIT_COMMIT_COUNT}.${GIT_COMMIT_HASH})
set(HEART_VERSION 1.3.${GIT_COMMIT_COUNT}.${GIT_COMMIT_HASH})
if (ANDROID OR IOS)
option(HEART_TESTS "Enable or disable tests of the heart library" OFF)

View File

@ -12,6 +12,7 @@
#include <shedullertest.h>
#include <bigdatatest.h>
#include <upgradedatabasetest.h>
#include <multiversiontest.h>
#define TestCase(name, testClass) \
void name() { \
@ -34,6 +35,8 @@ private slots:
TestCase(shedullerTest, ShedullerTest);
TestCase(upgradeDataBaseTest, UpgradeDataBaseTest)
TestCase(multiVersionTest, MultiVersionTest)
// END TEST CASES
@ -62,7 +65,6 @@ testProtockol::testProtockol() {
}
testProtockol::~testProtockol() {
_app->exit(0);
delete _app;
}

View File

@ -12,7 +12,7 @@
#define LOCAL_TEST_PORT TEST_PORT + 4
class BigPackage: public QH::PKG::AbstractData {
QH_PACKAGE(BigPackage, "BigPackage")
QH_PACKAGE("BigPackage")
public:
BigPackage(){
@ -22,13 +22,15 @@ public:
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override{
QDataStream &fromStream(QDataStream &stream) override {
stream >> data;
return stream;
};
QDataStream &toStream(QDataStream &stream) const override{
QDataStream &toStream(QDataStream &stream) const override {
stream << data;
return stream;

View File

@ -0,0 +1,360 @@
/*
* Copyright (C) 2023-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#include "multiversiontest.h"
#define LOCAL_TEST_PORT TEST_PORT + 6
class MultiVersionPkg {
public:
int v2;
int v1;
bool responce = false;
int lastSerializedFrom = 0;
int lastSerializedto = 0;
};
class MultiVersionPkg1: public QH::PKG::MultiversionData, public MultiVersionPkg {
QH_PACKAGE("MultiVersionPkg")
public:
MultiVersionPkg1(): QH::PKG::MultiversionData(
{
{0, // version 0
{
[this](QDataStream& stream) -> QDataStream&{ // from
lastSerializedFrom = 0;
stream >> v1;
stream >> responce;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
lastSerializedto = 0;
stream << v1;
stream << responce;
return stream;
}
}
},
{1, // version 1
{
[this](QDataStream& stream) -> QDataStream&{ // from
lastSerializedFrom = 1;
stream >> v1;
stream >> responce;
stream >> v2;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
lastSerializedto = 1;
stream << v1;
stream << responce;
stream << v2;
return stream;
}
}
},
}
) {};
};
class SingleVersionPkg: public QH::PKG::AbstractData, public MultiVersionPkg {
QH_PACKAGE("MultiVersionPkg")
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override {
lastSerializedFrom = 0;
stream >> v1;
stream >> responce;
return stream;
};
QDataStream &toStream(QDataStream &stream) const override {
stream << v1;
stream << responce;
return stream;
};
};
class MultiVersionPkg2: public QH::PKG::MultiversionData, public MultiVersionPkg {
QH_PACKAGE("MultiVersionPkg")
public:
MultiVersionPkg2(): QH::PKG::MultiversionData(
{
{0, // version 0
{
[this](QDataStream& stream) -> QDataStream&{ // from
lastSerializedFrom = 0;
stream >> v1;
stream >> responce;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
lastSerializedto = 0;
stream << v1;
stream << responce;
return stream;
}
}
},
{1, // version 1
{
[this](QDataStream& stream) -> QDataStream&{ // from
lastSerializedFrom = 1;
stream >> v1;
stream >> responce;
stream >> v2;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
lastSerializedto = 1;
stream << v1;
stream << responce;
stream << v2;
return stream;
}
}
},
{2, // version 2
{
[this](QDataStream& stream) -> QDataStream&{ // from
lastSerializedFrom = 2;
stream >> v2;
stream >> responce;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
lastSerializedto = 2;
stream << v2;
stream << responce;
return stream;
}
}
}
}
) {};
};
template <class Base>
class TestAPI: public QH::iParser {
public:
TestAPI(QH::AbstractNode* parentNode): QH::iParser(parentNode) {
registerPackageType<Base>();
}
// iParser interface
public:
QH::ParserResult parsePackage(const QSharedPointer<QH::PKG::AbstractData> &pkg,
const QH::Header &hdr,
QH::AbstractNodeInfo *sender) override {
if (pkg->cmd() == Base::command()) {
data = pkg;
if (!data.dynamicCast<MultiVersionPkg>()->responce) {
data.dynamicCast<MultiVersionPkg>()->responce = true;
if (!sendData(pkg.data(), sender, &hdr)) {
return QH::ParserResult::Error;
}
}
return QH::ParserResult::Processed;
}
return QH::ParserResult::NotProcessed;
};
int version() const override {return 0;};
QString parserId() const override {return "BigDataTestParser";};
QSharedPointer<QH::PKG::AbstractData> getData() const{
return data;
};
void dropData() {
data = nullptr;
};
private:
QSharedPointer<QH::PKG::AbstractData> data = nullptr;
};
template <class Base>
class TestingClient: public QH::AbstractNode {
// AbstractNode interface
public:
TestingClient() {
_parser = addApiParser<TestAPI<Base>>();
}
bool sendRequest(const Base& data, int port) {
return sendData(&data, QH::HostAddress(TEST_LOCAL_HOST, port));
}
NodeType nodeType() const override {
return NodeType::Node;
};
const QSharedPointer<QH::iParser>& parser() const {
return _parser;
}
private:
QSharedPointer<QH::iParser> _parser;
};
MultiVersionTest::MultiVersionTest() {
_nodeV1 = new TestingClient<MultiVersionPkg1>;
_nodeV2 = new TestingClient<MultiVersionPkg2>;
_nodeOld = new TestingClient<SingleVersionPkg>;
}
MultiVersionTest::~MultiVersionTest() {
_nodeV1->softDelete();
_nodeV2->softDelete();
_nodeOld->softDelete();
}
void MultiVersionTest::test() {
QVERIFY(_nodeV1->run(TEST_LOCAL_HOST, LOCAL_TEST_PORT));
QVERIFY(connectFunc(_nodeV2, TEST_LOCAL_HOST, LOCAL_TEST_PORT));
QVERIFY(connectFunc(_nodeOld, TEST_LOCAL_HOST, LOCAL_TEST_PORT));
testMultipacakges();
testSinglePackages();
}
void MultiVersionTest::testMultipacakges() {
auto nodeWithV1 = dynamic_cast<TestingClient<MultiVersionPkg1>*>(_nodeV1);
auto nodeWithV2 = dynamic_cast<TestingClient<MultiVersionPkg2>*>(_nodeV2);
// clean old data;
nodeWithV1->parser().staticCast<TestAPI<MultiVersionPkg1>>()->dropData();
nodeWithV2->parser().staticCast<TestAPI<MultiVersionPkg2>>()->dropData();
// from new to old
{
// initialize test values.
MultiVersionPkg2 pkg;
pkg.v1 = 10;
pkg.v2 = 20;
// send test values into dist node
QVERIFY(nodeWithV2->sendRequest(pkg, LOCAL_TEST_PORT));
// should use the maximum available serialization. it is 1
QVERIFY(pkg.lastSerializedto == 1);
// wait for receive packge on distanation node
QVERIFY(wait([&nodeWithV1]() {
if (auto data = nodeWithV1->parser().staticCast<TestAPI<MultiVersionPkg1>>()->
getData().staticCast<MultiVersionPkg1>()) {
return data->lastSerializedFrom == 1;
}
return false;
}, WAIT_RESPOCE_TIME));
// wait for package on sender node.
QVERIFY(wait([&nodeWithV2]() {
if (auto data = nodeWithV2->parser().staticCast<TestAPI<MultiVersionPkg1>>()->
getData().staticCast<MultiVersionPkg1>()) {
return data->responce == true;
}
return false;
}, WAIT_RESPOCE_TIME));
// chec data all data should not be changed.
auto data = nodeWithV2->parser().staticCast<TestAPI<MultiVersionPkg2>>()->
getData().staticCast<MultiVersionPkg2>();
QVERIFY(data->v1 == pkg.v1);
QVERIFY(data->v2 == pkg.v2);
}
}
void MultiVersionTest::testSinglePackages() {
auto nodeWithSingle = dynamic_cast<TestingClient<SingleVersionPkg>*>(_nodeOld);
auto nodeWithV1 = dynamic_cast<TestingClient<MultiVersionPkg1>*>(_nodeV1);
// clean old data;
nodeWithSingle->parser().staticCast<TestAPI<SingleVersionPkg>>()->dropData();
nodeWithV1->parser().staticCast<TestAPI<MultiVersionPkg1>>()->dropData();
// from single package to new
{
// initialize test values.
SingleVersionPkg pkg;
pkg.v1 = 10;
pkg.v2 = 20;
// send test values into dist node
QVERIFY(nodeWithSingle->sendRequest(pkg, LOCAL_TEST_PORT));
// should use the maximum available serialization. it is 0
QVERIFY(pkg.lastSerializedto == 0);
// wait for receive packge on distanation node
QVERIFY(wait([&nodeWithV1]() {
if (auto data = nodeWithV1->parser().staticCast<TestAPI<MultiVersionPkg1>>()->
getData().staticCast<MultiVersionPkg1>()) {
return data->lastSerializedFrom == 0;
}
return false;
}, WAIT_RESPOCE_TIME));
// wait for package on sender node.
QVERIFY(wait([&nodeWithSingle]() {
if (auto data = nodeWithSingle->parser().staticCast<TestAPI<SingleVersionPkg>>()->
getData().staticCast<SingleVersionPkg>()) {
return data->responce == true;
}
return false;
}, WAIT_RESPOCE_TIME));
// chec data all data should not be changed.
auto data = nodeWithSingle->parser().staticCast<TestAPI<SingleVersionPkg>>()->
getData().staticCast<SingleVersionPkg>();
QVERIFY(data->v1 == pkg.v1);
// v2 is not supported on the v0 parser
QVERIFY(data->v2 == 0);
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2023-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef MULTIVERSIONTEST_H
#define MULTIVERSIONTEST_H
#include "test.h"
#include "testutils.h"
#include <QtTest>
#include <abstractnode.h>
/**
* @brief The MultiVersionTest class test work of packages with different versions.
*/
class MultiVersionTest: public Test, protected TestUtils
{
public:
MultiVersionTest();
~MultiVersionTest();
void test();
protected:
void testMultipacakges();
void testSinglePackages();
private:
QH::AbstractNode *_nodeV1 = nullptr;
QH::AbstractNode *_nodeV2 = nullptr;
QH::AbstractNode *_nodeOld = nullptr;
};
#endif // MULTIVERSIONTEST_H

View File

@ -40,6 +40,14 @@ public:
};
#ifdef Q_OS_WIN
const int stepTime = 5000;
const int measurementError = 2000;
#else
const int stepTime = 2000;
const int measurementError = 1000;
#endif
ShedullerTest::ShedullerTest() {
}
@ -56,13 +64,13 @@ void ShedullerTest::testSingleMode() {
auto task = QSharedPointer<TestTask>::create();
task->setMode(QH::ScheduleMode::SingleWork);
task->setTime(2000);
task->setTime(stepTime);
quint64 ct = QDateTime::currentMSecsSinceEpoch();
node->sheduleTask(task);
QVERIFY(wait([&node](){return node->executedTime;}, WAIT_TIME));
int diff = std::abs(static_cast<long long>(node->executedTime - (ct + 2000)));
QVERIFY(diff < 1000);
int diff = std::abs(static_cast<long long>(node->executedTime - (ct + stepTime)));
QVERIFY(diff < measurementError);
node->executedTime = 0;
QVERIFY(node->sheduledTaskCount() == 0);
@ -73,24 +81,24 @@ void ShedullerTest::testSingleMode() {
void ShedullerTest::testRepeatMode() {
ShedullerestNode *node = new ShedullerestNode();
auto task = QSharedPointer<TestTask>::create();
task->setTime(2000);
task->setTime(stepTime);
task->setMode(QH::ScheduleMode::Repeat);
quint64 ct = QDateTime::currentMSecsSinceEpoch();
node->sheduleTask(task);
QVERIFY(wait([&node](){return node->executedTime;}, WAIT_TIME));
int diff = std::abs(static_cast<long long>(node->executedTime - (ct + 2000)));
int diff = std::abs(static_cast<long long>(node->executedTime - (ct + stepTime)));
QVERIFY(diff < 1000);
QVERIFY(diff < measurementError);
node->executedTime = 0;
QVERIFY(node->sheduledTaskCount() == 1);
QVERIFY(wait([&node](){return node->executedTime;}, WAIT_TIME));
diff = std::abs(static_cast<long long>(node->executedTime - (ct + 4000)));
diff = std::abs(static_cast<long long>(node->executedTime - (ct + stepTime * 2)));
QVERIFY(diff < 1000);
QVERIFY(diff < measurementError);
QVERIFY(node->sheduledTaskCount() == 1);
node->removeTask(task->taskId());
@ -114,7 +122,7 @@ void ShedullerTest::testTimePointMode() {
QVERIFY(wait([&node](){return node->executedTime;}, WAIT_TIME));
int diff = std::abs(static_cast<long long>(node->executedTime - requestTime));
QVERIFY(diff < 1000);
QVERIFY(diff < measurementError);
QVERIFY(node->sheduledTaskCount() == 0);
node->softDelete();

View File

@ -17,28 +17,45 @@ APIVersion::APIVersion() {
QDataStream &APIVersion::fromStream(QDataStream &stream) {
stream >> _version;
stream >> _apisVersions;
stream >> _packagesVersions;
return stream;
}
QDataStream &APIVersion::toStream(QDataStream &stream) const {
stream << _version;
stream << _apisVersions;
stream << _packagesVersions;
return stream;
}
const VersionData &APIVersion::version() const {
return _version;
VersionData APIVersion::apisVersions() const {
return _apisVersions;
}
void APIVersion::setVersion(const VersionData &newVersion) {
_version = newVersion;
void APIVersion::setApisVersions(const VersionData &newApisVersions) {
_apisVersions = newApisVersions;
}
PackagesVersionData APIVersion::packagesVersions() const {
return _packagesVersions;
}
void APIVersion::setPackagesVersions(const PackagesVersionData &newPackagesVersions) {
_packagesVersions = newPackagesVersions;
}
bool APIVersion::isValid() const {
if (_version.isEmpty())
if (_apisVersions.isEmpty())
return false;
for (const auto & version: _version) {
for (const auto & version: _apisVersions) {
if (version.max() < version.min()) {
return false;
}
}
for (const auto & version: _packagesVersions) {
if (version.max() < version.min()) {
return false;
}

View File

@ -27,23 +27,32 @@ public:
APIVersion();
static unsigned short command(){return PROTOCKOL_VERSION_COMMAND;}
static unsigned short version(){return 0;}
static QString commandText(){return "PROTOCKOL_VERSION_COMMAND";}
unsigned short cmd() const override {return APIVersion::command();}
QString cmdString() const override {return APIVersion::commandText();}
const VersionData &version() const;
void setVersion(const VersionData &newVersion);
bool isValid() const override;
/**
* @brief packagesVersions This method return list of available multi-version packages on the node.
* @return
*/
PackagesVersionData packagesVersions() const;
void setPackagesVersions(const PackagesVersionData &newPackagesVersions);
VersionData apisVersions() const;
void setApisVersions(const VersionData &newApisVersions);
protected:
unsigned int localCode() const override {return typeid(APIVersion).hash_code();}
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
private:
VersionData _version;
VersionData _apisVersions;
PackagesVersionData _packagesVersions;
};

View File

@ -22,6 +22,7 @@ class VersionIsReceived: public QH::PKG::AbstractData
public:
VersionIsReceived();
static unsigned short version(){return 0;}
static unsigned short command(){return PROTOCKOL_VERSION_RECEIVED_COMMAND;}
static QString commandText(){return "PROTOCKOL_VERSION_RECEIVED_COMMAND";}
@ -31,7 +32,6 @@ public:
// StreamBase interface
protected:
unsigned int localCode() const override {return typeid(VersionIsReceived).hash_code();}
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
};

View File

@ -557,7 +557,8 @@ ParserResult AbstractNode::parsePackage(const QSharedPointer<AbstractData> &pkg,
return _apiVersionParser->parsePackage(pkg, pkgHeader, sender);
}
QSharedPointer<AbstractData> AbstractNode::genPackage(unsigned short cmd, AbstractNodeInfo *sender) const {
QSharedPointer<AbstractData> AbstractNode::genPackage(unsigned short cmd,
AbstractNodeInfo *sender) const {
if (_apiVersionParser)
return _apiVersionParser->searchPackage(cmd, sender);
@ -606,9 +607,9 @@ unsigned int AbstractNode::sendData(const PKG::AbstractData *resp,
Package pkg;
bool convert = false;
if (req && req->isValid()) {
convert = resp->toPackage(pkg, req->hash);
convert = resp->toPackage(pkg, node->multiVersionPackages().value(resp->cmd()),req->hash);
} else {
convert = resp->toPackage(pkg);
convert = resp->toPackage(pkg, node->multiVersionPackages().value(resp->cmd()));
}
if (!convert) {

View File

@ -733,8 +733,15 @@ private:
const Header &pkgHeader,
AbstractNodeInfo *sender);
/**
* @brief genPackage This method generate a package from the command and version
* @param cmd this is command of the package.
* @param sender This is sender that sent this requests.
* @return empty package object.
*/
QSharedPointer<PKG::AbstractData>
genPackage(unsigned short cmd, AbstractNodeInfo *sender) const;
genPackage(unsigned short cmd,
AbstractNodeInfo *sender) const;
/**
@note just disaable listen method in the node objects.

View File

@ -131,6 +131,14 @@ bool AbstractNodeInfo::confirmData() const {
return _status != NodeCoonectionStatus::NotConnected && fVersionDelivered() && fVersionReceived();
}
const PackagesVersionData& AbstractNodeInfo::multiVersionPackages() const {
return _multiVersionPackages;
}
void AbstractNodeInfo::setMultiVersionPackages(const PackagesVersionData &newMultiVersionPackages) {
_multiVersionPackages = newMultiVersionPackages;
}
bool AbstractNodeInfo::fVersionDelivered() const {
return _fVersionDelivered;
}

View File

@ -259,6 +259,18 @@ public:
*/
void addParser(QSharedPointer<QH::iParser> parser);
/**
* @brief multiVersionPackages This is list of packages of one api package tah support multiple versions.
* @return list of packages of one api package tah support multiple versions.
*/
const PackagesVersionData &multiVersionPackages() const;
/**
* @brief setMultiVersionPackages This method sets new list of multi-version packages.
* @param newMultiVersionPackages This is new value of multi-version packages.
*/
void setMultiVersionPackages(const PackagesVersionData &newMultiVersionPackages);
public slots:
/**
* @brief removeSocket This method use for remove socket.
@ -335,6 +347,10 @@ private:
QHash<QString, QSharedPointer<iParser>> _parsersKeysMap;
QMutex _parsersListMutex;
/**
* @brief _multiVersionPackages contains packages list that has multiple versions on one api rest of this is universal packages with version 0.
*/
PackagesVersionData _multiVersionPackages;
VersionData _version;
bool _fVersionReceived = false;
bool _fVersionDelivered = false;

View File

@ -59,6 +59,7 @@ bool AccessToken::operator !=(const AccessToken &other) const {
AccessToken& AccessToken::operator =(const AccessToken &other) = default;
QDataStream &AccessToken::fromStream(QDataStream &stream) {
stream >> _data;
stream >> _duration;
return stream;

View File

@ -232,7 +232,7 @@ QSharedPointer<iParser> APIVersionParser::selectParser(const QString &parserKey,
}
QSharedPointer<iParser> APIVersionParser::selectParserImpl(unsigned short cmd,
AbstractNodeInfo *sender) const{
AbstractNodeInfo *sender) const {
auto version = sender->version();
const auto availableParser = selectParser(version);
for (const auto& parser: availableParser) {
@ -275,10 +275,18 @@ unsigned short APIVersionParser::minimumApiVersion(const QString &apiKey) const
bool APIVersionParser::sendSupportedAPI(AbstractNodeInfo *dist) const {
VersionData supportedAPIs;
PackagesVersionData multiVersionPackages;
for (auto it = _apiParsers.begin(); it != _apiParsers.end(); ++it) {
DistVersion supportVersions;
for (auto api = it->begin(); api != it->end(); ++api) {
const auto packages = api.value()->multiVersionPackages();
for (auto pkg = packages.begin(); pkg != packages.end(); ++pkg) {
multiVersionPackages[pkg.key()] = pkg.value();
}
}
supportVersions.setMax(it->lastKey());
supportVersions.setMin(it->firstKey());
@ -290,7 +298,8 @@ bool APIVersionParser::sendSupportedAPI(AbstractNodeInfo *dist) const {
return false;
PKG::APIVersion versionInformationPkg;
versionInformationPkg.setVersion(supportedAPIs);
versionInformationPkg.setApisVersions(supportedAPIs);
versionInformationPkg.setPackagesVersions(multiVersionPackages);
return sendData(&versionInformationPkg, dist);
}
@ -299,8 +308,10 @@ bool APIVersionParser::processAppVersion(const QSharedPointer<PKG::APIVersion> &
QH::AbstractNodeInfo *sender,
const QH::Header &) {
auto distVersion = message->version();
auto distVersion = message->apisVersions();
sender->setVersion(distVersion);
sender->setMultiVersionPackages(message->packagesVersions());
auto parser = selectParser(distVersion);
for (auto parserKey = distVersion.keyBegin(); parserKey != distVersion.keyEnd(); ++parserKey) {

View File

@ -44,11 +44,13 @@ public:
* @brief searchPackage This method search package recursive in all registered pararsers. Searching will be in compatibility versions.
* Before search methd choose compatibly verson.
* @param cmd This is command for that shold be create pacakge object.
* @param ver This is version for that shold be create pacakge object.
* @param sender This is node that sent @a the cmd.
* @return Package generated from cmd.
*/
QSharedPointer<PKG::AbstractData>
searchPackage(unsigned short cmd, AbstractNodeInfo *sender) const;
searchPackage(unsigned short cmd,
AbstractNodeInfo *sender) const;
/**
* @brief getSelectedApiParser This method return apiParser for selected node
@ -129,6 +131,8 @@ public:
*/
bool sendSupportedAPI(AbstractNodeInfo *dist) const;
unsigned short selectPackageVersion(const VersionData& local, const VersionData& dist);
signals:
/**

View File

@ -16,7 +16,36 @@ void DistVersion::setMax(unsigned short newMax) {
_max = newMax;
}
int DistVersion::getMaxCompatible(const DistVersion &distVersion) const {
unsigned short midMax = std::min(distVersion.max(), _max);
unsigned short midMin = std::max(distVersion.min(), _min);
if (midMax < midMin)
return -1;
return midMax;
}
int DistVersion::getMinCompatible(const DistVersion &distVersion) const {
unsigned short midMax = std::min(distVersion.max(), _max);
unsigned short midMin = std::max(distVersion.min(), _min);
if (midMax < midMin)
return -1;
return midMin;
}
bool DistVersion::isSupport(unsigned short version) const {
return _min <= version && version <= _max;
}
QString DistVersion::toString() const {
return QString("%0:%1").arg(_min).arg(_max);
}
QDataStream &DistVersion::fromStream(QDataStream &stream) {
stream >> _min;
stream >> _max;
return stream;
@ -28,6 +57,10 @@ QDataStream &DistVersion::toStream(QDataStream &stream) const {
return stream;
}
DistVersion::operator bool() const {
return _min || _max;
}
unsigned short DistVersion::min() const {
return _min;
}

View File

@ -8,6 +8,7 @@
#ifndef DISTVERSION_H
#define DISTVERSION_H
#include "humanreadableobject.h"
#include <QHash>
#include <streambase.h>
@ -15,17 +16,42 @@
namespace QH {
/**
* @brief The DistVersion class This is infirmation of supported versions of the distanation api.
* @brief The DistVersion class This is information of supported versions of the destinations api.
*/
class DistVersion: public StreamBase {
class HEARTSHARED_EXPORT DistVersion: public StreamBase, public QuasarAppUtils::iHRO {
public:
operator bool() const;
unsigned short min() const;
void setMin(unsigned short newMin);
unsigned short max() const;
void setMax(unsigned short newMax);
/**
* @brief getMaxСompatible return maximum available on booth nodes version.
* @param distVersion this is dis version.
* @return return maximum version. if this version is not found return "-1"
*/
int getMaxCompatible(const DistVersion& distVersion) const;
/**
* @brief getMinСompatible return maximum available on booth nodes version.
* @param distVersion this is dis version.
* @return return minimum version. if this version is not found return "-1"
*/
int getMinCompatible(const DistVersion& distVersion) const;
/**
* @brief isSupport This method return true if the @a version is supported of this versions range.
* @param version This is checked version.
* @return true if the @a version is supported of this versions range.
*/
bool isSupport(unsigned short version) const;
QString toString() const override;
protected:
QDataStream &fromStream(QDataStream &stream) override;
@ -33,7 +59,7 @@ protected:
private:
/// This is monimum supported version.
/// This is minimum supported version.
unsigned short _min = 0;
/// This is maximum supported version.
@ -41,11 +67,15 @@ private:
};
/**
* @brief VersionData This is array of all avalable apis and supported its versions.
* @brief VersionData This is array of all available apis and supported its versions.
*/
typedef QHash<QString, DistVersion> VersionData;
/**
* @brief PackagesVersionData This is some as VersionData but for int commands.
*/
typedef QHash<unsigned short, DistVersion> PackagesVersionData;
}
#endif // DISTVERSION_H

View File

@ -10,6 +10,7 @@
#include <QString>
namespace QH {
Header::Header() {
reset();
}
@ -18,7 +19,7 @@ bool Header::isValid() const {
if (size > Package::maximumSize()) {
return false;
}
return command && hash;
return command && hash && headerVersion == 1 && unusedSpace1 == 0 && unusedSpace2 == 0 && unusedSpace3 == 0;
}
void Header::reset() {
@ -26,10 +27,14 @@ void Header::reset() {
command = 0;
triggerHash = 0;
hash = 0;
unusedSpace1 = 0;
unusedSpace2 = 0;
unusedSpace3 = 0;
}
QString Header::toString() const {
return QString("Header description: Size - %0, Command - %1, hash - %2, triggerHash - %3").
arg(size).arg(command).arg(QString::number(hash, 16), QString::number(triggerHash, 16));
return QString("Header description: HeaderVersion - %0, Size - %1, Command - %2, hash - %3, triggerHash - %4").
arg(headerVersion).arg(size).arg(command).arg(QString::number(hash, 16), QString::number(triggerHash, 16));
}
}

View File

@ -13,30 +13,42 @@
namespace QH {
/**
* @brief The Header struct 12 bytes.
* @brief The Header struct 32 bytes.
*/
#pragma pack(push, 1)
struct HEARTSHARED_EXPORT Header {
/**
* @brief command of package for more information see the AbstractData::toPackage method.
*/
unsigned short command;
unsigned short command = 0; //2 bytes
/**
* @brief headerVersion This is version of the header struct
*/
const unsigned char headerVersion = 1; //3 bytes
/**
* @brief size This is size of package data (exclude header size).
*/
unsigned int size;
unsigned int size = 0; //7 bytes
/**
* @brief hash This is unique id of a package. id calc with CRC32 function for Qt implementation.
*/
unsigned int hash;
unsigned int hash = 0; //11 bytes
/**
* @brief triggerHash This is hash of request package that package has been responded.
* The server should write to which command it responds.
*/
unsigned int triggerHash;
unsigned int triggerHash = 0; //15 bytes
/**
* @brief unusedSpace This is unused space for changes of the header struct in the future.
*/
unsigned long long unusedSpace1 = 0; //23 bytes
unsigned long long unusedSpace2 = 0; //31 bytes
unsigned char unusedSpace3 = 0; //32 bytes
/**
* @brief Header default constructor
@ -63,7 +75,6 @@ struct HEARTSHARED_EXPORT Header {
};
#pragma pack(pop)
}

View File

@ -31,8 +31,7 @@ QString iParser::pareseResultToString(const ParserResult &parseResult) {
}
}
const QHash<unsigned short, std::function<PKG::AbstractData *()> > &
iParser::registeredTypes() const {
const PacksMap &iParser::registeredTypes() const {
return _registeredTypes;
}
@ -58,7 +57,10 @@ unsigned int iParser::sendData(const PKG::AbstractData *resp,
const AbstractNodeInfo *dist,
const Header *req) const {
return node()->sendData(resp, dist, req);
}
const PackagesVersionData &iParser::multiVersionPackages() const {
return _multiVersionPackages;
}
void iParser::initSupportedCommands() {}

View File

@ -9,18 +9,21 @@
#ifndef IPARSER_H
#define IPARSER_H
#include "distversion.h"
#include "hostaddress.h"
#include <QSharedPointer>
#include <abstractdata.h>
#include <multiversiondata.h>
namespace QH {
class AbstractNodeInfo;
class AbstractNode;
namespace PKG {
class AbstractData;
}
/**
* @brief PacksMap This is hash map where id is command of package and value is factory function.
*/
using PacksMap = QHash<unsigned short, std::function<PKG::AbstractData *()>>;
/**
@ -60,6 +63,13 @@ public:
_registeredTypes[T::command()] = [](){
return new T();
};
if constexpr(std::is_base_of_v<PKG::MultiversionData, T>) {
T tmp;
if (const DistVersion &distVersion = tmp.packageVersion()) {
_multiVersionPackages[tmp.cmd()] = distVersion;
}
}
};
/**
@ -181,7 +191,7 @@ public:
* @return list of registered command.
* @see iParser::registerPackageType
*/
const QHash<unsigned short, std::function<PKG::AbstractData *()> > &registeredTypes() const;
const PacksMap &registeredTypes() const;
/**
* @brief genPackage This is factory method that generate data pacakge objects by command.
@ -213,6 +223,12 @@ public:
virtual void initSupportedCommands();
QString toString() const override;
/**
* @brief multiVersionPackages return list of the supported multiversions packages.
* @return list of the supported multiversions packages.
*/
const PackagesVersionData &multiVersionPackages() const;
protected:
AbstractNode *node() const;
@ -239,7 +255,10 @@ protected:
const Header *req = nullptr) const;
private:
QHash<unsigned short, std::function<PKG::AbstractData*()>> _registeredTypes;
// command - {version - factory}
PacksMap _registeredTypes;
PackagesVersionData _multiVersionPackages;
AbstractNode *_node;
friend class BigDataParserOld;

View File

@ -27,10 +27,7 @@ bool Package::isValid() const {
if (hdr.size > maximumSize())
return false;
if (calcHash() == hdr.hash)
return true;
return calcHashOld() == hdr.hash;
return calcHash() == hdr.hash;
}
void Package::reset() {
@ -41,7 +38,7 @@ void Package::reset() {
QString Package::toString() const {
return QString("Pakcage description: %0."
" Data description: Data size - %1, Data: %2").
arg(hdr.toString()).arg(data.size()).arg(QString(data.toHex().toUpper()));
arg(hdr.toString()).arg(data.size()).arg(QString(data.toHex().toUpper()));
}
unsigned int Package::calcHash() const {
@ -49,10 +46,6 @@ unsigned int Package::calcHash() const {
return qa_common::hash32(tmp.constData(), tmp.size());
}
unsigned int Package::calcHashOld() const {
return qHash(data + QByteArray::number(hdr.command));
}
unsigned int Package::maximumSize() {
return 1024 * 1024;
}

View File

@ -15,10 +15,9 @@
namespace QH {
class Abstract;
/**
* @brief The Package struct. This is base structure for transporting data by network between QH nodes.
* The Package contains a 12 bytes header and Package::data array. The size on the header should be equals size of Package::data array.
* The Package contains a 32 bytes header and Package::data array. The size on the header should be equals size of Package::data array.
*
*/
class HEARTSHARED_EXPORT Package: public StreamBase {
@ -60,13 +59,6 @@ public:
*/
unsigned int calcHash() const;
/**
* @brief calcHash This method recalc hash sum for this pacakge.
* @return int32 hash of pacakge.
*/
unsigned int calcHashOld() const;
/**
* @brief maximumSize This method return maximu size of pacakge. If pacakge large the maximum size then package will separate to BigDataPart in sending.
* @return size in bytes of pacakge.

View File

@ -21,46 +21,33 @@ AbstractData::AbstractData() {
}
bool AbstractData::toPackage(Package &package,
const DistVersion& ,
unsigned int triggerHash) const {
if (!checkCmd()) {
QuasarAppUtils::Params::log("You try send pacakge without QH_PACKAGE macross. Please add QH_PACKAGE macros to this class.",
QuasarAppUtils::Error);
return false;
}
if (!isValid()) {
return false;
}
package.data = toBytes();
package.hdr.command = cmd();
package.hdr.triggerHash = triggerHash;
package.hdr.size = package.data.size();
if (isOldPackage()) {
package.hdr.hash = package.calcHashOld();
} else {
package.hdr.hash = package.calcHash();
}
package.hdr.hash = package.calcHash();
return package.isValid();
}
bool AbstractData::checkCmd() const {
unsigned int code = typeid (*this).hash_code();
return code == localCode();
}
bool AbstractData::isValid() const {
return true;
}
QString AbstractData::toString() const {
return QString("Type: %0, command: %1").
return QString("Type: %0 \n"
"Command: %1 \n").
arg(cmdString()).
arg(cmd());
arg(cmd());
}
void AbstractData::fromPakcage(const Package &pkg) {
@ -71,9 +58,6 @@ AbstractData::~AbstractData() {
}
bool QH::PKG::AbstractData::isOldPackage() const {
return false;
}
}

View File

@ -7,8 +7,10 @@
#ifndef ABSTRACTDATA_H
#define ABSTRACTDATA_H
#include "distversion.h"
#include "humanreadableobject.h"
#include "package.h"
#include <QSharedPointer>
#include <streambase.h>
#include <crc/crchash.h>
@ -23,26 +25,24 @@
#define PROTOCKOL_VERSION_RECEIVED_COMMAND PROTOCKOL_VERSION_COMMAND - 1
/**
* @brief QH_PACKAGE This macross prepare data to send and create a global id for package. For get global id use the cmd method.
* @brief QH_PACKAGE This macross prepare data to send and create a global id for package.
* For get global id use the cmd method.
* For get quick access for global command use the ClassName::command() method. This method is static.
* @arg S This is unique id of the pacakge. Shold be some on all your network devices.
*/
#define QH_PACKAGE(X, S) \
#define QH_PACKAGE(S) \
public: \
static unsigned short command(){\
QByteArray ba = QString(S).toLocal8Bit();\
return qa_common::hash16(ba.data(), ba.size());\
} \
static QString commandText(){return S;} \
unsigned short cmd() const override {return X::command();} \
QString cmdString() const override {return X::commandText();} \
protected: \
unsigned int localCode() const override {return typeid(X).hash_code();} \
\
unsigned short cmd() const override {return command();} \
\
QString cmdString() const override {return S;} \
private:
#define QH_PACKAGE_AUTO(X) QH_PACKAGE(X,#X)
namespace QH {
namespace PKG {
@ -54,6 +54,7 @@ namespace PKG {
* \code{cpp}
* class MyPackage: public QH::AbstractData
{
QH_PACKAGE_AUTO_VER(MyPackage, 1)
public:
MyPackage();
@ -103,11 +104,12 @@ public:
/**
* @brief toPackage This method convert this class object to the package.
* For more info see Package class.
* @param package This is return value of Package class.
* @param package This is return value of Package class.
* @param reqVersion This is required version. This method create package of the needed version.
* @param triggerHash This is hash of the package the current class is responding to.
* @return True if convert to package finished successful.
*/
bool toPackage(Package &package, unsigned int triggerHash = 0) const;
virtual bool toPackage(Package &package, const DistVersion &reqVersion, unsigned int triggerHash = 0) const;
/**
* @brief isValid This method check current object to valid.
@ -158,24 +160,6 @@ protected:
*/
explicit AbstractData();
/**
* @brief localCode This method return local code
* @return local command of this class. used for check QH_PACKAGE macro before send pacakge.
*/
virtual unsigned int localCode() const = 0;
/**
* @brief isOldPackage This method mark package as a old, old pacakges use the Package::calcHashOld method for calculation hash sum of packages.
* @return true if the pacakge is old.
*/
virtual bool isOldPackage() const;
private:
/**
* @brief checkCmd This method check QH_PACKAGE macross.
* @return true if the QH_PACKAGE macross is enabled else fal.
*/
bool checkCmd() const;;
};

View File

@ -28,7 +28,6 @@ BadRequest::BadRequest(const Package &package):
}
QDataStream &BadRequest::fromStream(QDataStream &stream) {
stream >> _errCode;
stream >> _err;

View File

@ -33,7 +33,7 @@ struct ErrorData {
*/
class HEARTSHARED_EXPORT BadRequest : public AbstractData
{
QH_PACKAGE(BadRequest, "BadRequest")
QH_PACKAGE("BadRequest")
public:
/**

View File

@ -25,6 +25,7 @@ void BigDataBase::setPackageId(int newPackageId) {
}
QDataStream &BigDataBase::fromStream(QDataStream &stream) {
stream >> _packageId;
return stream;

View File

@ -19,7 +19,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT BigDataBase: public AbstractData
{
QH_PACKAGE(BigDataBase, "BigDataBase")
QH_PACKAGE("BigDataBase")
public:
BigDataBase();

View File

@ -27,7 +27,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT BigDataHeader : public BigDataBase
{
QH_PACKAGE(BigDataHeader, "BigDataHeader")
QH_PACKAGE("BigDataHeader")
public:
BigDataHeader();
@ -66,7 +66,7 @@ protected:
private:
int packagesCount;
unsigned short _command;
unsigned short _command = 0;
};
}
}

View File

@ -20,7 +20,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT BigDataPart : public BigDataBase
{
QH_PACKAGE(BigDataPart, "BigDataPart")
QH_PACKAGE("BigDataPart")
public:
BigDataPart();

View File

@ -19,7 +19,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT BigDataRequest: public BigDataBase
{
QH_PACKAGE(BigDataRequest, "BigDataRequest")
QH_PACKAGE("BigDataRequest")
public:
BigDataRequest();

View File

@ -19,7 +19,7 @@ namespace PKG {
*/
class BigDataWraper: public AbstractData
{
QH_PACKAGE(BigDataWraper, "BigDataWraper")
QH_PACKAGE("BigDataWraper")
public:
BigDataWraper() = default;

View File

@ -27,7 +27,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT CloseConnection: public AbstractData
{
QH_PACKAGE(CloseConnection, "CloseConnection")
QH_PACKAGE("CloseConnection")
public:
CloseConnection();

View File

@ -8,8 +8,7 @@
#ifndef DATAPACK_H
#define DATAPACK_H
#include "universaldata.h"
#include <abstractdata.h>
namespace QH {
namespace PKG {
@ -25,7 +24,7 @@ namespace PKG {
template<class Package>
class DataPack final: public AbstractData
{
QH_PACKAGE(DataPack<Package>, Package::commandText() + "Pack")
QH_PACKAGE(Package::commandText() + "Pack")
public:
@ -135,8 +134,8 @@ protected:
QDataStream &toStream(QDataStream &stream) const override {
stream << static_cast<int>(_packData.size());
for (const auto &ptr: qAsConst(_packData)) {
stream << *ptr;
for (const auto &data: qAsConst(_packData)) {
stream << *data;
}
stream << _data;
@ -144,7 +143,6 @@ protected:
return stream;
}
private:
QList<QSharedPointer<Package>> _packData;
QByteArray _data;

View File

@ -18,12 +18,6 @@ class QSqlQuery;
namespace QH {
namespace PKG {
/**
* The ONLY_DATABASE_PACKAGE macross is base macros for all database objects that do not use stream and network functions.
*/
#define ONLY_DATABASE_PACKAGE QH_PACKAGE(DBObject, "DBObject")
/**
* @brief The PrepareResult enum is result of work prepare sql query of dbobjects.
*/
@ -95,7 +89,7 @@ typedef QMap<QString, DBVariant> DBVariantMap;
*/
class HEARTSHARED_EXPORT DBObject : public AbstractData
{
QH_PACKAGE(DBObject, "DBObject")
QH_PACKAGE("DBObject")
public:

View File

@ -22,7 +22,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT DBObjectSet: public DBObject
{
QH_PACKAGE(DBObjectSet, "DBObjectSet")
QH_PACKAGE("DBObjectSet")
public:
DBObjectSet(const QString table);

View File

@ -25,7 +25,6 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT DeleteObject: public DBObject, public IToken
{
QH_PACKAGE(DeleteObject, "DeleteObject")
public:
DeleteObject();

View File

@ -19,7 +19,6 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT GetMaxIntegerId: public DBObject
{
QH_PACKAGE(GetMaxIntegerId, "GetMaxIntegerId")
public:
/**

View File

@ -38,7 +38,6 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT GetSingleValue final: public DBObject
{
QH_PACKAGE(GetSingleValue, "GetSingleValue")
public:
/**

View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2023-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#include "multiversiondata.h"
#include "qaglobalutils.h"
#include <QIODevice>
namespace QH {
namespace PKG {
#define MAGIC "mver"
MultiversionData::MultiversionData(const QMap<unsigned short /*version*/, SerializationBox>& serializers):
_serializers(serializers) {
if (serializers.size()) {
_packageVersion.setMax(serializers.lastKey());
_packageVersion.setMin(serializers.firstKey());
}
}
QDataStream &MultiversionData::fromStream(QDataStream &stream) {
if (!_serializers.size()) {
debug_assert(false,
"Your MultiversionData not support any serialized functions. "
"Please initialize it in constructor of the MultiversionData class.");
return stream;
}
QByteArray magic;
stream >> magic;
unsigned short version = 0;
if (magic == MAGIC) {
stream >> version;
} else {
stream.device()->seek(0);
}
return _serializers.value(version).from(stream);
}
QDataStream &MultiversionData::toStream(QDataStream &stream) const {
if (!_serializers.size()) {
debug_assert(false,
"Your MultiversionData not support any serialized functions. "
"Please initialize it in constructor of the MultiversionData class.");
return stream;
}
stream << QByteArray{MAGIC};
stream << _serializers.lastKey();
return _serializers.last().to(stream);
}
QByteArray MultiversionData::toBytesOf(const DistVersion& version) const {
QByteArray res;
QDataStream stream(&res, QIODevice::WriteOnly);
if (parsingVersion()) {
stream.setVersion(parsingVersion());
}
toStreamOf(stream, version);
return res;
}
QDataStream &MultiversionData::toStreamOf(QDataStream &stream, const DistVersion& version) const {
unsigned short ver = _packageVersion.getMaxCompatible(version);
auto serializer = _serializers.value(ver, {});
if (!serializer.to) {
debug_assert(false,
"Your MultiversionData not support the required version serialized functions. "
"Please initialize it in constructor of the MultiversionData class.");
return stream;
}
if (ver) {
stream << QByteArray{MAGIC};
stream << ver;
}
return serializer.to(stream);
}
bool MultiversionData::toPackage(Package &package,
const DistVersion& reqVersion,
unsigned int triggerHash) const {
if (!isValid()) {
return false;
}
package.data = toBytesOf(reqVersion);
package.hdr.command = cmd();
package.hdr.triggerHash = triggerHash;
package.hdr.size = package.data.size();
package.hdr.hash = package.calcHash();
return package.isValid();
}
const DistVersion &MultiversionData::packageVersion() const {
return _packageVersion;
}
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2023-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef MULTIVERSIONDATA_H
#define MULTIVERSIONDATA_H
#include "abstractdata.h"
namespace QH {
namespace PKG {
struct SerializationBox {
std::function<QDataStream& (QDataStream& stream)> from = nullptr;
std::function<QDataStream& (QDataStream& stream)> to = nullptr;
};
/**
* @brief The MultiversionData class This class add support for multiple versions of ne command/package.
* If you need to add support multiple versions make your pakcage class children of the MultiversionData class.
*
* Example:
*
* @code{cpp}
*
* class MyPackage: public MultiversionData {
MyPackage(): QH::PKG::MultiversionData(
{
{0, // version 0
{
[this](QDataStream& stream) -> QDataStream&{ // from
stream >> v1;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
stream << v1;
return stream;
}
}
},
{1, // version 1
{
[this](QDataStream& stream) -> QDataStream&{ // from
stream >> v1;
stream >> v2;
return stream;
},
[this](QDataStream& stream) -> QDataStream&{ // to
stream << v1;
stream << v2;
return stream;
}
}
}
}
) {};
* @endcode
*
* @note the default toBytes function of this class will be convert your class using latest version.
*/
class HEARTSHARED_EXPORT MultiversionData: public AbstractData
{
public:
/**
* @brief MultiversionData main constructor
* @param serializers this is map of the all supported versions.
*/
MultiversionData(const QMap<unsigned short /*version*/, SerializationBox>& serializers);
/**
* @brief packageVersion This method should be return number of the pacakge version.
* @return pcakge version. by default return - 0 (any version)
*/
const DistVersion& packageVersion() const;
QDataStream& fromStream(QDataStream& stream) override final;
QDataStream& toStream(QDataStream& stream) const override final;
/**
* @brief toBytesOf This is overload method of StreamBase::toBytes for support multi versions of packages.
* @param version This is required version pacakge.
* @return bytes array for package.
* @note This is just wrapper method for the AbstractData::toStream method.
*/
QByteArray toBytesOf(const DistVersion &version) const;
/**
* @brief toStreamOf This overrload of the base toStream method for support the multi version packages.
* @param stream this is stream object.
* @param version this is custom version of parsing function.
* @return stream object.
*/
QDataStream& toStreamOf(QDataStream& stream, const DistVersion &version) const;
bool toPackage(Package &package, const DistVersion &reqVersion, unsigned int triggerHash = 0) const override final;
private:
DistVersion _packageVersion;
QMap<unsigned short /*version*/, SerializationBox> _serializers;
};
}
}
#endif // MULTIVERSIONDATA_H

View File

@ -33,6 +33,7 @@ void Ping::setAnsver(bool ansver) {
}
QDataStream &Ping::fromStream(QDataStream &stream) {
stream >> _ansver;
return stream;

View File

@ -20,7 +20,7 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT Ping: public AbstractData
{
QH_PACKAGE(Ping, "Ping")
QH_PACKAGE("Ping")
public:
Ping();

View File

@ -32,8 +32,6 @@ namespace PKG {
*/
class HEARTSHARED_EXPORT SetSingleValue final: public DBObject
{
QH_PACKAGE(SetSingleValue, "SetSingleValue")
public:
/**
* @brief SetSingleValue This is default constructor of the update query generator.

View File

@ -43,6 +43,7 @@ QVariant *UniversalData::ref(int key) {
}
QDataStream &UniversalData::fromStream(QDataStream &stream) {
stream >> _data;
return stream;

View File

@ -22,7 +22,7 @@ namespace PKG {
* @code{cpp}
* class AuthRequest: public QH::PKG::UniversalData
{
QH_PACKAGE_AUTO(RC::API::V4::AuthRequest)
QH_PACKAGE(RC::API::V4::AuthRequest)
enum Filds{
UserId = 0