mirror of
https://github.com/QuasarApp/Heart.git
synced 2025-04-28 02:34:41 +00:00
Merge branch 'main' into openssl3_1_3
This commit is contained in:
commit
e668d5762c
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
360
HeartTests/units/multiversiontest.cpp
Normal file
360
HeartTests/units/multiversiontest.cpp
Normal 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);
|
||||
}
|
||||
}
|
39
HeartTests/units/multiversiontest.h
Normal file
39
HeartTests/units/multiversiontest.h
Normal 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
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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 *()> > ®isteredTypes() const;
|
||||
const PacksMap ®isteredTypes() 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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -28,7 +28,6 @@ BadRequest::BadRequest(const Package &package):
|
||||
}
|
||||
|
||||
QDataStream &BadRequest::fromStream(QDataStream &stream) {
|
||||
|
||||
stream >> _errCode;
|
||||
stream >> _err;
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct ErrorData {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT BadRequest : public AbstractData
|
||||
{
|
||||
QH_PACKAGE(BadRequest, "BadRequest")
|
||||
QH_PACKAGE("BadRequest")
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,7 @@ void BigDataBase::setPackageId(int newPackageId) {
|
||||
}
|
||||
|
||||
QDataStream &BigDataBase::fromStream(QDataStream &stream) {
|
||||
|
||||
stream >> _packageId;
|
||||
|
||||
return stream;
|
||||
|
@ -19,7 +19,7 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT BigDataBase: public AbstractData
|
||||
{
|
||||
QH_PACKAGE(BigDataBase, "BigDataBase")
|
||||
QH_PACKAGE("BigDataBase")
|
||||
|
||||
public:
|
||||
BigDataBase();
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT BigDataPart : public BigDataBase
|
||||
{
|
||||
QH_PACKAGE(BigDataPart, "BigDataPart")
|
||||
QH_PACKAGE("BigDataPart")
|
||||
|
||||
public:
|
||||
BigDataPart();
|
||||
|
@ -19,7 +19,7 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT BigDataRequest: public BigDataBase
|
||||
{
|
||||
QH_PACKAGE(BigDataRequest, "BigDataRequest")
|
||||
QH_PACKAGE("BigDataRequest")
|
||||
|
||||
public:
|
||||
BigDataRequest();
|
||||
|
@ -19,7 +19,7 @@ namespace PKG {
|
||||
*/
|
||||
class BigDataWraper: public AbstractData
|
||||
{
|
||||
QH_PACKAGE(BigDataWraper, "BigDataWraper")
|
||||
QH_PACKAGE("BigDataWraper")
|
||||
|
||||
public:
|
||||
BigDataWraper() = default;
|
||||
|
@ -27,7 +27,7 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT CloseConnection: public AbstractData
|
||||
{
|
||||
QH_PACKAGE(CloseConnection, "CloseConnection")
|
||||
QH_PACKAGE("CloseConnection")
|
||||
|
||||
public:
|
||||
CloseConnection();
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT DBObjectSet: public DBObject
|
||||
{
|
||||
QH_PACKAGE(DBObjectSet, "DBObjectSet")
|
||||
QH_PACKAGE("DBObjectSet")
|
||||
|
||||
public:
|
||||
DBObjectSet(const QString table);
|
||||
|
@ -25,7 +25,6 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT DeleteObject: public DBObject, public IToken
|
||||
{
|
||||
QH_PACKAGE(DeleteObject, "DeleteObject")
|
||||
|
||||
public:
|
||||
DeleteObject();
|
||||
|
@ -19,7 +19,6 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT GetMaxIntegerId: public DBObject
|
||||
{
|
||||
QH_PACKAGE(GetMaxIntegerId, "GetMaxIntegerId")
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -38,7 +38,6 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT GetSingleValue final: public DBObject
|
||||
{
|
||||
QH_PACKAGE(GetSingleValue, "GetSingleValue")
|
||||
|
||||
public:
|
||||
/**
|
||||
|
118
src/public/packages/multiversiondata.cpp
Normal file
118
src/public/packages/multiversiondata.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
113
src/public/packages/multiversiondata.h
Normal file
113
src/public/packages/multiversiondata.h
Normal 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
|
@ -33,6 +33,7 @@ void Ping::setAnsver(bool ansver) {
|
||||
}
|
||||
|
||||
QDataStream &Ping::fromStream(QDataStream &stream) {
|
||||
|
||||
stream >> _ansver;
|
||||
return stream;
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace PKG {
|
||||
*/
|
||||
class HEARTSHARED_EXPORT Ping: public AbstractData
|
||||
{
|
||||
QH_PACKAGE(Ping, "Ping")
|
||||
QH_PACKAGE("Ping")
|
||||
|
||||
public:
|
||||
Ping();
|
||||
|
@ -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.
|
||||
|
@ -43,6 +43,7 @@ QVariant *UniversalData::ref(int key) {
|
||||
}
|
||||
|
||||
QDataStream &UniversalData::fromStream(QDataStream &stream) {
|
||||
|
||||
stream >> _data;
|
||||
|
||||
return stream;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user