squash (50 commits, rename project)

This commit is contained in:
Andrei Yankovich 2020-09-15 21:16:35 +03:00
parent 1113590fb8
commit 0ec4b738a1
214 changed files with 15246 additions and 5033 deletions

4
.gitignore vendored
View File

@ -28,6 +28,10 @@ ui_*.h
*.jsc
Makefile*
*build-*
Heart/build/
HeartTests/build/
ServerProtocol/build/
ClientProtocol/build/
ProtocolTests/build/

6
.gitmodules vendored
View File

@ -1,7 +1,7 @@
[submodule "QuasarAppLib"]
path = QuasarAppLib
url = https://github.com/QuasarApp/QuasarAppLib.git
[submodule "openssl-cmake"]
path = openssl-cmake
url = https://github.com/QuasarApp/openssl-cmake.git
[submodule "Heart/Qt-Secret"]
path = Heart/Qt-Secret
url = https://github.com/QuasarApp/Qt-Secret.git

View File

@ -5,15 +5,26 @@
# of this license document, but changing it is not allowed.
#
cmake_minimum_required(VERSION 3.1)
project(MainNetworkProtocol)
cmake_minimum_required(VERSION 3.10)
project(Heart)
if(TARGET ${PROJECT_NAME})
message("The ${PROJECT_NAME} arledy included in main Project")
return()
endif()
find_package(Qt5 COMPONENTS Core Test REQUIRED)
if(NOT DEFINED BUILD_LVL)
set(BUILD_LVL 2)
endif()
include(QuasarAppLib/CMake/ccache.cmake)
# Add sub directories
add_subdirectory(QuasarAppLib)
add_subdirectory(openssl-cmake)
add_subdirectory(NetworkProtocol)
add_subdirectory(ProtocolTests)
add_subdirectory(Heart)
add_subdirectory(HeartTests)
include(QuasarAppLib/CMake/QuasarAppCITargets.cmake)
initAll()
addDoc(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.conf)

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,502 @@
/*
* Copyright (C) 2018-2020 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 ABSTRACTNODE_H
#define ABSTRACTNODE_H
#include "abstractnodeinfo.h"
#include <openssl/evp.h>
#include <QAbstractSocket>
#include <QFutureWatcher>
#include <QMutex>
#include <QSslConfiguration>
#include <QTcpServer>
#include <QTimer>
#include "abstractdata.h"
#include "workstate.h"
#include "cryptopairkeys.h"
#include "icrypto.h"
#include "heart_global.h"
#include "receivedata.h"
#include "packagemanager.h"
class QSslCertificate;
class QSslKey;
class QSslConfiguration;
namespace NP {
class DataSender;
/**
* @brief The ParserResult enum
* Error - parser detect a errorob package
* NotProcessed - the parser does not know what to do with the package or has not finished processing it.
* Processed - the parser finished processing correctly
*/
enum class ParserResult {
/// parser detect a errorob package
Error = 0,
/// the parser does not know what to do with the package or has not finished processing it.
NotProcessed = 1,
/// the parser finished processing correctly
Processed = 2
};
enum class SslMode {
NoSSL,
InitFromSystem,
InitSelfSigned
};
/**
* @brief The SslSrtData struct
*/
struct SslSrtData {
QString country = "BY";
QString organization = "QuasarApp";
QString commonName = "Dev";
long long endTime = 31536000L; //1 year
};
#define CRITICAL_ERROOR -50
#define LOGICK_ERROOR -20
#define REQUEST_ERROR -5
class Abstract;
/**
* @brief The AbstractNode class - Abstract implementation of node.
* this implementation have a methods for send and receive data messages,
* and work with crypto method for crease a security connections betwin nodes.
* AbstractNode - is thread save class
*/
class NETWORKPROTOCOLSHARED_EXPORT AbstractNode : public QTcpServer
{
Q_OBJECT
public:
/**
* @brief AbstractNode
* @param ssl
* @param ptr
*/
AbstractNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr);
~AbstractNode() override;
/**
* @brief run
* @param addres - If address is empty then serve weel be listen all addreses of all interfaces
* @param port
* @return true if all good
*/
virtual bool run(const QString& addres, unsigned short port);
/**
* @brief stop stop this node and close all connections.
*/
virtual void stop();
/**
* @brief getInfo
* @param id of selected node
* @return pointer to information about node. if address not found return nullpt
*/
virtual AbstractNodeInfo* getInfoPtr(const HostAddress &id);
/**
* @brief getInfoPtr
* @param id peer adders
* @return pointer to information about node. if address not found return nullpt
*/
virtual const AbstractNodeInfo* getInfoPtr(const HostAddress &id) const;
/**
* @brief ban
* @param target id of ban node
*/
virtual void ban(const HostAddress& target);
/**
* @brief unBan
* @param target id of unban node
*/
virtual void unBan(const HostAddress& target);
/**
* @brief connectToHost - connect to host node
* @param address - address of node
* @param mode - mode see SslMode
*/
virtual bool connectToHost(const HostAddress &address, SslMode mode = SslMode::NoSSL);
/**
* @brief connectToHost - connect to host node. this method find ip address of domain befor connecting
* @param domain: address of node
* @param port - port of node
* @param mode - mode see SslMode
*/
virtual bool connectToHost(const QString &domain, unsigned short port, SslMode mode = SslMode::NoSSL);
/**
* @brief addNode - add new node for connect
* @param nodeAdderess - the network addres of a new node.
*/
void addNode(const HostAddress& nodeAdderess);
/**
* @brief removeNode - remove node
* @param nodeAdderess - the adddress of removed node.
*/
void removeNode(const HostAddress& nodeAdderess);
/**
* @brief address - address of this node
* @return return current adders
*/
HostAddress address() const;
/**
* @brief getSslConfig - configuration of this node.
* @return current ssl configuration on this nod
*/
QSslConfiguration getSslConfig() const;
/**
* @brief getMode
* @return
*/
SslMode getMode() const;
/**
* @brief getWorkState
* @return
*/
virtual WorkState getWorkState() const;
/**
* @brief pareseResultToString
* @return string of pareseresult
*/
QString pareseResultToString(const ParserResult& parseResult) const;
/**
* @brief connectionsCount - return count fo connections (nodes with status connected)
* @return
*/
int connectionsCount() const;
/**
* @brief connectionsCount - return count of nodes with status confirmend
* @return
*/
int confirmendCount() const;
/**
* @brief ping - ping address for testing
* @param address - address of other node
* @return true if ping sendet
*/
bool ping( const HostAddress& address);
signals:
void requestError(QString msg);
protected:
/**
* @brief generateRSAforSSL
* @param pkey -
* @return
*/
virtual bool generateRSAforSSL(EVP_PKEY* pkey) const;
/**
* @brief generateSslData - generate new ssl data
* @param data - sign data
* @param r_srt - result srt
* @param r_key - result private key
* @return true if all good
*/
virtual bool generateSslDataPrivate(const SslSrtData& data, QSslCertificate& r_srt, QSslKey& r_key);
/**
* @brief selfSignedSslConfiguration
* @return generate new keys and use it
*/
virtual QSslConfiguration selfSignedSslConfiguration();
/**
* @brief createNodeInfo
* @return nodeinfo for new connection
* override this metho for set your own nodeInfo objects;
*/
virtual AbstractNodeInfo* createNodeInfo(QAbstractSocket *socket,
const HostAddress *clientAddress = nullptr) const;
/**
* @brief registerSocket - this method registration new socket
* @param socket - socket pointer
* @param incoming - host address of socket. by default is nullptr.
* Set this value for nodes created on this host
* @return return true if the scoeket has been registered successful
*/
virtual bool registerSocket(QAbstractSocket *socket, const HostAddress* address = nullptr);
/**
* @brief parsePackage
* @param pkg
* @param sender
* @return item of ParserResult ()
*/
virtual ParserResult parsePackage(const Package &pkg, const AbstractNodeInfo* sender);
/**
* @brief sendPackage
* @param pkg
* @param target
* @return
*/
virtual bool sendPackage(const Package &pkg, QAbstractSocket *target) const;
/**
* @brief sendData send data package to address and prepare object to sending.
* @param resp - pointer to sendet object
* @param address - target addres for sending
* @param req - header of request
* @return true if data sendet succesful.
*/
virtual bool sendData(AbstractData *resp, const HostAddress& addere,
const Header *req = nullptr);
/**
* @brief sendData this is some as a sendData(AbstractData *resp ...) exept this method not prepare object for sending.
* @param resp - pointer to sendet object
* @param address - target addres for sending
* @param req - header of request
* @return true if data sendet succesful.
*/
virtual bool sendData(const AbstractData *resp, const HostAddress& addere,
const Header *req = nullptr);
/**
* @brief badRequestu
* @param address
* @param req
* @param msg - message of error
*/
virtual void badRequest(const HostAddress &address, const Header &req,
const QString msg = "");
/**
* @brief getWorkStateString
* @return string of work state
*/
virtual QString getWorkStateString() const;
/**
* @brief connectionState
* @return string with count users state
*/
virtual QString connectionState() const;
/**
* @brief banedList
* @return list of baned nodes
*/
QList<HostAddress> banedList() const;
/**
* @brief isBanned
* @param socket
* @return
*/
bool isBanned(QAbstractSocket* socket) const;
/**
* @brief incomingConnection
* @param handle
*/
void incomingConnection(qintptr handle) override;
/**
* @brief changeTrust change trust of connected node
* @param id - id of select node
* @param diff
* @return true if all good
*/
virtual bool changeTrust(const HostAddress& id, int diff);
/**
* @brief incomingConnection for ssl sockets
* @param handle - handle of socket
*/
virtual void incomingSsl(qintptr handle);
/**
* @brief incomingConnection for tcp sockets
* @param handle - handle of socket
*/
virtual void incomingTcp(qintptr handle);
/**
* @brief setMode - invoke this method befor run method
* @param mode
*/
bool setMode(const SslMode &mode);
/**
* @brief incomingData - this signal invoked when node get command or ansver
* @param pkg - get package (in this implementation it is only the Ping command)
* @param sender - sender of the package
* @note override this method for get a signals.
*/
virtual void incomingData(AbstractData* pkg,
const HostAddress& sender);
/**
* @brief connections - return hash map of all connections of this node.
* @return
*/
QHash<HostAddress, AbstractNodeInfo*> connections() const;
/**
* @brief connectionRegistered Override this method for get registered incoming connections.
* @param info - connection information.
*/
virtual void connectionRegistered(const AbstractNodeInfo *info);
/**
* @brief nodeStatusChanged - This method invoked when status of node chganged.
* Base implementation do nothing. Override this method for add own functionality.
* @param node - address of changed node.
* @param status - new status of node.
*
*/
void nodeStatusChanged(const HostAddress& node, NodeCoonectionStatus status);
/**
* @brief nodeConfirmend - thim method invocked when the node status changed to "confirmend"
* default implementatio do nothing
* @param node - the address of changed node
*/
virtual void nodeConfirmend(const HostAddress& node);
/**
* @brief nodeConnected thim method invocked when the node status changed to "connected"
* default implementatio do nothing
* @param node
*/
virtual void nodeConnected(const HostAddress& node);
/**
* @brief nodeConnected thim method invocked when the node status changed to "disconnected"
* default implementatio do nothing
* @param node
*/
virtual void nodeDisconnected(const HostAddress& node);
/**
* @brief pushToQueue - This method add action to queue. When the node status will be equal 'triggerStatus' then node run a action method.
* @param node - node.
* @param action - lyamda function with action.
* @param triggerStatus - node status.
*/
void pushToQueue(const std::function<void ()> &action,
const HostAddress& node,
NodeCoonectionStatus triggerStatus);
/**
* @brief takeFromQueue - take the list of actions of node. after invoke take elements will be removed.
* @param node - node
* @param triggerStatus - status of node
* @return list o actions
*/
QList<std::function<void ()>> takeFromQueue(const HostAddress& node,
NodeCoonectionStatus triggerStatus);
private slots:
void avelableBytes();
void handleDisconnected();
void handleConnected();
void handleCheckConfirmendOfNode(HostAddress node);
/**
* @brief handleWorkerStoped
*/
void handleWorkerStoped();
/**
* @brief handleForceRemoveNode - force remove connection.
* @param node
*/
void handleForceRemoveNode(HostAddress node);
/**
* @brief connectNodePrivate
*/
void connectNodePrivate(NP::HostAddress);
private:
/**
@note just disaable listen method in the node objects.
*/
bool listen(const HostAddress& address = HostAddress::Any);
/**
* @brief newWork - this method it is wraper of the parsePackage method.
* the newWork invoke a parsePackage in the new thread.
* @param pkg
* @param sender
*/
void newWork(const Package &pkg, const AbstractNodeInfo* sender, const HostAddress &id);
/**
* @brief nodeConfirmet - this metthod invoked when node is confirment.
* @param sender - node with new status;
*/
void nodeConfirmet(const HostAddress &node);
/**
* @brief checkConfirmendOfNode - this method remove old not confirmed node.
* @param node - node address
*/
void checkConfirmendOfNode(const HostAddress& node);
SslMode _mode;
QSslConfiguration _ssl;
QHash<HostAddress, AbstractNodeInfo*> _connections;
QHash<HostAddress, ReceiveData> _receiveData;
QHash<HostAddress, QHash<NodeCoonectionStatus, QList<std::function<void()>>>> _actionCache;
DataSender * _dataSender = nullptr;
QSet<QFutureWatcher <bool>*> _workers;
PackageManager _packageManager;
mutable QMutex _connectionsMutex;
mutable QMutex _actionCacheMutex;
mutable QMutex _confirmNodeMutex;
friend class WebSocketController;
};
}
#endif // ABSTRACTNODE_H

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2018-2020 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 "abstractnodeinfo.h"
#include <hostaddress.h>
#include <QAbstractSocket>
#include <QDataStream>
#include <QHostInfo>
namespace NP {
AbstractNodeInfo::AbstractNodeInfo(QAbstractSocket *sct,
const HostAddress *address) {
setSct(sct);
if (address)
setNetworkAddress(*address);
}
AbstractNodeInfo::~AbstractNodeInfo() {}
QAbstractSocket *AbstractNodeInfo::sct() const {
return _sct;
}
void AbstractNodeInfo::disconnect() {
if (_sct) {
_sct->close();
_sct->deleteLater();
_sct = nullptr;
}
}
void AbstractNodeInfo::ban() {
_trust = static_cast<int>(TrustNode::Baned);
disconnect();
}
bool AbstractNodeInfo::isBanned() const {
return _trust < 1;
}
void AbstractNodeInfo::unBan() {
_trust = static_cast<int>(TrustNode::Restore);
}
void AbstractNodeInfo::setSct(QAbstractSocket *sct) {
_sct = sct;
if (_sct && !_sct->peerAddress().isNull()) {
setNetworkAddress(HostAddress{_sct->peerAddress(), _sct->peerPort()});
}
}
void AbstractNodeInfo::setIsLocal(bool isLocal) {
_isLocal = isLocal;
}
NodeCoonectionStatus AbstractNodeInfo::status() const {
return _status;
}
void AbstractNodeInfo::setStatus(const NodeCoonectionStatus &status) {
_status = status;
}
bool AbstractNodeInfo::confirmData() const {
return _status != NodeCoonectionStatus::NotConnected;
}
bool AbstractNodeInfo::isLocal() const {
return _isLocal;
}
HostAddress AbstractNodeInfo::networkAddress() const {
if (isValid() && _sct->isValid())
return HostAddress{_sct->peerAddress(), _sct->peerPort()};
return _networkAddress;
}
void AbstractNodeInfo::setNetworkAddress(const HostAddress &networkAddress) {
if (!networkAddress.isNull()) {
_networkAddress = networkAddress;
QHostInfo::lookupHost(_networkAddress.toString(), [this] (QHostInfo info){
if (dynamic_cast<AbstractNodeInfo*>(this)) {
setInfo(info);
}
});
}
}
void AbstractNodeInfo::setInfo(const QHostInfo &info) {
if (!_info)
_info = new QHostInfo();
*_info = info;
}
QHostInfo *AbstractNodeInfo::info() const {
return _info;
}
int AbstractNodeInfo::trust() const {
return _trust;
}
void AbstractNodeInfo::setTrust(int trust) {
_trust = trust;
if (isBanned()) {
disconnect();
}
}
bool AbstractNodeInfo::isValid() const {
return _sct;
}
bool AbstractNodeInfo::isConnected() const {
return isValid() && _sct->isOpen();
}
QDataStream &AbstractNodeInfo::fromStream(QDataStream &stream) {
stream >> _networkAddress;
return stream;
}
QDataStream &AbstractNodeInfo::toStream(QDataStream &stream) const {
stream << _networkAddress;
return stream;
}
uint qHash(NodeCoonectionStatus status) {
return static_cast<uint>(status);
}
}

View File

@ -0,0 +1,213 @@
/*
* Copyright (C) 2018-2020 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 ABSTRACTNODEINFO_H
#define ABSTRACTNODEINFO_H
#include "hostaddress.h"
#include "heart_global.h"
#include <hostaddress.h>
class QAbstractSocket;
class QHostInfo;
namespace NP {
/**
* @brief The TrustNode enum
*/
enum class TrustNode: unsigned char {
/// undefined node
Undefined = 0xFF,
/// general trust of node
Default = 100,
/// this trusted of unbaned nodes
Restore = 20,
/// node with this trusted is forbidden
Baned = 0
};
/**
* @brief The AbstractNodeState enum - This is status of known nodes.
*/
enum class NodeCoonectionStatus: int {
/// This node not sent data about its envirement
NotConnected,
/// The node with this status has already sent data about its environment.
Connected,
/// The node confirmend. Node with it status sent a information
/// requarement for confirm in to this node object.
Confirmed,
};
uint qHash(NodeCoonectionStatus status);
/**
* @brief The AbstractNodeInfo class
*/
class NETWORKPROTOCOLSHARED_EXPORT AbstractNodeInfo
{
public:
/**
* @brief AbstractNodeInfo
* @param sct socket of connection
* @param address - address of socket
*/
AbstractNodeInfo(QAbstractSocket *sct = nullptr,
const HostAddress* address = nullptr);
/**
* @brief ~AbstractNodeInfo
*/
virtual ~AbstractNodeInfo();
/**
* @brief sct
* @return return socket of connection
*/
QAbstractSocket *sct() const;
/**
* @brief disconnect disconnect from host
*/
virtual void disconnect();
/**
* @brief ban this node
*/
virtual void ban();
/**
* @brief isBanned
* @return true if node baned
*/
virtual bool isBanned() const;
/**
* @brief unBan
*/
virtual void unBan();
/**
* @brief trust
* @return rtust
*/
virtual int trust() const;
/**
* @brief setTrust manual set value of trust
* @param trust - new value
*/
virtual void setTrust(int trust);
/**
* @brief isValid
* @return true if all data valid
*/
virtual bool isValid() const;
/**
* @brief isConnected
* @return true if the socket connected
*/
virtual bool isConnected() const;
/**
* @brief fromStream
* @param stream
* @return stream
*/
virtual QDataStream& fromStream(QDataStream& stream);
/**
* @brief toStream
* @param stream
* @return stream
*/
virtual QDataStream& toStream(QDataStream& stream) const;
/**
* @brief info
* @return Host info of this node
*/
QHostInfo *info() const;
/**
* @brief setInfo - set new temp info for this node
* @param info
*/
void setInfo(const QHostInfo &info);
/**
* @brief networkAddress
* @return network adderess of node
*/
HostAddress networkAddress() const;
/**
* @brief setNetworkAddress - update network address
* @param networkAddress - new address
*/
void setNetworkAddress(const HostAddress &networkAddress);
/**
* @brief status - status of node connection
* @return connection status
*/
NodeCoonectionStatus status() const;
/**
* @brief setStatus - set new value of status node
* @param status - new status
*/
void setStatus(const NodeCoonectionStatus &status);
/**
* @brief confirmData - check all data of node and return true if node is confirmed
* @return true if node is confirmed
*/
virtual bool confirmData() const;
/**
* @brief isLocal - return true if connectuion opened on this node.
* @return
*/
bool isLocal() const;
/**
* @brief setIsLocal - set local status for this Node.
* @param isLocal
*/
void setIsLocal(bool isLocal);
protected:
/**
* @brief setSct
* @param sct
*/
void setSct(QAbstractSocket *sct);
private:
QHostInfo *_info = nullptr;
HostAddress _networkAddress;
QAbstractSocket *_sct = nullptr;
int _trust = static_cast<int>(TrustNode::Default);
NodeCoonectionStatus _status = NodeCoonectionStatus::NotConnected;
bool _isLocal = false;
};
}
#endif // ABSTRACTNODEINFO_H

View File

@ -0,0 +1,9 @@
#ifndef ATOMICMETATYPES_H
#define ATOMICMETATYPES_H
#include <QMetaType>
Q_DECLARE_METATYPE(const bool*)
Q_DECLARE_METATYPE(bool*)
#endif // ATOMICMETATYPES_H

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2018-2020 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 CONFIG_H
#define CONFIG_H
#include <QStandardPaths>
// network settings
#define LOCAL_SERVER "127.0.0.1"
#define DEFAULT_PORT 3090
#define WAIT_CONFIRM_TIME 30000 // 30000 msec = 30 sec
// Data Base settings
#define DEFAULT_DB_NAME "Storage.sqlite"
#define DEFAULT_DB_PATH QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
#define DEFAULT_DB_INIT_FILE_PATH ":/sql/DataBaseSpace/Res/BaseDB.sql"
#define DEFAULT_UPDATE_INTERVAL 3600000 // 1 hour
// Transport Protockol settings
#define ROUTE_COUNT_LIMIT 1000
#define TRANSPORT_PACKAGES_CACHE 1000
// Node Settings
#define PACKAGE_CACHE_SIZE 1000
// Other settings
#ifdef RELEASE_BUILD
#define WAIT_TIME 30000
#define WAIT_RESPOCE_TIME 10000
#else
#define WAIT_TIME 300000000
#define WAIT_RESPOCE_TIME 100000000
#endif
#endif // CONFIG_H

View File

@ -0,0 +1,73 @@
#include "cryptopairkeys.h"
#include <QDataStream>
namespace NP {
CryptoPairKeys::CryptoPairKeys() {
}
CryptoPairKeys::CryptoPairKeys(const QByteArray &pubKey, const QByteArray &privKey) {
setPrivKey(privKey);
setPublicKey(pubKey);
setBits(privKey.size() * 8);
}
bool CryptoPairKeys::isValid() const {
return _privKey.size() && _publicKey.size() && !(_bits % 8) && _bits > 1;
}
QByteArray CryptoPairKeys::privKey() const {
return _privKey;
}
void CryptoPairKeys::setPrivKey(const QByteArray &privKey) {
_privKey = privKey;
}
QByteArray CryptoPairKeys::publicKey() const {
return _publicKey;
}
void CryptoPairKeys::setPublicKey(const QByteArray &publicKey) {
_publicKey = publicKey;
}
int CryptoPairKeys::bits() const {
return _bits;
}
void CryptoPairKeys::setBits(int bits) {
_bits = bits;
}
QDataStream &CryptoPairKeys::fromStream(QDataStream &stream) {
stream >> _publicKey;
stream >> _privKey;
stream >> _bits;
return stream;
}
QDataStream &CryptoPairKeys::toStream(QDataStream &stream) const {
stream << _publicKey;
stream << _privKey;
stream << _bits;
return stream;
}
bool operator ==(const CryptoPairKeys &left, const CryptoPairKeys &right) {
return !(left != right);
}
bool operator !=(const CryptoPairKeys &left, const CryptoPairKeys &right) {
return left._privKey != right._privKey || left._publicKey != right._publicKey;
}
uint qHash(const CryptoPairKeys &value) {
return qHash(value.privKey());
}
}

View File

@ -0,0 +1,59 @@
#ifndef CRYPTOPAIRKEYS_H
#define CRYPTOPAIRKEYS_H
#include "streambase.h"
namespace NP {
/**
* @brief The CryptoPairKeys class contains pair keys.
*/
class NETWORKPROTOCOLSHARED_EXPORT CryptoPairKeys: public StreamBase
{
public:
CryptoPairKeys();
CryptoPairKeys(const QByteArray& pubKey, const QByteArray& privKey);
/**
* @brief isValid
* @return true if this objcet contains pair keys
*/
bool isValid() const;
QByteArray privKey() const;
void setPrivKey(const QByteArray &privKey);
QByteArray publicKey() const;
void setPublicKey(const QByteArray &publicKey);
/**
* @brief bits
* @return bits size of keys pair
*/
int bits() const;
/**
* @brief setBits
* @param bits
*/
void setBits(int bits);
friend bool operator != (const CryptoPairKeys& left, const CryptoPairKeys& right);
friend bool operator == (const CryptoPairKeys& left, const CryptoPairKeys& right);
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream);
QDataStream &toStream(QDataStream &stream) const;
private:
QByteArray _privKey;
QByteArray _publicKey;
int _bits;
};
uint qHash(const CryptoPairKeys& value);
}
#endif // CRYPTOPAIRKEYS_H

View File

@ -0,0 +1,19 @@
#include "datasender.h"
#include <QAbstractSocket>
#include <quasarapp.h>
#include <QThread>
namespace NP {
DataSender::DataSender() {
}
void NP::DataSender::sendPackagePrivate(QByteArray array, void *target) const {
auto ptr = static_cast<QAbstractSocket*>(target);
if (array.size() != ptr->write(array)) {
QuasarAppUtils::Params::log("not writed data to socket", QuasarAppUtils::Error);
}
}
}

View File

@ -0,0 +1,29 @@
#ifndef DATASENDER_H
#define DATASENDER_H
#include <QObject>
class QAbstractSocket;
namespace NP {
/**
* @brief The DataSender class - this class create a queue for sendet data to network.
* work on a main thread
*/
class DataSender: public QObject
{
Q_OBJECT
public:
DataSender();
public slots:
/**
* @brief sendPackagePrivate
* @param array
* @param target
*/
void sendPackagePrivate(QByteArray array, void *target) const;
};
}
#endif // DATASENDER_H

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2018-2020 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 "header.h"
#include <QString>
namespace NP {
Header::Header() {
reset();
}
bool Header::isValid() const {
return command && size && hash;
}
void Header::reset() {
size = 0;
command = 0;
triggerHash = 0;
hash = 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)).arg(QString::number(triggerHash, 16));
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2018-2020 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 ABSTRACTHEADER_H
#define ABSTRACTHEADER_H
#include "heart_global.h"
namespace NP {
/**
* @brief The Header struct 12 byte
*/
#pragma pack(push, 1)
struct NETWORKPROTOCOLSHARED_EXPORT Header{
/**
* @brief size - size of package data (not header)
*/
unsigned short size;
/**
* @brief command of pacage
*/
unsigned short command;
/**
* @brief hash - is uniqueue id of a package. id calc with CRC32 function fo Qt implamentation. qHash(QByteArray)
*/
unsigned int hash;
/**
* @brief triggerHash - this is hash of request package that this package has been responded
* the server should write to which command it responds
*/
unsigned int triggerHash;
/**
* @brief Header default constructor
*/
Header();
~Header() = default;
/**
* @brief isValid
* @return true if header is valid
*/
bool isValid() const;
/**
* @brief reset - reset all data and set for header invalid status
*/
void reset();
/**
* @brief toString - return string of header of package
* @return
*/
QString toString() const;
};
#pragma pack(pop)
}
#endif // ABSTRACTHEADER_H

View File

@ -0,0 +1,60 @@
#include "hostaddress.h"
#include <QDataStream>
#include <quasarapp.h>
namespace NP {
HostAddress::HostAddress() {
}
HostAddress::HostAddress(const QHostAddress &other, int port):
QHostAddress(other) {
setPort(port);
}
HostAddress::HostAddress(const QString &other, int port):
QHostAddress(other) {
setPort(port);
}
HostAddress::HostAddress(const QHostAddress::SpecialAddress &other, int port):
QHostAddress(other) {
setPort(port);
}
HostAddress::HostAddress(const HostAddress &other):
QHostAddress(*static_cast<const HostAddress*>(&other)) {
setPort(other.port());
}
unsigned short HostAddress::port() const {
return _port;
}
void HostAddress::setPort(unsigned short port) {
debug_assert(port);
_port = port;
}
QDataStream &operator >>(QDataStream &stream, HostAddress &address) {
stream >> static_cast<QHostAddress&>(address);
stream >> address._port;
return stream;
}
QDataStream &operator <<(QDataStream &stream, const HostAddress &address) {
stream << static_cast<const QHostAddress&>(address);
stream << address._port;
return stream;
}
uint qHash(const HostAddress &address) {
return qHash(QString("%1:%2").arg(address.toString()).arg(address.port()));
}
}

View File

@ -0,0 +1,39 @@
#ifndef HOSTADDRESS_H
#define HOSTADDRESS_H
#include "heart_global.h"
#include <QHostAddress>
#include "config.h"
namespace NP {
/**
* @brief The HostAddress class - this is Wraper of QHostAddress
*/
class NETWORKPROTOCOLSHARED_EXPORT HostAddress: public QHostAddress
{
public:
explicit HostAddress();
explicit HostAddress(const QHostAddress& other, int port = DEFAULT_PORT);
explicit HostAddress(const QString& other, int port = DEFAULT_PORT);
HostAddress(const SpecialAddress& other, int port = DEFAULT_PORT);
HostAddress(const HostAddress& other);
unsigned short port() const;
void setPort(unsigned short port);
friend QDataStream& operator << (QDataStream& stream, const HostAddress& address);
friend QDataStream& operator >> (QDataStream& stream, HostAddress& address);
private:
unsigned short _port = 0;
};
uint qHash(const HostAddress& address);
}
Q_DECLARE_METATYPE(NP::HostAddress);
#endif // HOSTADDRESS_H

View File

@ -0,0 +1,10 @@
#include "icrypto.h"
namespace NP {
ICrypto::ICrypto() = default;
ICrypto::~ICrypto() = default;
}

View File

@ -0,0 +1,95 @@
#ifndef ICRYPTO_H
#define ICRYPTO_H
#include <QList>
#include <QThread>
#include "heart_global.h"
#include <QByteArray>
#include <QHash>
#include <QSet>
#define RAND_KEY ""
class QMutex;
namespace NP {
class CryptoPairKeys;
/**
* @brief The ICrypto class provide cryptografu functionality.
* this is interface for decaration of KeyStorage classes.
*/
class NETWORKPROTOCOLSHARED_EXPORT ICrypto
{
public:
ICrypto();
virtual ~ICrypto();
/**
* @brief isValid
* @return true if the crypto object is valid.
*/
virtual bool isValid() const = 0;
/**
* @brief crypt
* @param data - pointer to data array for crypting.
* @note data as ben changed after call this method.
* @param publicKey - key for crypting data
* @return true if function finished seccussful
*/
virtual bool crypt(QByteArray *data, const QByteArray& publicKey) = 0;
/**
* @brief decrypt
* @param cryptedData - pointer to data array for decrypting.
* @note cryptedData as ben changed after call this method.
* @param privateKey
* @return true if function finished seccussful
*/
virtual bool decrypt(QByteArray *cryptedData, const QByteArray& privateKey) = 0;
/**
* @brief sign
* @param data - pointer to data array for signed.
* @note data as ben changed after call this method.
* @param privateKey
* @return true if function finished seccussful
*/
virtual bool sign(QByteArray* data, const QByteArray& privateKey) = 0;
/**
* @brief extractSign - extract sign from signed byteArray
* @param data - signed message.
* @return return array of sign.
*/
virtual QByteArray extractSign(const QByteArray& data) = 0;
/**
* @brief concatSign
* @param data - message data
* @return signed message
*/
virtual QByteArray concatSign(const QByteArray& data, const QByteArray& sign) = 0;
/**
* @brief check
* @param publicKey
* @return true if function finished seccussful and signedData is valid.
*/
virtual bool check(const QByteArray& signedData, const QByteArray& publicKey) = 0;
/**
* @brief generate a new key. Default implementation do nothing.
* @note Override this method for create of new class with new keys type.
* @param genesis
* @return crypto pair keys
*/
virtual CryptoPairKeys generate(const QByteArray& genesis = {}) const = 0;
};
}
#endif // CRYPTO_H

View File

@ -0,0 +1,383 @@
#include "cryptopairkeys.h"
#include "icrypto.h"
#include "keystorage.h"
#include <quasarapp.h>
#include <QCoreApplication>
#include <QDataStream>
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QMutex>
#include <QStandardPaths>
#include "config.h"
namespace NP {
#define THE_CLASS(x) QString::fromLatin1(typeid(*x).name())
#define VERSION_FILE "version"
KeyStorage::KeyStorage(ICrypto * cryptoMethod) {
_keyPoolSizeMutex = new QMutex();
_keysMutex = new QMutex();
_taskMutex = new QMutex();
_cryptoMethod = cryptoMethod;
assert(_cryptoMethod);
}
KeyStorage::~KeyStorage() {
stop();
waitForThreadFinished(WAIT_TIME);
if (!saveStorage()) {
QuasarAppUtils::Params::log("save keys to storae is failed!",
QuasarAppUtils::Error);
}
delete _keyPoolSizeMutex;
delete _keysMutex;
delete _taskMutex;
delete _cryptoMethod;
}
CryptoPairKeys KeyStorage::getNextPair(const QString &accsessKey,
const QByteArray& genesis,
int timeout) {
if (!isInited() && genesis == RAND_KEY) {
QuasarAppUtils::Params::log("You want get the random crypto keys pair in a not initialized crypto object.",
QuasarAppUtils::Error);
return CryptoPairKeys{};
}
if (_keyPoolSize <= 0) {
return CryptoPairKeys{};
}
if (!genKey(accsessKey, genesis)) {
return {};
}
start();
if (!waitForGeneratekey(accsessKey, timeout)) {
return CryptoPairKeys{};
}
QMutexLocker locker(_keysMutex);
return _keys.value(accsessKey, {});
}
int KeyStorage::getKeyPoolSize() const {
return _keyPoolSize;
}
void KeyStorage::setKeyPoolSize(int keyPoolSize) {
_keyPoolSizeMutex->lock();
_keyPoolSize = keyPoolSize;
_keyPoolSizeMutex->unlock();
start();
}
bool KeyStorage::isValid() const {
return isInited();
}
bool KeyStorage::isInited() const {
return _inited;
}
bool KeyStorage::crypt(QByteArray *data, const QByteArray &publicKey) {
return _cryptoMethod->crypt(data, publicKey);
}
bool KeyStorage::decrypt(QByteArray *cryptedData, const QByteArray &privateKey) {
return _cryptoMethod->decrypt(cryptedData, privateKey);
}
bool KeyStorage::sign(QByteArray *data, const QByteArray &privateKey) {
return _cryptoMethod->sign(data, privateKey);
}
QByteArray KeyStorage::extractSign(const QByteArray &data) {
return _cryptoMethod->extractSign(data);
}
QByteArray KeyStorage::concatSign(const QByteArray &data, const QByteArray &sign) {
return _cryptoMethod->concatSign(data, sign);
}
bool KeyStorage::check(const QByteArray &signedData, const QByteArray &publicKey) {
return _cryptoMethod->check(signedData, publicKey);
}
void KeyStorage::setGenesisList(const QList<QByteArray>& list) {
_keysMutex->lock();
for (const auto& i : list) {
_keys.insert(i, {});
}
_keysMutex->unlock();
start();
}
bool KeyStorage::toStorage(const QString &key) const {
if (!isValid())
return false;
_keysMutex->lock();
CryptoPairKeys value = _keys.value(key);
_keysMutex->unlock();
auto filePath = storageLocation() + "/" + key;
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return false;
}
file.setPermissions(QFile::Permission::ReadOwner | QFile::Permission::WriteOwner);
QDataStream stream(&file);
stream << value;
file.close();
return true;
}
bool KeyStorage::fromStorage(const QByteArray &key) {
auto filePath = storageLocation() + "/" + key;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
QDataStream stream(&file);
CryptoPairKeys value;
stream >> value;
file.close();
_keys.insert(key, value);
return value.isValid();
}
void KeyStorage::generateKeysByTasks() {
_taskMutex->lock();
auto tasks = _generateTasks;
_taskMutex->unlock();
for (auto it = tasks.begin(); it != tasks.end(); ++it) {
if (_stopGenerator) {
return;
}
const auto& value = _keys.value(it.key());
if (!value.isValid()) {
_keysMutex->lock();
if (it.value() == RAND_KEY && _randomKeysPool.size()) {
_keys[it.key()] = *_randomKeysPool.begin();
_randomKeysPool.erase(_randomKeysPool.begin());
} else {
_keys[it.key()] = _cryptoMethod->generate(it.value());
}
_keysMutex->unlock();
}
_taskMutex->lock();
_generateTasks.remove(it.key());
_taskMutex->unlock();
}
}
void KeyStorage::generateRandomKeys() {
_keyPoolSizeMutex->lock();
int size = _keyPoolSize;
_keyPoolSizeMutex->unlock();
while (size > _randomKeysPool.size()) {
if ((_stopGenerator))
return;
auto &&keys = _cryptoMethod->generate();
_keysMutex->lock();
_randomKeysPool.insert(keys);
_keysMutex->unlock();
}
}
void KeyStorage::run() {
if (_stopGenerator) {
return;
}
_keyPoolSizeMutex->lock();
int keyPoolSize = _keyPoolSize;
_keyPoolSizeMutex->unlock();
while ((_generateTasks.size() || keyPoolSize > _randomKeysPool.size())
&& !_stopGenerator) {
generateKeysByTasks();
generateRandomKeys();
_keyPoolSizeMutex->lock();
keyPoolSize = _keyPoolSize;
_keyPoolSizeMutex->unlock();
}
}
void KeyStorage::stop() {
_stopGenerator = true;
}
bool KeyStorage::waitForGeneratekey(const QString& key, int timeout) const {
return waitFor([this, &key](){return _keys.contains(key);}, timeout);
}
bool KeyStorage::waitForThreadFinished(int timeout) const {
return waitFor([this](){return !isRunning();}, timeout);
}
bool KeyStorage::waitFor(const std::function<bool()> &checkFunc, int timeout) const {
auto waitFor = timeout + QDateTime::currentMSecsSinceEpoch();
while (!checkFunc() && waitFor > QDateTime::currentMSecsSinceEpoch()) {
QCoreApplication::processEvents();
}
return checkFunc();
}
void KeyStorage::loadAllKeysFromStorage() {
auto list = QDir(storageLocation()).entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
for (const auto& file: list ) {
if (file.fileName() != VERSION_FILE) {
fromStorage(file.fileName().toLatin1());
}
}
}
bool KeyStorage::saveStorage() const {
bool result = true;
for (auto it = _keys.begin(); it != _keys.end(); ++it) {
result = result && toStorage(it.key());
}
return result;
}
bool KeyStorage::genKey(const QString &accessKey, const QByteArray &genesis) {
if (accessKey.isEmpty())
return false;
QMutexLocker locker(_taskMutex);
_generateTasks.insert(accessKey, genesis);
return true;
}
QString KeyStorage::storageLocation() const {
return _storageLocation;
}
bool KeyStorage::initStorageLocation(const QString &value) {
QFile version(value + "/" + VERSION_FILE);
if (!QFile::exists(value)) {
if (!QDir().mkpath(value)) {
QuasarAppUtils::Params::log(" fail to create a key storagge. Into "
+ value, QuasarAppUtils::Error);
return false;
}
QFile::setPermissions(value,
QFile::Permission::ExeOwner |
QFile::Permission::ReadOwner |
QFile::Permission::WriteOwner);
QFile version(value + "/" + VERSION_FILE);
if (!version.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return false;
}
QDataStream stream(&version);
stream << THE_CLASS(_cryptoMethod);
version.close();
} else {
if (!version.open(QIODevice::ReadOnly)) {
return false;
}
QDataStream stream(&version);
QString versionName;
stream >> versionName;
version.close();
if (THE_CLASS(_cryptoMethod) != versionName) {
return false;
}
}
_storageLocation = value;
return _storageLocation.size();
}
bool KeyStorage::initDefaultStorageLocation(const QString &dirName) {
auto storageLoation =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
"/" + dirName;
if (dirName.isEmpty()) {
storageLoation += THE_CLASS(_cryptoMethod);
}
storageLoation += "/crypto/";
if (!initStorageLocation(storageLoation)) {
QuasarAppUtils::Params::log("CryptoStorage not inited",
QuasarAppUtils::Error);
return false;
}
loadAllKeysFromStorage();
return _inited = true;
}
void KeyStorage::clearStorage() const {
QDir::root().remove(storageLocation());
}
}

View File

@ -0,0 +1,246 @@
#ifndef KEYSTORAGE_H
#define KEYSTORAGE_H
#include <QList>
#include <QThread>
#include "heart_global.h"
#include <QByteArray>
#include <QHash>
#include <QSet>
#include "config.h"
#define RAND_KEY ""
class QMutex;
namespace NP {
class CryptoPairKeys;
class ICrypto;
/**
* @brief The KeyStorage class - this class provie the functionality of controll crypto keys (generate, save, write);
*/
class KeyStorage: public QThread
{
Q_OBJECT
public:
/**
* @brief KeyStorage
* @param cryptoMethod - any class inherited from ICrypto
*/
KeyStorage(ICrypto* cryptoMethod);
~KeyStorage();
/**
* @brief getNextPair - take a one pair key from keys pool.
* @warning If key pool is empty then this method frease a current thread for awiting f neg generated pair key.
* @note if the key is not generated within the specified period of time, an invalid copy of the key pair will be returned.
* @param accsessKey - the byte array for get a acceses to key from storage.
* @param genesis - set this params to empty for get random key pair or set the byte array for get a key pair for genesis array.
* @param timeout_msec - timeout in milisecunds. default is WAIT_TIME (30000)
* @return pair of keys.
*/
CryptoPairKeys getNextPair(const QString &accsessKey,
const QByteArray &genesis = RAND_KEY,
int timeout_msec = WAIT_TIME);
/**
* @brief getKeyPoolSize
* @return
*/
int getKeyPoolSize() const;
/**
* @brief setKeyPoolSize
* @param keyPoolSize
*/
void setKeyPoolSize(int keyPoolSize);
/**
* @brief isValid
* @return true if the crypto object is valid.
*/
virtual bool isValid() const;
/**
* @brief isInited
* @return true if the crypto object has been initialized.
*/
virtual bool isInited() const;
/**
* @brief crypt
* @param data - pointer to data array for crypting.
* @note data as ben changed after call this method.
* @param publicKey - key for crypting data
* @return true if function finished seccussful
*/
bool crypt(QByteArray *data, const QByteArray& publicKey);
/**
* @brief decrypt
* @param cryptedData - pointer to data array for decrypting.
* @note cryptedData as ben changed after call this method.
* @param privateKey
* @return true if function finished seccussful
*/
bool decrypt(QByteArray *cryptedData, const QByteArray& privateKey);
/**
* @brief sign
* @param data - pointer to data array for signed.
* @note data as ben changed after call this method.
* @param privateKey
* @return true if function finished seccussful
*/
bool sign(QByteArray* data, const QByteArray& privateKey);
/**
* @brief extractSign - extract sign from signed byteArray
* @param data - signed message.
* @return return array of sign.
*/
QByteArray extractSign(const QByteArray& data);
/**
* @brief concatSign
* @param data - message data
* @return signed message
*/
QByteArray concatSign(const QByteArray& data, const QByteArray& sign);
/**
* @brief check
* @param publicKey
* @return true if function finished seccussful and signedData is valid.
*/
bool check(const QByteArray& signedData, const QByteArray& publicKey);
/**
* @brief setGenesisList - set genesis list for generation key pairs
*/
void setGenesisList(const QList<QByteArray> &list);
/**
* @brief storageLocation
* @default QStandardPaths::DataLocation/KeysStorage
* @return parth to storage location of crypto keys
*/
QString storageLocation() const;
/**
* @brief initStorageLocation set a new path for storage location of keys.
* @param value - new path
*/
bool initStorageLocation(const QString &value);
/**
* @brief initDefaultStorageLocation - the some as initStorageLocation, but set default
* path.
* @param dirName - it is name of storage location. If This parametr weel be empty then
* storage location set default dir name. By default is name of crypto class.
* @default default path of storage is '/QStandardPaths::AppDataLocation/crypto/dirName'
* @return true if the storage inited successful
*/
bool initDefaultStorageLocation(const QString& dirName = "");
/**
* @brief clearStorage
*/
void clearStorage() const;
protected:
/**
* @brief toStorage - save key from genesis into local storage.
* @param genesis - genesis of key pair
* @note override this method if you want to change storage location or method of save of keys.
* @return true if key saved successful
*/
virtual bool toStorage(const QString &genesis) const;
/**
* @brief fromStorage - load keys from local storage
* @param genesis - genesis of key pair
* @return true if key pair saved seccussful.
*/
virtual bool fromStorage(const QByteArray& key);
/**
* @brief run - start the key generator.
*/
void run() override;
/**
* @brief stop - stop generate keys.
*/
void stop();
private:
/**
* @brief waitForGeneratekey
* @param timeout - maximum time for generation new key. by default = WAIT_TIME (30000)
* @return true if key generated successful
*/
bool waitForGeneratekey(const QString &key, int timeout = WAIT_TIME) const;
/**
* @brief waitForThreadFinished
* @param timeout
* @return
*/
bool waitForThreadFinished(int timeout = WAIT_TIME) const;
/**
* @brief waitFor - base waint function
* @param checkFunc - this is lyambda of check event
* @param timeout - maximu time line of waiting of event
* @return true if event is checkFunc return true
*/
bool waitFor(const std::function<bool()>& checkFunc, int timeout) const;
/**
* @brief loadAllKeysFromStorage
*/
void loadAllKeysFromStorage();
/**
* @brief saveStorage
* @return true if all keys has been saved in a storage.
*/
bool saveStorage() const;
/**
* @brief genKey - this method add a new task for generate keys pair
* @param accessKey - the byte array for get access of the keys pair.
* @param genesis - the byte array for generate new key
* @note If access key well be empty then this method return false.
* @note for generate random key use a RAND_KEY genesis or empty value.
* @return true if task of generation a new pair keys added seccussful else false.
*/
bool genKey(const QString &accessKey, const QByteArray& genesis = RAND_KEY);
QHash<QString, CryptoPairKeys> _keys;
QSet<CryptoPairKeys> _randomKeysPool;
QHash<QString, QByteArray> _generateTasks;
int _keyPoolSize = 1;
QMutex *_keyPoolSizeMutex = nullptr;
QMutex *_keysMutex = nullptr;
QMutex *_taskMutex = nullptr;
QString _storageLocation;
bool _inited = false;
bool _stopGenerator = false;
ICrypto *_cryptoMethod = nullptr;
void generateKeysByTasks();
void generateRandomKeys();
};
}
#endif // KEYSTORAGE_H

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2018-2020 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 "abstractdata.h"
#include "package.h"
#include <QDataStream>
namespace NP {
Package::Package() {
reset();
}
bool Package::isValid() const {
if (!hdr.isValid()) {
return false;
}
auto rawint = data.mid(0, sizeof (decltype (hdr.command)));
decltype (hdr.command) cmd;
memcpy(&cmd, rawint.data(), sizeof (cmd));
if (data.size() && hdr.command != cmd) {
std::reverse(rawint.begin(), rawint.end());
memcpy(&cmd, rawint.data(), sizeof (cmd));
if (hdr.command != cmd)
return false;
}
if (hdr.size != data.size()) {
return false;
}
return qHash(data) == hdr.hash;
}
void Package::reset() {
hdr.reset();
data.clear();
}
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()));
}
QDataStream &Package::fromStream(QDataStream &stream) {
reset();
stream.readRawData(reinterpret_cast<char*>(&hdr), sizeof(Header));
char * buf = static_cast<char*>(malloc(hdr.size));
stream.readRawData(buf, hdr.size);
data.clear();
data.insert(0, buf, hdr.size);
free(buf);
return stream;
}
QDataStream &Package::toStream(QDataStream &stream) const {
stream.writeRawData(reinterpret_cast<const char*>(&hdr),
sizeof (hdr));
stream.writeRawData(data.data(),
data.size());
return stream;
}
}

View File

@ -1,9 +1,17 @@
/*
* Copyright (C) 2018-2020 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 ABSTRACTPACKAGE_H
#define ABSTRACTPACKAGE_H
#include "header.h"
#include "networkprotocol_global.h"
#include "heart_global.h"
#include <QByteArray>
#include <baseid.h>
namespace NP {
@ -11,7 +19,9 @@ class Abstract;
/**
* @brief The Package struct
*/
struct NETWORKPROTOCOLSHARED_EXPORT Package {
class NETWORKPROTOCOLSHARED_EXPORT Package: public StreamBase {
public:
/**
* @brief hdr - header of package
*/
@ -22,6 +32,7 @@ struct NETWORKPROTOCOLSHARED_EXPORT Package {
QByteArray data;
Package();
virtual ~Package() = default;
/**
* @brief isValid
@ -29,24 +40,21 @@ struct NETWORKPROTOCOLSHARED_EXPORT Package {
*/
virtual bool isValid() const;
/**
* @brief toBytes
* @return bytes array of packag
*/
virtual QByteArray toBytes() const;
/**
* @brief fromBytes
* @return bytes array to packag
*/
virtual void fromBytes(const QByteArray &array);
/**
* @brief reset - reset all data and set for package invalid status
*/
virtual void reset();
virtual ~Package() = default;
/**
* @brief toString - convert pakcage information to string label
* @return string
*/
QString toString() const;
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
};
}

View File

@ -0,0 +1,59 @@
#include "packagemanager.h"
#include <package.h>
#include <ctime>
#include <config.h>
namespace NP {
PackageManager::PackageManager()
{
}
PackageManager::~PackageManager() {
for (const auto& data : _parseResults) {
delete data;
}
_parseResults.clear();
}
const Package *PackageManager::getPkgFromArhive(const unsigned int &id) const {
if (!contains(id))
return nullptr;
QMutexLocker lock(&_processMutex);
return _parseResults.value(id)->_data;
}
bool PackageManager::contains(const unsigned int &id) const {
QMutexLocker lock(&_processMutex);
return _parseResults.contains(id);
}
void PackageManager::processed(const Package &pkg, char processResult) {
if (!pkg.hdr.hash || !PACKAGE_CACHE_SIZE) {
return;
}
QMutexLocker lock(&_processMutex);
if (_parseResults.size() > PACKAGE_CACHE_SIZE) {
_processTime.erase(_processTime.begin());
}
_parseResults.insert(pkg.hdr.hash, new PackaData {
processResult,
new Package(pkg)
});
_processTime.insert(static_cast<int>(time(0)), pkg.hdr.hash);
}
PackageManager::PackaData::~PackaData() {
delete _data;
}
}

View File

@ -0,0 +1,58 @@
#ifndef PAKCAGEMANAGER_H
#define PAKCAGEMANAGER_H
#include <QMutex>
#include <QSharedDataPointer>
#include <baseid.h>
namespace NP {
/**
* @brief The PakcageManager class - contains all processed packages
*/
class PackageManager
{
public:
PackageManager();
~PackageManager();
/**
* @brief getPkgFromArhive - return pointer tot package from arhive.
* @param id - id of the requariment package.
* @result pointer of the processed package, if package not return nullpt
*/
const Package * getPkgFromArhive(const unsigned int &id) const;
/**
* @brief contains - check packge by id
* @param id
* @return true if pakcge has been parsed
*/
bool contains(const unsigned int& id) const;
/**
* @brief processed - add package to arhice
* @param pkg - object of package
* @param processResult - result of method parsePackage.
*/
void processed(const Package& pkg, char processResult);
private:
/**
* @brief The PackaData struct - private data of packages
*/
struct PackaData {
char _parseResult;
Package *_data = nullptr;
~PackaData();
};
QMultiMap<int, unsigned int> _processTime;
QHash<unsigned int, const PackaData*> _parseResults;
mutable QMutex _processMutex;
};
}
#endif // PAKCAGEMANAGER_H

View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2018-2020 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 "abstractdata.h"
#include <QDataStream>
#include <QMap>
#include <typeinfo>
#include "heart.h"
#include <limits>
#include <quasarapp.h>
#include <QCryptographicHash>
namespace NP {
unsigned short AbstractData::cmd() const {
return _cmd;
}
void AbstractData::setCmd(unsigned short cmd) {
_cmd = cmd;
}
bool AbstractData::init() {
if (typeid (*this).hash_code() == typeid(AbstractData).hash_code())
return false;
generateCmd();
return true;
}
void AbstractData::generateCmd() {
setCmd(H_16(*this));
}
AbstractData::AbstractData() {
_cmd = 0;
}
bool AbstractData::fromBytes(const QByteArray &data) {
return StreamBase::fromBytes(data);
}
QByteArray AbstractData::toBytes() const {
return StreamBase::toBytes();
}
bool AbstractData::toPackage(Package &package,
unsigned int triggerHash) const {
if (!isValid()) {
return false;
}
package.data = toBytes();
package.hdr.command = _cmd;
package.hdr.triggerHash = triggerHash;
package.hdr.size = static_cast<unsigned short>(package.data.size());
package.hdr.hash = qHash(package.data);
return package.isValid();
}
QDataStream &AbstractData::fromStream(QDataStream &stream) {
stream >> _cmd;
return stream;
}
QDataStream &AbstractData::toStream(QDataStream &stream) const {
stream << _cmd;
return stream;
}
bool AbstractData::isValid() const {
return _cmd;
}
bool AbstractData::copyFrom(const AbstractData *other) {
return other;
}
QString AbstractData::toString() const {
return QString("Object: type:%0, command:%1").
arg(typeid(*this).name()).
arg(_cmd);
}
bool AbstractData::prepareToSend() {
if (isValid()) {
return true;
}
return init();
}
AbstractData::~AbstractData() {
}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright (C) 2018-2020 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 ABSTRACTDATA_H
#define ABSTRACTDATA_H
#include "package.h"
#include <streambase.h>
#include <global.h>
namespace NP {
/**
* @brief The AbstractData class
* all data packages inherited this class.
*/
class NETWORKPROTOCOLSHARED_EXPORT AbstractData : public StreamBase
{
public:
virtual ~AbstractData() override;
/**
* @brief cmd
* @return command of package
*/
unsigned short cmd() const;
/**
* @brief toBytes
* @return byte array for package
*/
QByteArray toBytes() const;
/**
* @brief toPackage
* @param package - return value
* @param trigeredCommand - old cmd
* @return retorn package object created from this object.
*/
bool toPackage(Package &package, unsigned int triggerHash = 0) const;
/**
* @brief isValid
* @return true if class isValid
*/
virtual bool isValid() const;
/**
* @brief copyFrom this function try cast other object to this class type
* and invoke copy operation. cmd option is ignored;
* @param other
* @return true if all good
*/
virtual bool copyFrom(const AbstractData*);
/**
* @brief toString - return a string implementation fo this object
* @return string of object
*/
virtual QString toString() const;
/**
* @brief prepareToSend - this method check object to valid and if an object is invalid invoke method init.
* @return return true if the object prepared for sending.
*/
bool prepareToSend();
/**
* @brief create - this is factory method for create a new object with some type that parent object.
* @param args - list of arguments for create object
* @return pointer toObject
*/
template<class C, class... Args>
C* create(Args&&... args) const {
C* object = new C(std::forward<Args>(args)...);
object->generateCmd();
return object;
}
protected:
/**
* @brief AbstractData
*/
explicit AbstractData();
/**
* @brief fromBytes - private initialisation of object from byte array
* @return true if all good
*/
bool fromBytes(const QByteArray&);
/**
* @brief setCmd
* @param cmd
*/
void setCmd(unsigned short cmd);
/**
* @brief init - this method need to invoke after create object for initialize all componet of ojects.
* @note do not invode this method on constructor of object, becose object wel be initialized not correctly.
* @default defaul implementation of object init _com of object.
* @return true if object initialized correctly.
*/
virtual bool init();
/**
* @brief fromStream
* @param stream
* @return stream
*/
QDataStream& fromStream(QDataStream& stream) override;
/**
* @brief toStream
* @param stream
* @return stream
*/
QDataStream& toStream(QDataStream& stream) const override;
private:
/**
* @brief generateCmd set cmd from class name.
* @note call this method only after create objects. do not call in constructor of class.
*/
void generateCmd();
/**
* @brief _cmd - unique id of class using in Header of package for identification.
*/
unsigned short _cmd = 0;
};
}
#endif // ABSTRACTDATA_H

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 "badrequest.h"
#include <QDataStream>
@ -6,7 +13,7 @@ namespace NP{
BadRequest::BadRequest(const QString &err):AbstractData() {
INIT_COMMAND
setErr(err);

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 BADREQUEST_H
#define BADREQUEST_H

View File

@ -0,0 +1,8 @@
#include "closeconnection.h"
namespace NP {
CloseConnection::CloseConnection()
{
}
}

View File

@ -0,0 +1,22 @@
#ifndef CLOSECONNECTION_H
#define CLOSECONNECTION_H
#include "abstractdata.h"
namespace NP{
/**
* @brief The CloseConnection class - This commnad is request for close connection on parent node of connection
* This neede becouse QAbstractSocket emit error when connection closed from remote node.
*
* From QtDocumentation :
* ``` If the remote host closes the connection, QAbstractSocket will emit errorOccurred(QAbstractSocket::RemoteHostClosedError), during which the socket state will still be ConnectedState, and then the disconnected() signal will be emitted.```
*/
class NETWORKPROTOCOLSHARED_EXPORT CloseConnection: public AbstractData
{
public:
CloseConnection();
};
}
#endif // CLOSECONNECTION_H

View File

@ -0,0 +1,50 @@
#include "ping.h"
#include <QDataStream>
namespace NP {
Ping::Ping() {
}
Ping::Ping(const Package &from): Ping() {
fromBytes(from.data);
}
bool Ping::isValid() const {
return AbstractData::isValid();
}
bool Ping::copyFrom(const AbstractData * other) {
if (!AbstractData::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const Ping*>(other);
if (!otherObject)
return false;
this->_ansver = otherObject->_ansver;
return true;
}
bool Ping::ansver() const {
return _ansver;
}
void Ping::setAnsver(bool ansver) {
_ansver = ansver;
}
QDataStream &Ping::fromStream(QDataStream &stream) {
AbstractData::fromStream(stream);
stream >> _ansver;
return stream;
}
QDataStream &Ping::toStream(QDataStream &stream) const {
AbstractData::toStream(stream);
stream << _ansver;
return stream;
}
}

View File

@ -0,0 +1,34 @@
#ifndef PING_H
#define PING_H
#include "abstractdata.h"
namespace NP {
/**
* @brief The Ping class - test class for translate data on network
*/
class NETWORKPROTOCOLSHARED_EXPORT Ping: public AbstractData
{
public:
Ping();
Ping(const Package& from);
// AbstractData interface
bool isValid() const;
bool copyFrom(const AbstractData *);
bool ansver() const;
void setAnsver(bool ansver);
protected:
// StreamBase interface
QDataStream &fromStream(QDataStream &stream);
QDataStream &toStream(QDataStream &stream) const;
private:
bool _ansver = false;
};
}
#endif // PING_H

View File

@ -0,0 +1,73 @@
#include "cryptopairkeys.h"
#include "qsecretrsa2048.h"
#include <QDir>
#include <qrsaencryption.h>
namespace NP {
QSecretRSA2048::QSecretRSA2048() {
qtSecret = new QRSAEncryption(QRSAEncryption::RSA_2048);
}
CryptoPairKeys QSecretRSA2048::generate(const QByteArray &genesis) const {
QByteArray pubKey;
QByteArray privKey;
qtSecret->generatePairKey(pubKey, privKey, genesis);
return {pubKey, privKey};
}
bool QSecretRSA2048::crypt(QByteArray *data,
const QByteArray &publicKey) {
*data = qtSecret->encode(*data, publicKey);
return data->size();
}
bool QSecretRSA2048::decrypt(QByteArray *cryptedData,
const QByteArray &privateKey) {
*cryptedData = qtSecret->decode(*cryptedData, privateKey);
return cryptedData->size();
}
bool QSecretRSA2048::sign(QByteArray *data,
const QByteArray &privateKey) {
*data = qtSecret->signMessage(*data, privateKey);
return data->size();
}
bool QSecretRSA2048::check(const QByteArray &signedData,
const QByteArray &publicKey) {
return qtSecret->checkSignMessage(signedData, publicKey);
}
QByteArray QSecretRSA2048::extractSign(const QByteArray &data) {
int end = data.lastIndexOf("-SIGN-");
int begin = data.lastIndexOf("-SIGN-", end);
if (end < 0 || begin < 0) {
return {};
}
return QByteArray::fromHex(data.mid(begin, begin - end));
}
QByteArray QSecretRSA2048::concatSign(const QByteArray &data, const QByteArray &sign) {
return data + "-SIGN-" + sign.toHex() + "-SIGN-";
}
bool QSecretRSA2048::isValid() const {
return qtSecret;
}
QSecretRSA2048::~QSecretRSA2048() {
delete qtSecret;
}
}

View File

@ -0,0 +1,44 @@
#ifndef QSECRETRSA2048_H
#define QSECRETRSA2048_H
#include "icrypto.h"
#include <QHash>
class QRSAEncryption;
namespace NP {
/**
* @brief The QSecretRSA2048 class Use
*/
class NETWORKPROTOCOLSHARED_EXPORT QSecretRSA2048: public ICrypto
{
// ICrypto interface
public:
QSecretRSA2048();
~QSecretRSA2048() override;
bool crypt(QByteArray *data, const QByteArray &publicKey) override;
bool decrypt(QByteArray *cryptedData, const QByteArray &privateKey) override;
bool sign(QByteArray *data, const QByteArray &privateKey) override;
bool check(const QByteArray &signedData, const QByteArray &publicKey) override;
QByteArray extractSign(const QByteArray &data) override;
QByteArray concatSign(const QByteArray &data, const QByteArray &sign) override;
/**
* @brief isValid
* @return true if object is valid.
*/
bool isValid() const override;
protected:
CryptoPairKeys generate(const QByteArray& genesis = {}) const override;
private:
QRSAEncryption *qtSecret = nullptr;
};
}
#endif // QSECRETRSA2048_H

View File

@ -0,0 +1,9 @@
#include "receivedata.h"
namespace NP {
ReceiveData::ReceiveData()
{
}
}

View File

@ -0,0 +1,21 @@
#ifndef RECEIVEDATA_H
#define RECEIVEDATA_H
#include "package.h"
namespace NP {
/**
* @brief The ReceiveData struct - this structure contains informaton for parse packages
*/
struct ReceiveData
{
public:
ReceiveData();
Package _pkg;
QByteArray _hdrArray;
};
}
#endif // RECEIVEDATA_H

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2018-2020 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 "request.h"
namespace NP {
Request::Request() {
}
unsigned char Request::getRequestCmd() const {
return requestCmd;
}
void Request::setRequestCmd(unsigned char value) {
requestCmd = value;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2018-2020 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 IREQUEST_H
#define IREQUEST_H
#include "heart_global.h"
namespace NP {
/**
* @brief The Request class - base request methods for data packages
*/
class NETWORKPROTOCOLSHARED_EXPORT Request
{
public:
Request();
unsigned char getRequestCmd() const;
void setRequestCmd(unsigned char value);
protected:
unsigned char requestCmd = 0;
};
}
#endif // IREQUEST_H

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 "package.h"
#include "streambase.h"

View File

@ -1,15 +1,25 @@
/*
* Copyright (C) 2018-2020 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 STREAMBASE_H
#define STREAMBASE_H
#include <QByteArray>
#include <QVariantMap>
#include "networkprotocol_global.h"
#include "heart_global.h"
class QDataStream;
namespace NP {
class Package;
/**
* @brief The StreamBase class - this class add support for streaming data for all cheldren classes.
*/
class NETWORKPROTOCOLSHARED_EXPORT StreamBase
{
public:
@ -28,20 +38,6 @@ public:
*/
QByteArray toBytes() const;
/**
* @brief fromStream
* @param stream
* @return stream
*/
virtual QDataStream& fromStream(QDataStream& stream) = 0;
/**
* @brief toStream
* @param stream
* @return stream
*/
virtual QDataStream& toStream(QDataStream& stream) const = 0;
/**
* @brief operator << it is wraper over toStream
@ -60,7 +56,20 @@ public:
friend QDataStream& operator>> (QDataStream& stream, StreamBase& obj);
protected:
/**
* @brief fromStream
* @param stream
* @return stream
*/
virtual QDataStream& fromStream(QDataStream& stream) = 0;
/**
* @brief toStream
* @param stream
* @return stream
*/
virtual QDataStream& toStream(QDataStream& stream) const = 0;
};
}

View File

@ -1,6 +1,13 @@
/*
* Copyright (C) 2018-2020 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 "workstate.h"
#include <QHostAddress>
#include <hostaddress.h>
namespace NP{
@ -61,11 +68,11 @@ void WorkState::setMaxConnectionCount(int value) {
maxConnectionCount = value;
}
QList<QHostAddress> WorkState::getBanedList() const {
QList<HostAddress> WorkState::getBanedList() const {
return _banedList;
}
void WorkState::setBanedList(const QList<QHostAddress> &banedList) {
void WorkState::setBanedList(const QList<HostAddress> &banedList) {
_banedList = banedList;
}
}

View File

@ -1,7 +1,14 @@
/*
* Copyright (C) 2018-2020 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 WORKSTATE_H
#define WORKSTATE_H
#include <QHostAddress>
#include <hostaddress.h>
#include <QList>
namespace NP {
@ -16,7 +23,7 @@ private:
int maxConnectionCount = 0;
bool isRun = false;
QList<QHostAddress> _banedList;
QList<HostAddress> _banedList;
QString getWorkStateString() const;
public:
@ -60,13 +67,13 @@ public:
* @brief getBanedList
* @return list of id's of baned nodes
*/
QList<QHostAddress> getBanedList() const;
QList<HostAddress> getBanedList() const;
/**
* @brief setBanedList
* @param banedList set new baned list
*/
void setBanedList(const QList<QHostAddress> &banedList);
void setBanedList(const QList<HostAddress> &banedList);
/**
* @brief getIsRun

87
Heart/CMakeLists.txt Normal file
View File

@ -0,0 +1,87 @@
#
# Copyright (C) 2018-2020 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.
#
cmake_minimum_required(VERSION 3.10)
include(../QuasarAppLib/CMake/ProjectOut.cmake)
include(../QuasarAppLib/CMake/Version.cmake)
add_subdirectory(Qt-Secret)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-DNETWORKPROTOCOL_LIBRARY)
find_package(Qt5 COMPONENTS Core Network Sql Concurrent REQUIRED)
if (${BUILD_LVL} GREATER_EQUAL 0)
message("BUILD LVL >= 0")
file(GLOB SOURCE_CPP_LVL_0
"*.cpp" "*.qrc"
"AbstractSpace/*.cpp" "AbstractSpace/*.qrc"
"AbstractSpace/packages/*.cpp" "AbstractSpace/packages/*.qrc"
"AbstractSpace/Private/*.cpp" "AbstractSpace/Private/*.qrc"
)
set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace")
set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace/packages")
set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace/Private")
endif()
if (${BUILD_LVL} GREATER_EQUAL 1)
message("BUILD LVL >= 1")
file(GLOB SOURCE_CPP_LVL_1
"DataBaseSpace/*.cpp" "DataBaseSpace/*.qrc"
"DataBaseSpace/packages/*.cpp" "DataBaseSpace/packages/*.qrc"
"DataBaseSpace/Private/*.cpp" "DataBaseSpace/Private/*.qrc"
)
set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace")
set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace/packages")
set(PRIVATE_INCUDE_DIR ${PRIVATE_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace/Private")
endif()
if (${BUILD_LVL} GREATER_EQUAL 2)
message("BUILD LVL >= 2")
file(GLOB SOURCE_CPP_LVL_2
"NetworkSpace/*.cpp" "NetworkSpace/*.qrc"
"NetworkSpace/packages/*.cpp" "NetworkSpace/packages/*.qrc"
"NetworkSpace/Private/*.cpp" "NetworkSpace/Private/*.qrc"
)
set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace")
set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace/packages")
set(PRIVATE_INCUDE_DIR ${PRIVATE_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace/Private")
endif()
set(SOURCE_CPP ${SOURCE_CPP_LVL_0} ${SOURCE_CPP_LVL_1} ${SOURCE_CPP_LVL_2})
add_library(${PROJECT_NAME} SHARED ${SOURCE_CPP})
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core Qt5::Network Qt5::Sql Qt5::Concurrent QuasarApp crypto ssl Qt-Secret)
target_include_directories(${PROJECT_NAME} PUBLIC ${PUBLIC_INCUDE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${PRIVATE_INCUDE_DIR})
setVersion(1 1 0)

View File

@ -0,0 +1,19 @@
CREATE TABLE IF NOT EXISTS NetworkMembers (
id VARCHAR(64) PRIMARY KEY NOT NULL,
authenticationData BLOB default NULL,
trust INTEGER default 0
);
CREATE TABLE IF NOT EXISTS MemberPermisions (
memberId VARCHAR(64) NOT NULL,
objectTable VARCHAR(100) NOT NULL,
objectId VARCHAR(64) NOT NULL,
lvl INTEGER NOT NULL,
FOREIGN KEY(memberId) REFERENCES NetworkMembers(id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS MemberPermisionsIndex ON MemberPermisions(memberId, objectTable, objectId);

View File

@ -0,0 +1 @@
#include "abstractkey.h"

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2018-2020 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 ABSTRACTKEY_H
#define ABSTRACTKEY_H
#include "heart_global.h"
#include <baseid.h>
namespace NP {
/**
* @brief The Abstractkey class - this class provid one hash function for all keys of database objcets
*/
class NETWORKPROTOCOLSHARED_EXPORT AbstractKey
{
public:
AbstractKey() = default;
virtual ~AbstractKey() = default;
virtual unsigned int hash() const = 0;
virtual bool equal(const AbstractKey* other) const = 0;
/**
* @brief id - this method return id of object
* @return BaseId of object.
*/
virtual const BaseId& id() const = 0;
/**
* @brief table - this method return table name of object
* @return table name
*/
virtual const QString& table() const = 0;
/**
* @brief isValid
* @return true if key is valid
*/
virtual bool isValid() const = 0;
};
}
#endif // ABSTRACTKEY_H

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 "accesstoken.h"
#include <QCryptographicHash>
#include <QDataStream>

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 ACCSESTOKEN_H
#define ACCSESTOKEN_H
@ -5,7 +12,7 @@
#include <QByteArray>
#include <QDateTime>
#include <networkprotocol_global.h>
#include <heart_global.h>
namespace NP {

View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2018-2020 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 "asyncsqldbwriter.h"
#include <QDateTime>
#include <QMetaMethod>
#include <QThread>
#include <dbobject.h>
#include <quasarapp.h>
namespace NP {
AsyncSqlDbWriter::AsyncSqlDbWriter(QObject *ptr):
QObject(ptr) {
_own = new QThread(this);
moveToThread(_own);
_own->start();
}
AsyncSqlDbWriter::~AsyncSqlDbWriter() {
_own->quit();
_own->wait();
}
bool AsyncSqlDbWriter::saveObject(const DBObject *saveObject) {
if (QThread::currentThread() == thread()) {
return SqlDBWriter::saveObject(saveObject);
}
return QMetaObject::invokeMethod(this,
"handleSaveObject",
Qt::QueuedConnection,
Q_ARG(const NP::DBObject *, saveObject),
Q_ARG(bool *, nullptr),
Q_ARG(bool *, nullptr));
}
bool AsyncSqlDbWriter::deleteObject(const DBObject *deleteObject) {
if (QThread::currentThread() == thread()) {
return SqlDBWriter::deleteObject(deleteObject);
}
return QMetaObject::invokeMethod(this,
"handleDeleteObject",
Qt::QueuedConnection,
Q_ARG(const NP::DBObject *, deleteObject),
Q_ARG(bool *, nullptr),
Q_ARG(bool *, nullptr));
}
bool AsyncSqlDbWriter::saveObjectWithWait(const DBObject *saveObject) {
if (QThread::currentThread() == thread()) {
return SqlDBWriter::saveObject(saveObject);
}
bool workOfEnd = false, workResult = false;
bool invoke = QMetaObject::invokeMethod(this,
"handleSaveObject",
Qt::QueuedConnection,
Q_ARG(const NP::DBObject *, saveObject),
Q_ARG(bool *, &workResult),
Q_ARG(bool *, &workOfEnd));
if (!invoke) {
QuasarAppUtils::Params::log("handleDeleteObject not invokecd", QuasarAppUtils::Debug);
return false;
}
if (!waitFor(&workOfEnd)) {
return false;
}
return workResult;
}
bool AsyncSqlDbWriter::deleteObjectWithWait(const DBObject *deleteObject) {
if (QThread::currentThread() == thread()) {
return SqlDBWriter::deleteObject(deleteObject);
}
bool workOfEnd = false, workResult = false;
bool invoke = QMetaObject::invokeMethod(this,
"handleDeleteObject",
Qt::QueuedConnection,
Q_ARG(const NP::DBObject *, deleteObject),
Q_ARG(bool *, &workResult),
Q_ARG(bool *, &workOfEnd));
if (!invoke) {
QuasarAppUtils::Params::log("handleDeleteObject not invokecd", QuasarAppUtils::Debug);
return false;
}
if (!waitFor(&workOfEnd)) {
return false;
}
return workResult;
}
bool AsyncSqlDbWriter::getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) {
if (QThread::currentThread() == thread()) {
return SqlDBWriter::getAllObjects(templateObject, result);
}
bool workOfEnd = false, workResult = false;
bool invockeResult = QMetaObject::invokeMethod(this,
"handleGetAllObject",
Qt::QueuedConnection,
Q_ARG(const NP::DBObject *, &templateObject),
Q_ARG(QList<const NP::DBObject *> *, &result),
Q_ARG(bool *, &workResult),
Q_ARG(bool *, &workOfEnd));
if (!invockeResult)
return false;
if (!waitFor(&workOfEnd)) {
return false;
}
return workResult;
}
bool AsyncSqlDbWriter::initDb(const QVariantMap &params) {
if (QThread::currentThread() == thread()) {
return SqlDBWriter::initDb(params);
}
bool workOfEnd = false, workResult = false;
bool invockeResult = QMetaObject::invokeMethod(this,
"handleInitDb",
Qt::QueuedConnection,
Q_ARG(const QVariantMap &, params),
Q_ARG(bool *, &workResult),
Q_ARG(bool *, &workOfEnd));
if (!invockeResult)
return false;
if (!waitFor(&workOfEnd)) {
return false;
}
return workResult;
}
void AsyncSqlDbWriter::handleSaveObject(const DBObject* saveObject,
bool *resultOfWork,
bool *endOfWork) {
if (resultOfWork) {
*resultOfWork = SqlDBWriter::saveObject(saveObject);
if (endOfWork) {
*endOfWork = true;
}
} else {
if (!SqlDBWriter::saveObject(saveObject)) {
QuasarAppUtils::Params::log("AsyncSqlDbWriter: save object fail!",
QuasarAppUtils::Error);
}
}
}
void AsyncSqlDbWriter::handleDeleteObject(const DBObject *deleteObject, bool *resultOfWork, bool *endOfWork) {
if (resultOfWork) {
*resultOfWork = SqlDBWriter::deleteObject(deleteObject);
if (endOfWork) {
*endOfWork = true;
}
} else {
if (!SqlDBWriter::deleteObject(deleteObject)) {
QuasarAppUtils::Params::log("AsyncSqlDbWriter: delete object fail!",
QuasarAppUtils::Error);
}
}
}
void AsyncSqlDbWriter::handleGetAllObject(const DBObject *templateObject,
QList<const DBObject *> *result,
bool *resultOfWork, bool *endOfWork) {
*resultOfWork = SqlDBWriter::getAllObjects(*templateObject, *result);
if (endOfWork) {
*endOfWork = true;
}
}
void AsyncSqlDbWriter::handleInitDb(const QVariantMap &params,
bool *resultOfWork, bool *endOfWork) {
*resultOfWork = SqlDBWriter::initDb(params);
if (endOfWork) {
*endOfWork = true;
}
}
bool AsyncSqlDbWriter::waitFor(bool *condition, int timeout) const {
auto curmsec = QDateTime::currentMSecsSinceEpoch() + timeout;
while (curmsec > QDateTime::currentMSecsSinceEpoch() && !*condition) {
QCoreApplication::processEvents();
}
QCoreApplication::processEvents();
return *condition;
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2018-2020 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 ASYNCSQLDBWRITER_H
#define ASYNCSQLDBWRITER_H
#include "sqldbwriter.h"
#include "atomicmetatypes.h"
namespace NP {
/**
* @brief The AsyncSqlDbWriter class some as SqlDBWriter bud run all commnad in main thread
* is thread save db writer.
*/
class AsyncSqlDbWriter :public QObject, public SqlDBWriter
{
Q_OBJECT
public:
AsyncSqlDbWriter(QObject* ptr = nullptr);
~AsyncSqlDbWriter();
// iObjectProvider interface
/**
* @brief saveObject - save object in to database. This implementation work on own thread
* @param saveObject - ptr to object
* @return true if function finished successful
*/
bool saveObject(const DBObject* saveObject) override;
/**
* @brief saveObject - delete object in to database. This implementation work on own thread
* @param deleteObject - ptr to object
* @return true if function finished successful
*/
bool deleteObject(const DBObject* deleteObject) override;
/**
* @brief saveObjectWithWait - this is owerload of saveObject with wait results of a database thread.
* @param saveObject - ptr to object
* @return true if function finished successful
*/
bool saveObjectWithWait(const DBObject* saveObject);
/**
* @brief deleteObjectWithWait - this is owerload of deleteObject with wait results of a database thread.
* @param deleteObject - ptr to object
* @return true if function finished successful
*/
bool deleteObjectWithWait(const DBObject* deleteObject);
/**
* @brief getAllObjects - this implementation work on own thread and wait results in current thread.
* @param templateObject - template object with request
* @param result - list of objects
* @return true if function finished successful
*/
bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) override;
/**
* @brief initDb - this implementation initialise database in own thread and wait result of initialization on current thread
* @param initDbParams - initialise parameters
* @return true if database initialise successful
*/
bool initDb(const QVariantMap &params) override;
protected slots:
/**
* @brief handleSaveObject - this method call SaveObject on own thread.
* @param saveObject - object for save
*/
void handleSaveObject(const NP::DBObject* saveObject,
bool *resultOfWork, bool *endOfWork);
/**
* @brief handleDeleteObject - this method call DeleteObject on own thread.
* @param deleteObject object for delete
*/
void handleDeleteObject(const NP::DBObject* deleteObject,
bool *resultOfWork, bool *endOfWork);
/**
* @brief the handleGetAllObject - this method call getAllObjects on own thread.
* @param templateObject - the some as in getAllObjects
* @param result - the some as in getAllObjects
* @param resultOfWork - this ptr contains result of invoked of getAllObjects method on own thread
* @param endOfWork - this ptr set true when invocked method is finished
* @param cb - this call back method invoke after getAllObjects method
*/
virtual void handleGetAllObject(const NP::DBObject *templateObject,
QList<const NP::DBObject *> *result,
bool *resultOfWork, bool *endOfWork = nullptr);
/**
* @brief handleInitDb - this method invoke initDb on own thread
* @param params - input parameters data
* @param resultOfWork - this ptr contains result of invoked of initDb method on own thread
* @param endOfWork - this ptr set true when invocked method is finished
*/
void handleInitDb(const QVariantMap &params,
bool *resultOfWork, bool *endOfWork = nullptr);
private:
/**
* @brief waitFor - The base wait function.
* @param condition - condition for wait
* @param timeout - maximu time for wait. By default this value equals WAIT_TIME it is 30000 msec.
* @return true if condition is true.
*/
bool waitFor(bool* condition, int timeout = WAIT_TIME) const;
QThread *_own = nullptr;
};
}
#endif // ASYNCSQLDBWRITER_H

View File

@ -0,0 +1,19 @@
#ifndef BASEDEFINES_H
#define BASEDEFINES_H
namespace NP {
/**
* @brief The DBOperationResult enum
*/
enum class DBOperationResult {
/// Node do not know about this operaio
Unknown,
/// Node allow this operation and exec it
Allowed,
/// Node forbid this operation.
Forbidden,
};
}
#endif // BASEDEFINES_H

View File

@ -0,0 +1,75 @@
#include "baseid.h"
namespace NP {
BaseId::BaseId() = default;
BaseId::BaseId(unsigned int val) {
fromRaw(reinterpret_cast<char*>(&val), sizeof (val));
}
BaseId::BaseId(const QByteArray &raw) {
fromRaw(raw);
}
BaseId::BaseId(const QString &base64) {
fromBase64(base64.toLatin1());
}
bool BaseId::fromBase64(const QByteArray &base64) {
return fromRaw(QByteArray::fromBase64(base64, QByteArray::Base64UrlEncoding));
}
bool BaseId::fromRaw(const QByteArray &raw) {
_data = raw;
return isValid();
}
bool BaseId::fromRaw(const char *data, int len) {
_data.clear();
_data.insert(0, data, len);
return isValid();
}
QByteArray BaseId::toBase64() const {
return _data.toBase64(QByteArray::Base64UrlEncoding);
}
const QByteArray& BaseId::toRaw() const {
return _data;
}
bool BaseId::isValid() const {
return _data.size();
}
void BaseId::clear() {
_data.clear();
}
unsigned char BaseId::prefix() const {
if (_data.size())
return _data[0];
return 0;
}
QDataStream &BaseId::fromStream(QDataStream &stream) {
stream >> _data;
return stream;
}
QDataStream &BaseId::toStream(QDataStream &stream) const {
stream << _data;
return stream;
}
bool operator==(const BaseId &left, const BaseId &other) {
return left._data == other._data;
}
uint qHash(const NP::BaseId &object) {
return qHash(object.toRaw());
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2018-2020 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 BaseId_H
#define BaseId_H
#include <QByteArray>
#include <streambase.h>
namespace NP {
/**
* @brief The BaseId class. General class for work with database id.
* Database id is '1byte of prefix + hash (sha256)' from object value.
*/
class NETWORKPROTOCOLSHARED_EXPORT BaseId: public StreamBase
{
public:
BaseId();
BaseId(unsigned int val);
BaseId(const QByteArray& raw);
BaseId(const QString& base64);
/**
* @brief fromBase64
* @param base64
* @return
*/
bool fromBase64(const QByteArray& base64);
/**
* @brief fromRaw
* @param raw
* @return
*/
bool fromRaw(const QByteArray& raw);
/**
* @brief fromRaw
* @param raw
* @return
*/
bool fromRaw(const char* data, int len);
/**
* @brief toBase64
* @return
*/
QByteArray toBase64() const;
/**
* @brief toRaw
* @return
*/
const QByteArray& toRaw() const;
/**
* @brief isValid
* @return true if object is valid
*/
virtual bool isValid() const;
/**
* @brief clear
* @return
*/
void clear();
/**
* @brief prefix - return prefix of id. if id is not valid return 0.
* @return prefix of id
*/
unsigned char prefix() const;
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
friend bool operator== (const BaseId& left, const BaseId& other);
private:
QByteArray _data;
};
uint qHash(const NP::BaseId& object);
}
#endif // BaseId_H

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2018-2020 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 "basenodeinfo.h"
#include "dbaddress.h"
#include <QTcpSocket>
#include <hostaddress.h>
namespace NP {
BaseNodeInfo::BaseNodeInfo(QAbstractSocket *tcp, const HostAddress* address):
AbstractNodeInfo(tcp, address){}
BaseNodeInfo::~BaseNodeInfo() = default;
bool BaseNodeInfo::isValid() const {
return AbstractNodeInfo::isValid();
}
BaseId BaseNodeInfo::selfId() const {
return _selfId;
}
void BaseNodeInfo::setSelfId(const BaseId &selfId) {
_selfId = selfId;
}
bool BaseNodeInfo::confirmData() const {
return AbstractNodeInfo::confirmData();
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2018-2020 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 CONNECTIONINFO_H
#define CONNECTIONINFO_H
#include "abstractnodeinfo.h"
#include "accesstoken.h"
#include "baseid.h"
#include "heart_global.h"
#include <QByteArray>
class QAbstractSocket;
namespace NP {
class DbAddress;
/**
* @brief The BaseNodeInfo class contaisn list of nodes id of know this node.
*/
class NETWORKPROTOCOLSHARED_EXPORT BaseNodeInfo: public AbstractNodeInfo {
public:
/**
* @brief BaseNodeInfo - create node info from the tcp descriptor
* @param tcp - tcp socket dsscriptor
*/
explicit BaseNodeInfo(QAbstractSocket * tcp = nullptr,
const HostAddress* clientAddress = nullptr);
~BaseNodeInfo() override;
/**
* @brief isValid
* @return true if node is valid.
*/
bool isValid() const override;
/**
* @brief selfId - it is id of peer node
* @return
*/
BaseId selfId() const;
/**
* @brief setSelfId
* @param selfId
*/
void setSelfId(const BaseId &selfId);
/**
* @brief confirmData - this implementaton check self id of node.
* @return true if node contains valid self id.
*/
bool confirmData() const override;
protected:
BaseId _selfId;
};
}
#endif // CONNECTIONINFO_H

View File

@ -0,0 +1,452 @@
/*
* Copyright (C) 2018-2020 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 "accesstoken.h"
#include "databasenode.h"
#include "abstractnodeinfo.h"
#include "sqldbcache.h"
#include "sqldbwriter.h"
#include "websocketcontroller.h"
#include "asyncsqldbwriter.h"
#include <badrequest.h>
#include <quasarapp.h>
#include <websocket.h>
#include <websocketsubscriptions.h>
#include <websocketcontroller.h>
#include <QCoreApplication>
#include <qsecretrsa2048.h>
#include <ping.h>
#include <keystorage.h>
#include <basenodeinfo.h>
#include <networkmember.h>
#include <memberpermisionobject.h>
#define THIS_NODE "this_node_key"
namespace NP {
DataBaseNode::DataBaseNode(NP::SslMode mode, QObject *ptr):
AbstractNode(mode, ptr) {
_webSocketWorker = new WebSocketController(this);
}
bool DataBaseNode::initSqlDb(QString DBparamsFile,
SqlDBCache *cache,
SqlDBWriter *writer) {
initDefaultDbObjects(cache, writer);
QVariantMap params;
if (DBparamsFile.isEmpty()) {
params = defaultDbParams();
return _db->init(params);
}
if (!_db->init(DBparamsFile)) {
return false;
}
return true;
}
bool DataBaseNode::isSqlInited() const {
return _db;
}
bool DataBaseNode::run(const QString &addres, unsigned short port) {
if (!isSqlInited() && !initSqlDb()) {
return false;
}
return AbstractNode::run(addres, port);
}
bool DataBaseNode::run(const QString &addres,
unsigned short port,
const QString &localNodeName) {
if (localNodeName.isEmpty())
return false;
_localNodeName = localNodeName;
if (!isSqlInited() && !initSqlDb()) {
return false;
}
return AbstractNode::run(addres, port);
}
void DataBaseNode::stop() {
AbstractNode::stop();
if (db()) {
auto writer = _db->writer();
delete _db;
_db = nullptr;
delete writer;
}
}
DataBaseNode::~DataBaseNode() {
}
void DataBaseNode::initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer) {
if (!writer) {
writer = new AsyncSqlDbWriter();
}
if (!cache) {
cache = new SqlDBCache();
}
cache->setWriter(writer);
_db = cache;
connect(_db, &SqlDBCache::sigItemChanged,
_webSocketWorker, &WebSocketController::handleItemChanged);
}
bool DataBaseNode::welcomeAddress(const HostAddress&) {
return true;
}
bool DataBaseNode::isBanned(const BaseId &node) const {
NetworkMember member(node);
auto objectFromDataBase = db()->getObject(member);
return objectFromDataBase->trust() <= 0;
}
void DataBaseNode::nodeConnected(const HostAddress &node) {
AbstractNode::nodeConnected(node);
welcomeAddress(node);
}
QString DataBaseNode::dbLocation() const {
if (db() && db()->writer()) {
return db()->writer()->databaseLocation();
}
return "";
}
bool DataBaseNode::sendData(AbstractData *resp,
const HostAddress &addere,
const Header *req) {
return AbstractNode::sendData(resp, addere, req);
}
bool DataBaseNode::sendData(const AbstractData *resp,
const HostAddress &addere,
const Header *req) {
return AbstractNode::sendData(resp, addere, req);
}
bool DataBaseNode::sendData(AbstractData *resp,
const BaseId &nodeId,
const Header *req) {
if (!resp || !resp->prepareToSend()) {
return false;
}
return sendData(const_cast<const AbstractData*>(resp), nodeId, req);
}
bool DataBaseNode::sendData(const AbstractData *resp, const BaseId &nodeId, const Header *req) {
auto nodes = connections();
for (auto it = nodes.begin(); it != nodes.end(); ++it) {
auto info = dynamic_cast<BaseNodeInfo*>(it.value());
if (info && info->selfId() == nodeId) {
return sendData(resp, it.key(), req);
}
}
return false;
}
void DataBaseNode::badRequest(const HostAddress &address, const Header &req, const QString msg) {
AbstractNode::badRequest(address, req, msg);
}
void DataBaseNode::badRequest(const BaseId &address, const Header &req, const QString msg) {
if (!changeTrust(address, REQUEST_ERROR)) {
QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!"
" because trust not changed",
QuasarAppUtils::Error);
return;
}
auto bad = BadRequest(msg);
if (!sendData(&bad, address, &req)) {
return;
}
QuasarAppUtils::Params::log("Bad request sendet to adderess: " +
address.toBase64(),
QuasarAppUtils::Info);
}
bool DataBaseNode::changeTrust(const HostAddress &id, int diff) {
return AbstractNode::changeTrust(id, diff);
}
bool DataBaseNode::changeTrust(const BaseId &id, int diff) {
if (!_db)
return false;
auto client = _db->getObject(NetworkMember{id});
if (!client) {
QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!"
" because client == null",
QuasarAppUtils::Error);
return false;
}
auto clone = client->clone().staticCast<NetworkMember>();
clone->changeTrust(diff);
if (!_db->saveObject(clone.data())) {
return false;
}
return true;
}
ParserResult DataBaseNode::parsePackage(const Package &pkg,
const AbstractNodeInfo *sender) {
auto parentResult = AbstractNode::parsePackage(pkg, sender);
if (parentResult != ParserResult::NotProcessed) {
return parentResult;
}
if (H_16<WebSocket>() == pkg.hdr.command) {
WebSocket obj(pkg);
BaseId requesterId = getSender(sender, &obj);
if (!obj.isValid()) {
badRequest(sender->networkAddress(), pkg.hdr);
return ParserResult::Error;
}
if (!workWithSubscribe(obj, requesterId, *sender)) {
badRequest(sender->networkAddress(), pkg.hdr);
return ParserResult::Error;
}
return ParserResult::Processed;
} else if (H_16<WebSocketSubscriptions>() == pkg.hdr.command) {
WebSocketSubscriptions obj(pkg);
if (!obj.isValid()) {
badRequest(sender->networkAddress(), pkg.hdr);
return ParserResult::Error;
}
incomingData(&obj, sender->networkAddress());
return ParserResult::Processed;
}
return ParserResult::NotProcessed;
}
QString DataBaseNode::hashgenerator(const QByteArray &pass) {
return QCryptographicHash::hash(
QCryptographicHash::hash(pass, QCryptographicHash::Sha256) + "QuassarAppSoult",
QCryptographicHash::Sha256);
}
SqlDBCache *DataBaseNode::db() const {
return _db;
}
bool DataBaseNode::workWithSubscribe(const WebSocket &rec,
const BaseId &clientOrNodeid,
const AbstractNodeInfo & sender) {
auto _db = db();
if (_db)
return false;
switch (static_cast<WebSocketRequest>(rec.getRequestCmd())) {
case WebSocketRequest::Subscribe: {
return _webSocketWorker->subscribe(clientOrNodeid, rec.address());
}
case WebSocketRequest::Unsubscribe: {
_webSocketWorker->unsubscribe(clientOrNodeid, rec.address());
return true;
}
case WebSocketRequest::SubscribeList: {
WebSocketSubscriptions resp;
resp.setAddresses(_webSocketWorker->list(clientOrNodeid));
return sendData(&resp, sender.networkAddress());
}
default: break;
}
return false;
}
QVariantMap DataBaseNode::defaultDbParams() const {
return {
{"DBDriver", "QSQLITE"},
{"DBFilePath", DEFAULT_DB_PATH + "/" + _localNodeName + "/" + _localNodeName + "_" + DEFAULT_DB_NAME},
{"DBInitFile", DEFAULT_DB_INIT_FILE_PATH}
};
}
DBOperationResult NP::DataBaseNode::getObject(const NP::BaseId &requester,
const NP::DBObject &templateObj,
const DBObject** result) const {
if (!_db && !result) {
return DBOperationResult::Unknown;
}
DBOperationResult permisionResult = checkPermission(requester, templateObj.dbAddress(),
Permission::Read);
if (permisionResult != DBOperationResult::Allowed) {
return permisionResult;
}
auto obj = _db->getObject(templateObj);
if (!obj || (obj->dbAddress() != templateObj.dbAddress())) {
return DBOperationResult::Unknown;
}
*result = obj;
return DBOperationResult::Allowed;
}
DBOperationResult DataBaseNode::getObjects(const BaseId &requester,
const DBObject &templateObj,
QList<const DBObject *> *result) const {
if (!_db && !result) {
return DBOperationResult::Unknown;
}
if (!_db->getAllObjects(templateObj, *result)) {
return DBOperationResult::Unknown;
}
for (const auto& obj: *result) {
if (!obj)
return DBOperationResult::Unknown;
auto permisionResult = checkPermission(requester, obj->dbAddress(),
Permission::Read);
if (permisionResult != DBOperationResult::Allowed) {
return permisionResult;
}
}
return DBOperationResult::Allowed;
}
DBOperationResult DataBaseNode::setObject(const BaseId &requester,
const DBObject *saveObject) {
if (!_db) {
return DBOperationResult::Unknown;
}
auto permisionResult = checkPermission(requester,
saveObject->dbAddress(),
Permission::Write);
if (permisionResult != DBOperationResult::Allowed) {
return permisionResult;
}
if (!_db->saveObject(saveObject)) {
return DBOperationResult::Unknown;
}
return DBOperationResult::Allowed;
}
BaseId DataBaseNode::getSender(const AbstractNodeInfo *connectInfo, const AbstractData *) const {
auto info = dynamic_cast<const BaseNodeInfo*>(connectInfo);
if (!info)
return {};
return info->selfId();
}
DBOperationResult DataBaseNode::checkPermission(const BaseId &requester,
const DbAddress &objectAddress,
const Permission& requarimentPermision) const {
const NetworkMember *member = _db->getObject(NetworkMember{requester});
if (!member) {
return DBOperationResult::Unknown;
}
const MemberPermisionObject *permision =
_db->getObject(MemberPermisionObject({requester, objectAddress}));
if (!permision) {
return DBOperationResult::Unknown;
}
if (permision->permisions() < requarimentPermision) {
return DBOperationResult::Forbidden;
}
return DBOperationResult::Allowed;
}
DBOperationResult DataBaseNode::deleteObject(const BaseId &requester,
const DBObject *dbObject) {
if (!_db) {
return DBOperationResult::Unknown;
}
auto permisionResult = checkPermission(requester,
dbObject->dbAddress(),
Permission::Write);
if (permisionResult != DBOperationResult::Allowed) {
return permisionResult;
}
if (!_db->deleteObject(dbObject)) {
return DBOperationResult::Unknown;
}
return DBOperationResult::Allowed;
}
}

View File

@ -0,0 +1,310 @@
/*
* Copyright (C) 2018-2020 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 DATABASENODE_H
#define DATABASENODE_H
#include "abstractnode.h"
#include <dbobject.h>
#include <hostaddress.h>
#include <permission.h>
namespace NP {
class SqlDBCache;
class SqlDBWriter;
class WebSocket;
class WebSocketController;
class DbAddress;
class BaseId;
/**
* @brief The BaseNode class - base inplementation of nodes. This implementation contains methods for work with database and work with data transopt on network.
* BaseNode - is thread save class
*/
class NETWORKPROTOCOLSHARED_EXPORT DataBaseNode : public AbstractNode
{
Q_OBJECT
public:
/**
* @brief BaseNode
* @param mode
* @param ptr
*/
DataBaseNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr);
~DataBaseNode() override;
/**
* @brief intSqlDb - this function init database of node
* @param DBparamsFile - path to json file with all patarams
* @param cache - new SqlDBCache object
* @param writer - new SqlDBWriter
* @return true if all good
*/
virtual bool initSqlDb( QString DBparamsFile = "",
SqlDBCache * cache = nullptr,
SqlDBWriter* writer = nullptr);
/**
* @brief isSqlInited
* @return return true if intSqlDb invocked correctly;
*/
bool isSqlInited() const;
/**
* @brief run server on address an port
* @param addres - If address is empty then serve weel be listen all addreses of all interfaces
* @param port
* @return recomendet befor invoke this method call the intSqlDb.
* If you skeap a call of intSqlDb method then data base inited with default parameters.
*/
bool run(const QString &addres, unsigned short port) override;
/**
* @brief run server on address an port with local name of storage of keys
* @param addres - network address of node
* @param port - port of node
* @return true if node is deployed successful
*/
virtual bool run(const QString &addres, unsigned short port,
const QString &localNodeName);
/**
* @brief stop - this implementation stop work database and push to database all cache data.
*/
void stop() override;
/**
* @brief defaultDbParams
* @return
*/
virtual QVariantMap defaultDbParams() const;
protected:
/**
* @brief initDefaultDbObjects create default cache and db writer if pointer is null
* @param cache
* @param writer
*/
void initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer);
/**
* @brief parsePackage
* @param pkg
* @param sender
* @return
*/
ParserResult parsePackage(const Package &pkg,
const AbstractNodeInfo* sender) override;
/**
* @brief sendData - send data to an ip address
* @param resp
* @param addere
* @param req
* @return true if a function finished seccussful
*/
bool sendData(AbstractData *resp,
const HostAddress &addere,
const Header *req = nullptr) override;
/**
* @brief sendData - send data to an ip address
* @param resp
* @param addere
* @param req
* @return true if a function finished seccussful
*/
bool sendData(const AbstractData *resp,
const HostAddress &addere,
const Header *req = nullptr) override;
/**
* @brief sendDataToId - send data to node or clientby them id. This implementation prepare object to sending.
* @param resp - responce package
* @param nodeId - id of target node
* @param req - header of request
* @return true if data sendet seccussful
*/
virtual bool sendData(AbstractData *resp, const BaseId &nodeId,
const Header *req = nullptr);
/**
* @brief sendDataToId - send data to node or clientby them id.
* @param resp - responce package
* @param nodeId - id of target node
* @param req - header of request
* @return true if data sendet seccussful
*/
virtual bool sendData(const AbstractData *resp, const BaseId &nodeId,
const Header *req = nullptr);
/**
* @brief badRequest -send bad request and change trus for ip address
* @param address
* @param req
* @param msg
*/
void badRequest(const HostAddress &address, const Header &req,
const QString msg = "") override;
/**
* @brief badRequest - send bad request to node with id
* @param address - id of target node or client
* @param req - header of an accepted request.
* @param msg
*/
virtual void badRequest(const BaseId &address, const Header &req,
const QString msg = "");
/**
* @brief changeTrust - change trust of ip address
* @param id - ip address of node
* @param diff
*/
bool changeTrust(const HostAddress &id, int diff) override;
/**
* @brief changeTrust change trus of node with id.
* @param id
* @param diff
* @return true if functin finished seccussful
*/
virtual bool changeTrust(const BaseId &id, int diff);
/**
* @brief hashgenerator
* @param pass
*/
virtual QString hashgenerator(const QByteArray &pass);
/**
* @brief nodeConnected - this implementation call a welcomeAddress method.
* @param node
*/
void nodeConnected(const HostAddress &node) override;
/**
* @brief db
* @return pinter to data base
*/
SqlDBCache* db() const;
/**
* @brief workWithSubscribe - this metod work work with subscribe commnads
* @param rec request data
* @param address sendet address
* @return true if data parsed seccusseful
*/
bool workWithSubscribe(const WebSocket &rec,
const BaseId &clientOrNodeid, const AbstractNodeInfo &sender);
/**
* @brief deleteObject - delete object by address dbObject
* @param requester - reqester.
* @param dbObject
* @return result of operation (allow, forbiden unknown)
*/
DBOperationResult deleteObject(const BaseId &requester,
const DBObject *dbObject);
/**
* @brief getObject - general method for geting object wth check permisions
* this function check permishen to requested object and set new object to res if access granted.
* @param requester - requser node or client
* @param templateObj - object with request
* @param result - pointer to pointer of result object
* @return operation status
*/
DBOperationResult getObject(const BaseId &requester,
const DBObject &templateObj,
const DBObject **result) const;
/**
* @brief getObjects - general object for get object
* this function check permishen to requested object and set new object to res if access granted.
* @param requester - requser node or client
* @param templateObj - object with request
* @param result - pointer to list of pointers with result objects
* @return operation status
*/
DBOperationResult getObjects(const BaseId &requester,
const DBObject &templateObj,
QList<const DBObject *> *result) const;
/**
* @brief setObject
* @param saveObject
* @param requiredNodeAddere
* @param dbObject
* @return operation status
*/
DBOperationResult setObject(const BaseId &requester,
const DBObject *saveObject);
/**
* @brief getSender - this method return id of requester.
* @default Base implementation get id from BaseNdoeInfo.
* @param connectInfo - info about connect
* @param requestData - data of request
* @return id of requester member
*/
virtual BaseId getSender(const AbstractNodeInfo *connectInfo, const AbstractData *requestData) const;
/**
* @brief checkPermision - check permision of requester to objectAddress
* Override this method for your backend
* @param requester - user on node or another object of network
* @param objectAddress - addres to database object
* @param requarimentPermision - needed permision for requester
* @return DBOperationResult::Alowed if permission granted
*/
virtual DBOperationResult checkPermission(const BaseId& requester,
const DbAddress& objectAddress,
const Permission& requarimentPermision) const;
/**
* @brief dbLocation - return location of database of node.
* @return path to the location of database
*/
QString dbLocation() const;
/**
* @brief welcomeAddress - this method send to the ip information about yaster self.
* @param ip - host address of the peer node obeject
* @return true if all iformation sendet succesful
*/
virtual bool welcomeAddress(const HostAddress &ip);
/**
* @brief isBanned - check trust of node, if node trus is lover of 0 return true.
* @param member
* @return true if node is banned
*/
bool isBanned(const BaseId& member) const;
private:
SqlDBCache *_db = nullptr;
QString _localNodeName;
WebSocketController *_webSocketWorker = nullptr;
friend class WebSocketController;
};
}
#endif // DATABASENODE_H

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2018-2020 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 "dbaddress.h"
#include <QDataStream>
#include <QHash>
namespace NP {
qint64 qHash(const DbAddress &address) {
return qHash(address.id().toRaw() + address.table());
}
DbAddress::DbAddress(const QString &table, const BaseId &id) {
this->_table = table;
this->_id = id;
}
bool operator==(const DbAddress & left, const DbAddress &other) {
return left._table == other._table && left._id == other._id;
}
QDataStream &DbAddress::fromStream(QDataStream &stream) {
stream >> _id;
stream >> _table;
return stream;
}
QDataStream &DbAddress::toStream(QDataStream &stream) const {
stream << _id;
stream << _table;
return stream;
}
QString DbAddress::toString() const {
return QString("DbAddress: id:%0, table:%1").
arg(QString(_id.toBase64())).
arg(_table);
}
bool operator!=(const DbAddress &left, const DbAddress &other) {
return !operator==(left, other);
}
bool DbAddress::isValid() const {
return _id.isValid() && _table.size();
}
const QString& DbAddress::table() const {
return _table;
}
void DbAddress::setTable(const QString &table) {
_table = table;
}
const BaseId& DbAddress::id() const {
return _id;
}
void DbAddress::setId(const BaseId &id) {
_id = id;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2018-2020 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 DBADDRESS_H
#define DBADDRESS_H
#include "streambase.h"
#include "basedefines.h"
#include "baseid.h"
namespace NP {
/**
* @brief The DbAddress class - this is address of data base object
*/
class NETWORKPROTOCOLSHARED_EXPORT DbAddress : public StreamBase {
public:
DbAddress() = default;
DbAddress(const QString& table, const BaseId& id);
QDataStream &fromStream(QDataStream &stream);
QDataStream &toStream(QDataStream &stream) const;
/**
* @brief toString - return a string implementation fo this object
* @return string of object
*/
QString toString() const;
friend bool operator== (const DbAddress& left, const DbAddress& other);
friend bool operator!= (const DbAddress& left, const DbAddress& other);
bool isValid() const;
const QString& table() const;
void setTable(const QString &table);
const BaseId &id() const;
void setId(const BaseId &id);
private:
QString _table;
BaseId _id;
};
qint64 qHash(const DbAddress& address);
}
#endif // DBADDRESS_H

View File

@ -0,0 +1,42 @@
#include "dbaddresskey.h"
namespace NP {
DbAddressKey::DbAddressKey() {
}
DbAddressKey::DbAddressKey(const DbAddress &address):
DbAddress(address) {
}
DbAddressKey::DbAddressKey(const QString &address, const BaseId &id):
DbAddress(address, id) {
}
unsigned int DbAddressKey::hash() const {
return qHash(*static_cast<const DbAddress*>(this));
}
const BaseId &DbAddressKey::id() const {
return DbAddress::id();
}
const QString &DbAddressKey::table() const {
return DbAddress::table();
}
bool DbAddressKey::equal(const AbstractKey *other) const {
auto otherObject = dynamic_cast<const DbAddressKey*>(other);
if (!otherObject)
return false;
return operator==(*static_cast<const DbAddress*>(this), *otherObject);
}
bool DbAddressKey::isValid() const {
return DbAddress::isValid();
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018-2020 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 DBADDRESSKEY_H
#define DBADDRESSKEY_H
#include "abstractkey.h"
#include "dbaddress.h"
namespace NP {
/**
* @brief The DbAddressKey class - key provider for DbAddress
*/
class NETWORKPROTOCOLSHARED_EXPORT DbAddressKey: public DbAddress, public AbstractKey
{
public:
DbAddressKey();
DbAddressKey(const DbAddress& address);
DbAddressKey(const QString& address, const BaseId& id);
unsigned int hash() const override;
const BaseId &id() const override;
const QString &table() const override;
bool equal(const AbstractKey *other) const override;
bool isValid() const override;
};
}
#endif // DBADDRESSKEY_H

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2018-2020 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 "dbcachekey.h"
#include <abstractkey.cpp>
namespace NP {
DBCacheKey *DBCacheKey::instance() {
static auto ptr = new DBCacheKey();
return ptr;
}
QString DBCacheKey::description(uint hash) const {
auto val = value(hash);
if (!val)
return "";
return QString("table:%0 id:%1").arg(val->id().toBase64(), val->table());
}
DBCacheKey::DBCacheKey() {}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2018-2020 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 DBCACHEKEY_H
#define DBCACHEKEY_H
#include "baseid.h"
#include <abstractkey.h>
#include <QHash>
#include <heart_global.h>
namespace NP {
/**
* @brief The DBCacheKey class - is database main key value
*/
class NETWORKPROTOCOLSHARED_EXPORT DBCacheKey
{
public:
/**
* @brief instance
* @return singleton of object
*/
static DBCacheKey* instance();
template <class TYPE = AbstractKey>
/**
* @brief value - return vale from key
* @param key - hash of ke value
* @return value of key
*/
const TYPE* value(uint key) const {
return dynamic_cast<const TYPE*>(_data.value(key, nullptr));
}
template <class TYPE>
/**
* @brief key - return hash key and save object into objects table
* @param value - the value of a key objekt
* @return hash of input value
*/
uint key(const TYPE& value) {
auto object = dynamic_cast<const AbstractKey*>(&value);
if (!object) {
return 0;
}
uint hash = object->hash();
if (_data.contains(hash)) {
_data[hash] = new TYPE(value);
}
return hash;
}
/**
* @brief description - return string description of id
* @param hash
* @return
*/
QString description(uint hash) const;
private:
QHash<uint, AbstractKey*> _data;
DBCacheKey();
};
#define HASH_KEY(X) DBCacheKey::instance()->key(X)
#define VALUE_KEY(X) DBCacheKey::instance()->value(X)
#define DESCRIPTION_KEY(X) DBCacheKey::instance()->description(X)
}
#endif // DBCACHEKEY_H

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2018-2020 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 "iobjectprovider.h"
namespace NP {
iObjectProvider::iObjectProvider() = default;
iObjectProvider::~iObjectProvider() = default;
const DBObject *iObjectProvider::getObjectRaw(const DBObject &templateVal) {
if (!dynamic_cast<const DBObject*>(&templateVal)) {
return nullptr;
}
QList<const DBObject *> list;
if (!getAllObjects(templateVal, list)) {
return nullptr;
}
if (list.size() > 1) {
QuasarAppUtils::Params::log("getObject method returned more than one object,"
" the first object was selected as the result, all the rest were lost.",
QuasarAppUtils::Warning);
}
return list.first();
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2018-2020 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 IOBJECTPROVIDER_H
#define IOBJECTPROVIDER_H
#include "heart_global.h"
#include <QSharedPointer>
#include <dbobject.h>
#include <quasarapp.h>
namespace NP {
class AbstractData;
class NETWORKPROTOCOLSHARED_EXPORT iObjectProvider
{
public:
iObjectProvider();
virtual ~iObjectProvider();
/**
* @brief getObject - this method return pointer to DBObject created by select method of template object.
* @param obj - template object with a select db request.
* @return return pointer to DBObject ot nullptr id object not exits.
*/
template<class TYPE>
const TYPE *getObject(const TYPE &templateVal) {
auto val = getObjectRaw(templateVal);
const TYPE* result = dynamic_cast<const TYPE*>(val);
if (!result && val) {
QuasarAppUtils::Params::log("getObject method returned object with deffirent type of TYPE,"
" check getAllObjects merhod",
QuasarAppUtils::Error);
}
return result;
}
/**
* @brief getObjectRaw - return object without test object type
* @note if you want get object with check object type use getObject method.
* @param templateVal - template object with request to database
* @return - return database object pointer (not casted)
*/
const DBObject *getObjectRaw(const DBObject &templateVal);
/**
* @brief getAllObjects - executable select method of objects and return list of all selected objects
* @param obj - template object with select request.
* @param result - return value, list of selected objects.
* @return true if objects have in db else false.
*/
virtual bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) = 0;
/**
* @brief saveObject
* @return
*/
virtual bool saveObject(const DBObject* saveObject) = 0;
/**
* @brief deleteObject
* @return
*/
virtual bool deleteObject(const DBObject* obj) = 0;
};
}
#endif // IOBJECTPROVIDER_H

View File

@ -0,0 +1,184 @@
/*
* Copyright (C) 2018-2020 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 "dbaddresskey.h"
#include "dbcachekey.h"
#include "dbobject.h"
#include <QDataStream>
#include <QDateTime>
#include <QSqlQuery>
#include <QHash>
#include <QSqlRecord>
#include <QVariantMap>
#include <QSharedPointer>
namespace NP {
DBObject::DBObject(const QString &tableName) {
clear();
_dbId.setTable(tableName);
}
DBObject::~DBObject() {
}
QString DBObject::tableName() const {
return _dbId.table();
}
PrepareResult DBObject::prepareSelectQuery(QSqlQuery &q) const {
QString queryString = "SELECT * FROM %0 " + getWhereBlock();
queryString = queryString.arg(tableName());
if (!q.prepare(queryString)) {
return PrepareResult::Fail;
}
return PrepareResult::Success;
}
bool DBObject::fromSqlRecord(const QSqlRecord &q) {
if (q.contains("id")) {
setId(q.value("id").toString());
return true;
}
return false;
}
bool DBObject::isCached() const {
return true;
}
bool DBObject::isBundle() const {
return false;
}
uint DBObject::dbKey() const {
return HASH_KEY(DbAddressKey(_dbId));
}
QPair<QString, QString> DBObject::altarnativeKey() const {
return {};
}
DbAddress DBObject::dbAddress() const {
return _dbId;
}
QSharedPointer<DBObject> DBObject::clone() const {
return QSharedPointer<DBObject>(cloneRaw());
}
DBObject *DBObject::cloneRaw() const {
auto cloneObject = factory();
if (!cloneObject->copyFrom(this)) {
return nullptr;
}
cloneObject->init();
return cloneObject;
}
QString DBObject::toString() const {
return AbstractData::toString() +
QString(" %0").arg(_dbId.toString());
}
QString DBObject::getWhereBlock() const {
QString whereBlock = "WHERE ";
if (getId().isValid()) {
whereBlock += "id='" + getId().toBase64() + "'";
} else {
auto altKeys = altarnativeKey();
if (altKeys.first.isEmpty()) {
return {};
}
whereBlock += altKeys.first + "='" + altKeys.second + "'";
}
return whereBlock;
}
PrepareResult DBObject::prepareRemoveQuery(QSqlQuery &q) const {
QString queryString = "DELETE FROM %0 " + getWhereBlock();
queryString = queryString.arg(tableName());
if (!q.prepare(queryString)) {
return PrepareResult::Fail;
}
return PrepareResult::Success;
}
QDataStream &DBObject::fromStream(QDataStream &stream) {
AbstractData::fromStream(stream);
stream >> _dbId;
return stream;
}
QDataStream &DBObject::toStream(QDataStream &stream) const {
AbstractData::toStream(stream);
stream << _dbId;
return stream;
}
bool DBObject::init() {
if (!AbstractData::init())
return false;
if (isBundle()) {
return true;
}
_dbId.setId(generateId());
return _dbId.isValid();
}
bool DBObject::isValid() const {
return AbstractData::isValid() && _dbId.isValid();
}
bool DBObject::copyFrom(const AbstractData * other) {
if (!AbstractData::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const DBObject*>(other);
if (!otherObject)
return false;
this->_dbId = otherObject->_dbId;
return true;
}
BaseId DBObject::getId() const {
return dbAddress().id();
}
void DBObject::setId(const BaseId& id) {
_dbId.setId(id);
}
void DBObject::clear() {
setId({});
}
}

View File

@ -0,0 +1,212 @@
/*
* Copyright (C) 2018-2020 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 DBOBJECT_H
#define DBOBJECT_H
#include <QSqlRecord>
#include <QVariantMap>
#include "abstractdata.h"
#include "heart_global.h"
#include "dbaddress.h"
#include "basedefines.h"
#include "dbcachekey.h"
class QSqlQuery;
namespace NP {
/**
* @brief The PrepareResult enum - result of work prepare sql query
*/
enum class PrepareResult {
/// prepare finished fail.
Fail,
/// prepare finished succussful
Success,
/// prepare disabled for method. Use this case for disable prepare method for object without errors.
Disabled,
};
/**
* @brief The DBObject class- main class for work with data base.
*/
class NETWORKPROTOCOLSHARED_EXPORT DBObject : public AbstractData
{
public:
/**
* @brief DBObject
*/
DBObject(const QString& tableName);
~DBObject() override;
//// AbstractData interface
bool isValid() const override;
/**
* @brief copyFrom get all data from other
* @arg other - other data package
* @return return true if method finished seccussful
*/
bool copyFrom(const AbstractData * other) override;
/**
* @brief getId
* @return id of objcet
*/
BaseId getId() const;
/**
* @brief setId - set new id for db object
* @param id
*/
void setId(const BaseId& id);
/**
* @brief clear
*/
virtual void clear();
/**
* @brief tableName
* @return
*/
QString tableName() const;
/**
* @brief factory
* @return clone of self object pointer
*/
virtual DBObject* factory() const = 0;
/**
* @brief prepareSelectQuery - override this metod for get item from database
* this method need to prepare a query for selected data.
* the default implementation generate default select: "select * from [table] where id=[id]".
* If id is empty this implementation use data from altarnativeKey method.
* @param q - query object
* @return true if query is prepared seccussful
*/
virtual PrepareResult prepareSelectQuery(QSqlQuery& q) const;
/**
* @brief fromSqlRecord- this method need to init this object from executed sqlRecord.
* default implementation get general dbObject information ( id and table name )
* @note this method weel be invoke for one object. but if isBundle return 'true' then a function fromSqlRecord moust be invoked foreach all elements of list.
* @param q - sql record
* @return true if method finished succesful
*/
virtual bool fromSqlRecord(const QSqlRecord& q);
/**
* @brief prepareSaveQuery - override this method for save item into database
* this method need to prepare a query for selected data.
* @param q - query of requst
* @return PrepareResult value
*/
virtual PrepareResult prepareSaveQuery(QSqlQuery& q) const = 0 ;
/**
* @brief prepareRemoveQuery - override this method for remove this item from database.
* this method need to prepare a query for remove this object.
* the default implementatin remove item from id or primaryKey.
* If id is empty this implementation use data from altarnativeKey method.
* @param q - query of requst
* @return PrepareResult value
*/
virtual PrepareResult prepareRemoveQuery(QSqlQuery& q) const;
/**
* @brief isCached
* @return return true if item in cache. default implementation retun true only
*/
virtual bool isCached() const;
/**
* @brief isBundle
* If this function return true then SqlDBWriter create only one object after invoked selectquery.
* And if the selectquery function return a list of more 1 elements then a method fromSqlRecord moust be invoked foreach all elements of list.
* @return true if the object is a selection from a set of database object.
*/
virtual bool isBundle() const;
/**
* @brief dbAddress - unique address of item in database {id:table}
* default implementation
* @return unique key of this object
*/
virtual uint dbKey() const;
/**
* @brief altarnativeKey - this method need to return a altarnative key:value pair for a select object when a object do not have a database id.
* @default default implementation return empty pair.
* @return pair of altarnative keys. Key : Value.
*/
virtual QPair<QString, QString> altarnativeKey() const;
/**
* @brief dbAddress
* @return
*/
DbAddress dbAddress() const;
/**
* @brief clone - this nethod create a new object. The new Object is cone of current object.
* @note If you want to get raw pointer to cone object use a "cloneRaw" method.
* @return return shared pointer to clone of current object
*/
QSharedPointer<DBObject> clone() const;
/**
* @brief cloneRaw - this method return a raw pointer to clone of this object.
* @warning - clone object don not removed automatically and may result in a memory leak.
* @note for get a shared pointer of clone object use the "clone" method.
* @return retuen raw pointer to cloe of this object.
*/
DBObject* cloneRaw() const;
/**
* @brief toString - return a string implementation fo this object
* @return string of object
*/
QString toString() const override;
protected:
//// StreamBase interface
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
/**
* @brief generateId - override this method for all db Objects.
* if create id is impasoble ther retrun not valid id.
* @return retuern Id of database object
*/
virtual BaseId generateId() const = 0;
/**
* @brief init - init this object, prepare work with database.
* @default - this implementation is create id for object of database.
* If method generateId return not valid id this method return false.
* @return true if object initialized fuccessful else return false.
*/
bool init() override;
private:
QString getWhereBlock() const;
DbAddress _dbId;
};
}
Q_DECLARE_METATYPE(const NP::DBObject*)
Q_DECLARE_METATYPE(NP::DBObject*)
Q_DECLARE_METATYPE(QList<NP::DBObject *>*);
Q_DECLARE_METATYPE(QList<const NP::DBObject *>*);
#endif // DBOBJECT_H

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2018-2020 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 "memberpermisionobject.h"
#include <QDataStream>
#include <QSqlQuery>
#include <dbcachekey.h>
namespace NP {
MemberPermisionObject::MemberPermisionObject():
DBObject("MemberPermisions") {
}
MemberPermisionObject::MemberPermisionObject(const Package &pkg):
MemberPermisionObject() {
fromBytes(pkg.data);
}
MemberPermisionObject::MemberPermisionObject(const PermisionData &id):
MemberPermisionObject() {
setKey(id);
}
bool MemberPermisionObject::isValid() const {
return _key.isValid();
}
bool MemberPermisionObject::copyFrom(const AbstractData *other) {
if (!DBObject::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const MemberPermisionObject*>(other);
if (!otherObject)
return false;
this->_key = otherObject->_key;
this->_permisions = otherObject->_permisions;
return true;
}
PrepareResult MemberPermisionObject::prepareSaveQuery(QSqlQuery &q) const {
if (!isValid()) {
return PrepareResult::Fail;
}
QString queryString = "INSERT INTO %0(%1) VALUES (%3) "
"ON CONFLICT(MemberPermisionsIndex) DO UPDATE SET %2";
queryString = queryString.arg(tableName());
queryString = queryString.arg(
"memberId, objectTable", "objectId", "lvl");
queryString = queryString.arg("memberId='" + _key.id().toBase64() + "', " +
"objectTable='" + _key.address().table()+ "', " +
"objectId='" + _key.address().id().toBase64() + "', " +
"lvl='" + QString::number(static_cast<int>(_permisions)) + "'");
QString values;
values += "'" + _key.id().toBase64() + "', ";
values += "'" + _key.address().table() + "', ";
values += "'" + _key.address().id().toBase64() + "', ";
values += QString::number(static_cast<int>(_permisions));
queryString = queryString.arg(values);
if (q.prepare(queryString))
return PrepareResult::Success;
return PrepareResult::Fail;
}
PrepareResult MemberPermisionObject::prepareRemoveQuery(QSqlQuery &q) const {
if (!isValid()) {
return PrepareResult::Fail;
}
QString queryString = "DELETE FROM %0 where memberId='%1' and objectTable='%2' and objectId='%3'";
queryString = queryString.arg(tableName(),
_key.id().toBase64(),
_key.address().table(),
_key.address().id().toBase64());
if (q.prepare(queryString))
return PrepareResult::Success;
return PrepareResult::Fail;
}
PrepareResult MemberPermisionObject::prepareSelectQuery(QSqlQuery &q) const {
if (_key.isValid()) {
return PrepareResult::Fail;
}
QString queryString = "SELECT * FROM %0 WHERE";
bool fOptionAdded = false;
if (_key.id().isValid()) {
queryString += "memberId='" + _key.id().toBase64() + "'";
fOptionAdded = true;
}
if (_key.address().table().size()) {
if (fOptionAdded)
queryString += " and ";
queryString += "objectTable='" + _key.address().table() + "'";
fOptionAdded = true;
}
if (_key.address().id().isValid()) {
if (fOptionAdded)
queryString += " and ";
queryString += "objectId='" + _key.address().id().toBase64() + "'";
fOptionAdded = true;
}
queryString = queryString.arg(tableName());
if (q.prepare(queryString))
return PrepareResult::Success;
return PrepareResult::Fail;
}
DBObject *MemberPermisionObject::factory() const {
return create<MemberPermisionObject>();
}
uint MemberPermisionObject::dbKey() const {
return HASH_KEY(_key);
}
QDataStream &MemberPermisionObject::fromStream(QDataStream &stream) {
stream >> _key;
stream >> _permisions;
return stream;
}
QDataStream &MemberPermisionObject::toStream(QDataStream &stream) const {
stream << _key;
stream << _permisions;
return stream;
}
BaseId MemberPermisionObject::generateId() const {
if (!_key.isValid())
return {};
return _key.hash();
}
PermisionData MemberPermisionObject::key() const {
return _key;
}
void MemberPermisionObject::setKey(const PermisionData &key) {
_key = key;
}
Permission MemberPermisionObject::permisions() const {
return _permisions;
}
void MemberPermisionObject::setPermisions(const Permission &permisions) {
_permisions = permisions;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2018-2020 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 NODESPERMISIONOBJECT_H
#define NODESPERMISIONOBJECT_H
#include "dbcachekey.h"
#include "dbobject.h"
#include "permisiondata.h"
#include "permission.h"
namespace NP {
/**
* @brief The NodesPermisionObject class - database object of permisions of node
*/
class NETWORKPROTOCOLSHARED_EXPORT MemberPermisionObject: public DBObject
{
public:
MemberPermisionObject();
MemberPermisionObject(const Package& pkg);
MemberPermisionObject(const PermisionData& id);
// AbstractData interface
bool isValid() const override;
bool copyFrom(const AbstractData *other) override;
// DBObject interface
PrepareResult prepareSaveQuery(QSqlQuery &q) const override;
PrepareResult prepareRemoveQuery(QSqlQuery &q) const override;
PrepareResult prepareSelectQuery(QSqlQuery &q) const override;
DBObject *factory() const override;
uint dbKey() const override;
Permission permisions() const;
void setPermisions(const Permission &permisions);
PermisionData key() const;
void setKey(const PermisionData &key);
protected:
// StreamBase interface
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
BaseId generateId() const override;
private:
Permission _permisions;
PermisionData _key;
};
}
#endif // NODESPERMISIONOBJECT_H

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2018-2020 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 "networkmember.h"
#include <quasarapp.h>
#include <QSqlQuery>
#include <QSqlError>
#include <QDataStream>
#include <QCryptographicHash>
namespace NP {
NetworkMember::NetworkMember():DBObject("NetworkMembers") {
}
NetworkMember::NetworkMember(const Package &pkg):
NetworkMember() {
fromBytes(pkg.data);
}
NetworkMember::NetworkMember(const BaseId &id):
NetworkMember() {
setId(id);
}
DBObject *NetworkMember::factory() const {
return create<NetworkMember>();
}
PrepareResult NetworkMember::prepareSaveQuery(QSqlQuery &q) const {
QString queryString = "INSERT INTO %0(%1) VALUES (%3) "
"ON CONFLICT(id) DO UPDATE SET %2";
queryString = queryString.arg(tableName());
queryString = queryString.arg("id, authenticationData, trust");
queryString = queryString.arg("authenticationData=:AuthenticationData, "
"trust=" + QString::number(_trust));
QString values;
values += "'" + getId().toBase64() + "', ";
values += ":AuthenticationData, ";
values += QString::number(_trust);
queryString = queryString.arg(values);
if (q.prepare(queryString)) {
q.bindValue(":AuthenticationData", authenticationData());
return PrepareResult::Success;
}
QuasarAppUtils::Params::log("Query:" + queryString,
QuasarAppUtils::Error);
return PrepareResult::Fail;
}
bool NetworkMember::fromSqlRecord(const QSqlRecord &q) {
if (!DBObject::fromSqlRecord(q)) {
return false;
}
setAuthenticationData(q.value("authenticationData").toByteArray());
setTrust(q.value("trust").toInt());
return isValid();
}
QByteArray NetworkMember::authenticationData() const {
return _authenticationData;
}
void NetworkMember::setAuthenticationData(const QByteArray &publickKey) {
_authenticationData = publickKey;
}
QDataStream &NetworkMember::fromStream(QDataStream &stream) {
DBObject::fromStream(stream);
stream >> _authenticationData;
stream >> _trust;
return stream;
}
QDataStream &NetworkMember::toStream(QDataStream &stream) const {
DBObject::toStream(stream);
stream << _authenticationData;
stream << _trust;
return stream;
}
BaseId NetworkMember::generateId() const {
if (authenticationData().isEmpty()) {
return {};
}
return QCryptographicHash::hash(authenticationData(), QCryptographicHash::Sha256);
}
int NetworkMember::trust() const {
return _trust;
}
void NetworkMember::changeTrust(int diff) {
_trust += diff;
}
void NetworkMember::setTrust(int trust) {
_trust = trust;
}
bool NetworkMember::isValid() const {
return DBObject::isValid() && _authenticationData.size();
}
bool NetworkMember::copyFrom(const AbstractData * other) {
if (!DBObject::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const NetworkMember*>(other);
if (!otherObject)
return false;
this->_authenticationData = otherObject->_authenticationData;
this->_trust = otherObject->_trust;
return true;
}
QPair<QString, QString> NetworkMember::altarnativeKey() const {
return {"authenticationData", _authenticationData.toBase64(QByteArray::Base64UrlEncoding)};
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2018-2020 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 NETWORKMEMBER_H
#define NETWORKMEMBER_H
#include "dbobject.h"
namespace NP {
/**
* @brief The NodeObject class - database structure of node
*/
class NETWORKPROTOCOLSHARED_EXPORT NetworkMember: public DBObject
{
public:
NetworkMember();
NetworkMember(const Package& pkg);
NetworkMember(const BaseId& id);
// DBObject interface
DBObject *factory() const override;
PrepareResult prepareSaveQuery(QSqlQuery &q) const override;
bool fromSqlRecord(const QSqlRecord &q) override;
QByteArray authenticationData() const;
void setAuthenticationData(const QByteArray &publickKey);
// AbstractData interface
bool isValid() const override;
bool copyFrom(const AbstractData *) override;
QPair<QString, QString> altarnativeKey() const override;
int trust() const;
void changeTrust(int diff);
void setTrust(int trust);
protected:
// StreamBase interface
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
BaseId generateId() const override;
private:
QByteArray _authenticationData;
int _trust;
};
}
#endif // NETWORKMEMBER_H

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2018-2020 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 "websocket.h"
#include <QDataStream>
#include <QSharedPointer>
namespace NP {
WebSocket::WebSocket(): AbstractData(){
}
WebSocket::WebSocket(const Package &package):
WebSocket() {
fromBytes(package.data);
}
QDataStream &WebSocket::fromStream(QDataStream &stream) {
AbstractData::fromStream(stream);
stream >> requestCmd;
stream >> _address;
return stream;
}
QDataStream &WebSocket::toStream(QDataStream &stream) const {
AbstractData::toStream(stream);
stream << requestCmd;
stream << _address;
return stream;
}
DbAddress WebSocket::address() const {
return _address;
}
void WebSocket::setAddress(const DbAddress &address) {
_address = address;
}
bool WebSocket::isValid() const {
return requestCmd > static_cast<int>(WebSocketRequest::Invalied)
&& AbstractData::isValid();
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2018-2020 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 WEBSOCKET_H
#define WEBSOCKET_H
#include "dbobject.h"
#include "request.h"
namespace NP {
/**
* @brief The WebSocketRequest enum
*/
enum class WebSocketRequest {
/// Invalied data
Invalied = 0,
/// subscribe to data
Subscribe = 1,
/// unsubscribe
Unsubscribe = 2,
/// get list of curennt subscribes
SubscribeList = 3
};
/**
* @brief The WebSocket class - this class contains methods for work with stream data
*/
class NETWORKPROTOCOLSHARED_EXPORT WebSocket:
public AbstractData, public Request
{
public:
WebSocket();
WebSocket(const Package& package);
bool isValid() const override;
// DBObject interface
DbAddress address() const;
void setAddress(const DbAddress &address);
protected:
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
private:
DbAddress _address;
};
}
#endif // WEBSOCKET_H

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 "websocketsubscriptions.h"
#include <QDataStream>
@ -5,7 +12,7 @@
namespace NP {
WebSocketSubscriptions::WebSocketSubscriptions()
{
INIT_COMMAND
}
@ -18,21 +25,21 @@ WebSocketSubscriptions::WebSocketSubscriptions(const NP::Package &package):
QDataStream &WebSocketSubscriptions::fromStream(QDataStream &stream) {
AbstractData::fromStream(stream);
return stream >> _addresses;
}
QDataStream &WebSocketSubscriptions::toStream(QDataStream &stream) const {
AbstractData::toStream(stream);
return stream << _addresses;
}
QSet<DbAddress> WebSocketSubscriptions::addresses() const
{
QSet<DbAddress> WebSocketSubscriptions::addresses() const {
return _addresses;
}
void WebSocketSubscriptions::setAddresses(const QSet<DbAddress> &addresses)
{
void WebSocketSubscriptions::setAddresses(const QSet<DbAddress> &addresses) {
_addresses = addresses;
}

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 WEBSOCKETSUBSCRIPTIONS_H
#define WEBSOCKETSUBSCRIPTIONS_H
@ -9,6 +16,9 @@
namespace NP {
/**
* @brief The WebSocketSubscriptions class
*/
class NETWORKPROTOCOLSHARED_EXPORT WebSocketSubscriptions: public AbstractData
{
public:

View File

@ -0,0 +1,72 @@
#include "dbaddress.h"
#include "permisiondata.h"
#include <quasarapp.h>
#include <QDataStream>
namespace NP {
bool operator ==(const PermisionData &left, const PermisionData &right) {
return left._id == right._id && left._address == right._address;
}
PermisionData::PermisionData(const BaseId &subject, const DbAddress &objcet) {
setId(subject);
setAddress(objcet);
}
unsigned int PermisionData::hash() const {
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << _id;
stream << _address;
return qHash(data);
}
const BaseId &PermisionData::id() const {
return _id;
}
const QString &PermisionData::table() const {
return _address.table();
}
bool PermisionData::isValid() const {
return address().isValid() && _id.isValid();
}
bool PermisionData::equal(const AbstractKey *other) const {
auto otherObject = dynamic_cast<const PermisionData*>(other);
if (!otherObject)
return false;
return _address == otherObject->_address && _id == otherObject->_id;
}
DbAddress PermisionData::address() const {
return _address;
}
void PermisionData::setAddress(const DbAddress &address) {
_address = address;
}
QDataStream &PermisionData::fromStream(QDataStream &stream) {
stream >> _id;
stream >> _address;
return stream;
}
QDataStream &PermisionData::toStream(QDataStream &stream) const {
stream << _id;
stream << _address;
return stream;
}
void PermisionData::setId(const BaseId &Id) {
_id = Id;
}
}

View File

@ -0,0 +1,57 @@
#ifndef PERMISIONDATA_H
#define PERMISIONDATA_H
#include <QString>
#include <abstractkey.h>
#include "dbaddress.h"
namespace NP {
/**
* @brief The PermisionData class- this class provide unique key for permison of subject (id) to object (address).
*/
class NETWORKPROTOCOLSHARED_EXPORT PermisionData: public AbstractKey, public StreamBase {
public:
PermisionData() = default;
PermisionData(const BaseId& subject, const DbAddress& objcet);
friend bool operator == (const PermisionData& left, const PermisionData& right);
/**
* @brief qHash - calc unique key of PermisionData
* @param userPermision
* @return unique key
*/
unsigned int hash() const override;
const BaseId & id() const override;
const QString &table() const override;
bool isValid() const override;
bool equal(const AbstractKey *other) const override;
void setId(const BaseId &Id);
DbAddress address() const;
void setAddress(const DbAddress &address);
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
private:
/// id of user of node
BaseId _id;
/// table of target object (second part of key)
DbAddress _address;
};
}
#endif // PERMISIONDATA_H

View File

@ -0,0 +1,17 @@
#ifndef PERMISIONS_H
#define PERMISIONS_H
namespace NP {
/**
* @brief The Permission enum
* permision to data in database
*/
enum class Permission: unsigned char {
NoPermission = 0x00,
Read = 0x01,
Update = 0x02,
Write = 0x03,
};
}
#endif // PERMISIONS_H

View File

@ -0,0 +1,255 @@
/*
* Copyright (C) 2018-2020 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 "sqldbcache.h"
#include "quasarapp.h"
#include "sqldbwriter.h"
#include "dbaddresskey.h"
#include "permisiondata.h"
#include <dbobject.h>
#include <asyncsqldbwriter.h>
#include <QDateTime>
#include <QtConcurrent/QtConcurrent>
namespace NP {
void SqlDBCache::globalUpdateDataBasePrivate(qint64 currentTime) {
QMutexLocker lock(&_saveLaterMutex);
for (uint it : _needToSaveCache) {
auto async = dynamic_cast<AsyncSqlDbWriter*>(_writer);
if (_writer && _writer->isValid()) {
auto obj = getFromCache(it);
if (!obj || !obj->isValid()) {
deleteFromCache(obj);
QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when"
" db object is not valid! key=" + DESCRIPTION_KEY(it) +
" " + obj->toString(),
QuasarAppUtils::VerboseLvl::Error);
continue;
}
bool saveResult = false;
if (async)
saveResult = async->saveObjectWithWait(obj);
else
saveResult = _writer->saveObject(obj);
if (!saveResult ) {
QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when"
" work globalUpdateDataRelease!!! key=" + DESCRIPTION_KEY(it) +
" " + obj->toString(),
QuasarAppUtils::VerboseLvl::Error);
}
} else {
QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when"
" db writer is npt inited! ",
QuasarAppUtils::VerboseLvl::Error);
return;
}
}
_needToSaveCache.clear();
lastUpdateTime = currentTime;
}
void SqlDBCache::globalUpdateDataBase(SqlDBCasheWriteMode mode) {
qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
if (currentTime - lastUpdateTime > updateInterval ||
static_cast<bool>(mode & SqlDBCasheWriteMode::Force)) {
if (static_cast<bool>(mode & SqlDBCasheWriteMode::On_New_Thread)) {
QtConcurrent::run([currentTime, this](){
globalUpdateDataBasePrivate(currentTime);
});
} else {
globalUpdateDataBasePrivate(currentTime);
}
}
}
SqlDBCache::SqlDBCache(qint64 updateInterval) {
lastUpdateTime = QDateTime::currentMSecsSinceEpoch();
this->updateInterval = updateInterval;
}
SqlDBCache::~SqlDBCache() {
globalUpdateDataBase(SqlDBCasheWriteMode::Force);
}
SqlDBWriter *SqlDBCache::writer() const {
return _writer;
}
void SqlDBCache::setWriter(SqlDBWriter *writer) {
_writer = writer;
}
bool SqlDBCache::getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) {
DBObject* obj = getFromCache(templateObject.dbKey());
if(obj) {
result.push_back(obj);
return true;
}
if (_writer && _writer->isValid()) {
if (!_writer->getAllObjects(templateObject, result)) {
return false;
}
for (auto object: result) {
if (object->isCached() && !saveToCache(object)) {
QuasarAppUtils::Params::log("Selected object from database can not be saved into database cache. " +
object->toString(),
QuasarAppUtils::Warning);
}
}
return true;
}
return false;
}
bool SqlDBCache::saveObject(const DBObject *saveObject) {
if (!saveObject || !saveObject->isValid()) {
return false;
}
saveToCache(saveObject);
if (getMode() == SqlDBCasheWriteMode::Force) {
if (_writer && _writer->isValid()) {
if (!_writer->saveObject(saveObject)) {
return false;
}
return true;
}
} else {
_needToSaveCache.insert(saveObject->dbKey());
globalUpdateDataBase(_mode);
}
return true;
}
bool SqlDBCache::deleteObject(const DBObject *delObj) {
if (!delObj)
return false;
deleteFromCache(delObj);
if (_writer && _writer->isValid()) {
return _writer->deleteObject(delObj);
}
return false;
}
bool SqlDBCache::init(const QString &initDbParams) {
if (!_writer) {
return false;
}
return _writer->initDb(initDbParams);
}
bool SqlDBCache::init(const QVariantMap &params) {
if (!_writer) {
return false;
}
return _writer->initDb(params);
}
void SqlDBCache::deleteFromCache(const DBObject *delObj) {
if (!delObj)
return;
_cacheMutex.lock();
_cache.remove(delObj->dbKey());
_cacheMutex.unlock();
}
bool SqlDBCache::saveToCache(const DBObject *obj) {
if (!obj)
return false;
QMutexLocker lock(&_cacheMutex);
auto existsObject = _cache.value(obj->dbKey(), nullptr);
if (!existsObject) {
_cache[obj->dbKey()] = obj->cloneRaw();
} else if (existsObject->cmd() != obj->cmd()) {
delete existsObject;
_cache[obj->dbKey()] = obj->cloneRaw();
} else {
if (!existsObject->copyFrom(obj)) {
return false;
}
}
emit sigItemChanged(obj);
return true;
}
DBObject* SqlDBCache::getFromCache(uint objKey) {
QMutexLocker locker(&_cacheMutex);
return _cache.value(objKey, nullptr);
}
SqlDBCasheWriteMode SqlDBCache::getMode() const {
return _mode;
}
void SqlDBCache::setMode(const SqlDBCasheWriteMode &mode) {
_mode = mode;
}
qint64 SqlDBCache::getUpdateInterval() const {
return updateInterval;
}
void SqlDBCache::setUpdateInterval(const qint64 &value) {
updateInterval = value;
}
}

View File

@ -1,19 +1,29 @@
/*
* Copyright (C) 2018-2020 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 SQLDBCASHE_H
#define SQLDBCASHE_H
#include "dbcachekey.h"
#include "iobjectprovider.h"
#include <QMap>
#include <QHash>
#include <QSet>
#include <QVariantMap>
#include <networkprotocol.h>
#include <QMutex>
#include "config.h"
#include "basedefines.h"
namespace NP {
class SqlDBWriter;
class DBObject;
class DbAddress;
enum class SqlDBCasheWriteMode: int {
Default = 0x0,
@ -37,19 +47,18 @@ public:
* @brief writer
* @return weak pointer to writer
*/
WP<SqlDBWriter> writer() const;
SqlDBWriter* writer() const;
/**
* @brief setWriter
* @param writer
*/
void setWriter(const WP<SqlDBWriter> &writer);
void setWriter(SqlDBWriter* writer);
bool getObject(SP<DBObject> &obj) override;
SP<DBObject> &getObjectFromCache(const QString& table, int id);
bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) override;
bool saveObject(const WP<AbstractData> &saveObject) override;
bool deleteObject(const WP<AbstractData>& delObj) override;
bool saveObject(const DBObject* saveObject) override;
bool deleteObject(const DBObject* delObj) override;
/**
* @brief getUpdateInterval of SqlDBCasheWriteMode::Default mode
@ -83,14 +92,20 @@ protected:
* @param id in table of object
* @return true if all good
*/
virtual void deleteFromCache(const QString &table, int id);
virtual void deleteFromCache(const DBObject *delObj);
/**
* @brief saveToCache
* @param obj
*/
virtual void saveToCache(const WP<AbstractData> &obj);
virtual bool saveToCache(const DBObject *obj);
/**
* @brief getFromCache - get database objcet from cache.
* @param objKey
* @return object from cache. if object with objKey not exits return nullptr
*/
virtual DBObject* getFromCache(uint objKey);
/**
* @brief getMode
@ -104,24 +119,35 @@ protected:
*/
void setMode(const SqlDBCasheWriteMode &mode);
QMutex _saveLaterMutex;
/**
* @brief globalUpdateDataBasePrivate
* @param currentTime
*/
virtual void globalUpdateDataBasePrivate(qint64 currentTime);
/**
* @brief globalUpdateDataBase
* @param mode
*/
virtual void globalUpdateDataBase(SqlDBCasheWriteMode mode = SqlDBCasheWriteMode::Default);
SqlDBWriter* _writer = nullptr;
private:
qint64 lastUpdateTime = 0;
qint64 updateInterval = DEFAULT_UPDATE_INTERVAL;
QMutex _saveLaterMutex;
QMutex _cacheMutex;
SqlDBCasheWriteMode _mode;
SP<SqlDBWriter> _writer = nullptr;
QHash<uint, DBObject*> _cache;
QSet<uint> _needToSaveCache;
QHash<QString, QHash <int, SP<DBObject>>> _cache;
QHash<QString, QList<int>> _needToSaveCache;
virtual void globalUpdateDataBasePrivate(qint64 currentTime);
virtual void globalUpdateDataBase(SqlDBCasheWriteMode mode = SqlDBCasheWriteMode::Default);
signals:
void sigItemChanged(const WP<AbstractData> &obj);
void sigItemChanged(const DBObject *obj);
};

View File

@ -1,5 +1,10 @@
#include "dbobjectsfactory.h"
#include "dbtablebase.h"
/*
* Copyright (C) 2018-2020 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 "sqldbwriter.h"
#include <QRegularExpression>
@ -8,12 +13,13 @@
#include <QDebug>
#include <QSqlError>
#include <quasarapp.h>
#include <networkprotocol.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QHash>
#include <dbobject.h>
#include <QSqlRecord>
#include <QStandardPaths>
#include <QCoreApplication>
namespace NP {
@ -115,7 +121,6 @@ QVariantMap SqlDBWriter::defaultInitPararm() const {
QVariantMap params;
params["DBDriver"] = "QSQLITE";
params["DBFile"] = DEFAULT_DB_PATH;
return params;
}
@ -191,45 +196,139 @@ bool SqlDBWriter::isValid() const {
return db.isValid() && db.isOpen() && initSuccessful;
}
bool SqlDBWriter::getObject(SP<DBObject>& obj) {
return selectQuery(obj);
bool SqlDBWriter::getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) {
return selectQuery(templateObject, result);
}
bool SqlDBWriter::saveObject(const WP<AbstractData> &saveObject) {
return saveQuery(saveObject);
bool SqlDBWriter::saveObject(const DBObject* ptr) {
return saveQuery(ptr);
}
bool SqlDBWriter::deleteObject(const WP<AbstractData> &deleteObject) {
return deleteQuery(deleteObject);
bool SqlDBWriter::deleteObject(const DBObject* ptr) {
return deleteQuery(ptr);
}
QString SqlDBWriter::databaseLocation() const {
return db.databaseName();
}
SqlDBWriter::~SqlDBWriter() {
db.close();
}
bool SqlDBWriter::saveQuery(const WP<AbstractData>& ptr) const {
bool SqlDBWriter::saveQuery(const DBObject* ptr) const {
if (!ptr)
return false;
QSqlQuery q(db);
auto obj = ptr.toStrongRef().dynamicCast<DBObject>();
if (obj.isNull())
auto prepare = [ptr](QSqlQuery&q) {
return ptr->prepareSaveQuery(q);
};
auto cb = [](){return true;};
return workWithQuery(q, prepare, cb);
}
bool SqlDBWriter::selectQuery(const DBObject& requestObject, QList<const DBObject *> &result) {
QSqlQuery q(db);
auto prepare = [&requestObject](QSqlQuery&q) {
return requestObject.prepareSelectQuery(q);
};
auto cb = [&q, &requestObject, &result]() -> bool {
if (requestObject.isBundle()) {
auto newObject = requestObject.factory();
if (!newObject)
return false;
while (q.next()) {
if (!newObject->fromSqlRecord(q.record())) {
QuasarAppUtils::Params::log("Init sql object error.",
QuasarAppUtils::Error);
return false;
}
}
result.push_back(newObject);
} else {
while (q.next()) {
auto newObject = requestObject.factory();
if (!newObject)
return false;
if (!newObject->fromSqlRecord(q.record())) {
QuasarAppUtils::Params::log("Init sql object error.",
QuasarAppUtils::Error);
return false;
}
result.push_back(newObject);
}
}
return result.size();
};
return workWithQuery(q, prepare, cb);
}
bool SqlDBWriter::deleteQuery(const DBObject *deleteObject) const {
if (!deleteObject)
return false;
return obj->save(q);
QSqlQuery q(db);
auto prepare = [deleteObject](QSqlQuery&q) {
return deleteObject->prepareRemoveQuery(q);
};
auto cb = []() -> bool {
return true;
};
return workWithQuery(q, prepare, cb);
}
bool SqlDBWriter::selectQuery(const SP<DBObject>& obj) {
if (obj.isNull())
bool SqlDBWriter::workWithQuery(QSqlQuery &q,
const std::function< PrepareResult (QSqlQuery &)> &prepareFunc,
const std::function<bool ()> &cb) const {
switch (prepareFunc(q)) {
case PrepareResult::Success: {
if (!q.exec()) {
QuasarAppUtils::Params::log("exec sql error: " + q.lastError().text(),
QuasarAppUtils::Error);
return false;
}
return cb();
}
case PrepareResult::Disabled: {
QuasarAppUtils::Params::log("call disabled operator! ",
QuasarAppUtils::Warning);
return true;
}
case PrepareResult::Fail: {
QuasarAppUtils::Params::log("prepare sql error: " + q.lastError().text(),
QuasarAppUtils::Error);
return false;
}
QSqlQuery query(db);
return obj->select(query);
}
}
bool SqlDBWriter::deleteQuery(const WP<AbstractData> &deleteObject) const {
QSqlQuery query(db);
auto ref = deleteObject.toStrongRef().dynamicCast<DBObject>();
return false;
return ref->remove(query);
}
}

View File

@ -1,3 +1,10 @@
/*
* Copyright (C) 2018-2020 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 SQLDBWRITER_H
#define SQLDBWRITER_H
@ -5,32 +12,74 @@
#include <QSqlDatabase>
#include <QDir>
#include <QSqlQuery>
#include "networkprotocol_global.h"
#include "heart_global.h"
#include "config.h"
#include "dbtablebase.h"
#include "iobjectprovider.h"
#include <QVariant>
#include <QCoreApplication>
#include <dbobject.h>
class QSqlQuery;
class QSqlDatabase;
class QSqlQuery;
class PlayerDBData;
namespace NP {
class DBObject;
class AbstractData;
/**
* @brief The SqlDBWriter class
*/
class NETWORKPROTOCOLSHARED_EXPORT SqlDBWriter : public iObjectProvider
{
private:
public:
SqlDBWriter();
bool exec(QSqlQuery *sq, const QString &sqlFile);
/**
* @brief initDb
* @param path
* @return
*/
virtual bool initDb(const QString &initDbParams = DEFAULT_DB_PATH);
bool initSuccessful = false;
QVariantMap _config;
/**
* @brief initDb
* @param path
* @return
*/
virtual bool initDb(const QVariantMap &params);
/**
* @brief isValid
* @return
*/
virtual bool isValid() const;
/**
* @brief getAllObjects - executable select method of objects and return list of all selected objects
* @param obj - template object with select request.
* @param result - return value, list of selected objects.
* @return true if objects have in db else false.
*/
bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) override;
/**
* @brief saveObject
* @return
*/
bool saveObject(const NP::DBObject *ptr) override;
/**
* @brief deleteObject
* @return
*/
bool deleteObject(const NP::DBObject *ptr) override;
/**
* @brief databaseLocation - return location of database.
* if it is sqllite then return path to db file else return database name.
* @return path or name of database.
*/
QString databaseLocation() const;
virtual ~SqlDBWriter() override;
protected:
@ -73,12 +122,13 @@ protected:
virtual QVariantMap defaultInitPararm() const;
QSqlDatabase db;
QHash<QString, DbTableBase> _dbStruct;
// 0 - table name
// 1 - headers of update values
// 2 - update values
virtual bool saveQuery(const WP<AbstractData> &ptr) const;
/**
* @brief saveQuery - exec save query of object
* @param ptr
* @return true if function finished seccussful
*/
virtual bool saveQuery(const NP::DBObject *ptr) const;
/**
* @brief selectQuery generate select query to database from parameters
@ -88,56 +138,30 @@ protected:
* @param val - compare value
* @return true if all goodelse false
*/
virtual bool selectQuery(const SP<DBObject> &obj);
virtual bool selectQuery(const DBObject &requestObject, QList<const DBObject *> &result);
virtual bool deleteQuery(const WP<AbstractData> &deleteObject) const;
virtual bool deleteQuery(const NP::DBObject *deleteObject) const;
public:
SqlDBWriter();
private:
/**
* @brief initDb
* @param path
* @return
* @brief workWithQuery - this base function for all prepareQuery functions.
* steps work : call prepareFunc, call exec , call cb.
* @param q - query object with a request
* @param prepareFunc - function with pripare data for query
* @param cb - call after success exec and prepare steps
* @return true if all steps finished successful
*/
virtual bool initDb(const QString &initDbParams = DEFAULT_DB_PATH);
bool workWithQuery(QSqlQuery &q,
const std::function< PrepareResult (QSqlQuery &)> &prepareFunc,
const std::function<bool()>& cb) const;
/**
* @brief initDb
* @param path
* @return
*/
virtual bool initDb(const QVariantMap &params);
bool exec(QSqlQuery *sq, const QString &sqlFile);
/**
* @brief isValid
* @return
*/
virtual bool isValid() const;
bool initSuccessful = false;
QVariantMap _config;
/**
* @brief getObject
* @return
*/
bool getObject(SP<DBObject> &obj) override;
/**
* @brief saveObject
* @return
*/
bool saveObject(const WP<AbstractData> &saveObject) override;
/**
* @brief deleteObject
* @return
*/
bool deleteObject(const WP<AbstractData> &deleteObject) override;
virtual ~SqlDBWriter() override;
QHash<QString, SP<DbTableBase> > getDbStruct() const;
void setDbStruct(const QHash<QString, SP<DbTableBase> > &dbStruct);
};
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2018-2020 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 "databasenode.h"
#include "abstractnodeinfo.h"
#include "websocketcontroller.h"
#include <quasarapp.h>
#include <permission.h>
namespace NP {
WebSocketController::WebSocketController(DataBaseNode *node) {
_node = node;
assert(_node);
}
bool WebSocketController::subscribe(const BaseId& subscriber,
const DbAddress &item) {
_subscribsMutex.lock();
_subscribs[item].insert(subscriber);
_subscribsMutex.unlock();
_itemsMutex.lock();
_items[subscriber].insert(item);
_itemsMutex.unlock();
return true;
}
void WebSocketController::unsubscribe(const BaseId &subscriber,
const DbAddress& item) {
_subscribsMutex.lock();
_subscribs[item].remove(subscriber);
_subscribsMutex.unlock();
_itemsMutex.lock();
_items[subscriber].remove(item);
_itemsMutex.unlock();
}
const QSet<DbAddress> &WebSocketController::list(const BaseId &subscriber) {
QMutexLocker locker(&_itemsMutex);
return _items[subscriber];
}
void WebSocketController::handleItemChanged(const DBObject *item) {
auto obj = dynamic_cast<const DBObject*>(item);
if (obj)
return;
QMutexLocker locker(&_subscribsMutex);
foreachSubscribers(item, _subscribs.value(obj->dbAddress()));
}
void WebSocketController::foreachSubscribers(const DBObject *item,
const QSet<BaseId> &subscribersList) {
for (const auto &subscriber : subscribersList) {
bool fAllowed = _node->checkPermission(subscriber, item->dbAddress(), Permission::Read) ==
DBOperationResult::Allowed;
if (fAllowed && !_node->sendData(item, subscriber)) {
QuasarAppUtils::Params::log("Send update failed for " + subscriber.toBase64(),
QuasarAppUtils::Warning);
}
if (!fAllowed) {
QuasarAppUtils::Params::log(QString("Internal Error. Member:%0 not have permission to object %1").
arg(QString(subscriber.toBase64())).arg(item->toString()),
QuasarAppUtils::Error);
}
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2018-2020 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 WEBSOCKETCONTROLLER_H
#define WEBSOCKETCONTROLLER_H
#include <QHash>
#include <QSharedPointer>
#include <dbobject.h>
#include <baseid.h>
#include <QMutex>
namespace NP {
class AbstractNodeInfo;
class DataBaseNode;
/**
* @brief The WebSocketController class - manage subscribe
*/
class NETWORKPROTOCOLSHARED_EXPORT WebSocketController : public QObject
{
Q_OBJECT
public:
WebSocketController(DataBaseNode *node);
bool subscribe(const BaseId &subscriber,
const DbAddress &item);
void unsubscribe(const BaseId &subscriber,
const DbAddress &item);
const QSet<DbAddress> &list(const BaseId& subscriber);
public slots:
void handleItemChanged(const DBObject *item);
private:
void foreachSubscribers(const DBObject *item,
const QSet<BaseId> &subscribersList);
/// subscribers it is nodes or clients
QHash<DbAddress, QSet<BaseId>> _subscribs;
QHash<BaseId, QSet<DbAddress>> _items;
QMutex _subscribsMutex;
QMutex _itemsMutex;
DataBaseNode *_node = nullptr;
};
}
#endif // WEBSOCKETCONTROLLER_H

View File

@ -0,0 +1,11 @@
#include "consensus.h"
namespace NP {
const QStringList Consensus::Nodes = {
"QuasarApp.ddns.net"
};
const short Consensus::networkPort = 8211;
}

View File

@ -0,0 +1,26 @@
#ifndef CONSENSUS_H
#define CONSENSUS_H
#include "heart_global.h"
#include <QStringList>
namespace NP {
/**
* @brief The Consensus namespace - a bundle of general rules constants for behavior of nodes network.
*/
namespace Consensus {
/**
* @brief Nodes - list of main nodes of network
*/
extern const QStringList Nodes;
/**
* @brief networkPort - sync network port
*/
extern const short networkPort;
};
}
#endif // CONSENSUS_Hs

View File

@ -0,0 +1,492 @@
/*
* Copyright (C) 2018-2020 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 "accesstoken.h"
#include "networknode.h"
#include "basenodeinfo.h"
#include "sqldbcache.h"
#include "sqldbwriter.h"
#include "websocketcontroller.h"
#include "badnoderequest.h"
#include "sign.h"
#include "asyncsqldbwriter.h"
#include "router.h"
#include <badrequest.h>
#include <quasarapp.h>
#include <transportdata.h>
#include <websocket.h>
#include <websocketsubscriptions.h>
#include <websocketcontroller.h>
#include <QCoreApplication>
#include <qsecretrsa2048.h>
#include <ping.h>
#include <keystorage.h>
#include <knowaddresses.h>
#include <longping.h>
#include <networkrequest.h>
#include <networkmember.h>
#include <networknodeinfo.h>
#include <nodeobject.h>
#define THIS_NODE "this_node_key"
namespace NP {
NetworkNode::NetworkNode(NP::SslMode mode, QObject *ptr):
DataBaseNode(mode, ptr) {
_nodeKeys = new KeyStorage(new QSecretRSA2048());
_router = new Router();
}
bool NetworkNode::run(const QString &addres, unsigned short port) {
if (!DataBaseNode::run(addres, port)) {
return false;
}
_nodeKeys->initDefaultStorageLocation();
_nodeKeys->start();
return true;
}
bool NetworkNode::run(const QString &addres,
unsigned short port,
const QString &localNodeName) {
if (!DataBaseNode::run(addres, port, localNodeName)) {
return false;
}
_nodeKeys->initDefaultStorageLocation(localNodeName);
_nodeKeys->start();
return true;
}
void NetworkNode::stop() {
DataBaseNode::stop();
}
NetworkNode::~NetworkNode() {
delete _nodeKeys;
delete _router;
}
BaseId NetworkNode::nodeId() const {
auto keys = _nodeKeys->getNextPair(THIS_NODE);
return QCryptographicHash::hash(keys.publicKey(), QCryptographicHash::Sha256);
}
bool NetworkNode::checkSignOfRequest(const AbstractData *request) {
auto object = dynamic_cast<const Sign*>(request);
auto dbObject = dynamic_cast<const SenderData*>(request);
if (!(object && dbObject)) {
return false;
}
auto node = db()->getObject(NetworkMember{dbObject->senderID()});
return _nodeKeys->check(_nodeKeys->concatSign(object->dataForSigned(),
object->sign()), node->authenticationData());
}
NodeObject NetworkNode::thisNode() const {
NodeObject res;
auto keys = _nodeKeys->getNextPair(THIS_NODE);
res.setAuthenticationData(keys.publicKey());
res.setTrust(0);
res.prepareToSend();
return res;
}
QSet<BaseId> NetworkNode::myKnowAddresses() const {
QSet<BaseId> res;
for (const AbstractNodeInfo *i : connections()) {
auto info = dynamic_cast<const BaseNodeInfo*>(i);
if (info && info->selfId().isValid()) {
res += info->selfId();
}
}
return res;
}
bool NetworkNode::welcomeAddress(const HostAddress& ip) {
NodeObject self = thisNode();
if (!sendData(&self, ip)) {
return false;
}
if (connections().size()) {
auto knowAddresses = myKnowAddresses();
if (knowAddresses.size()) {
KnowAddresses addressesData;
addressesData.setKnowAddresses(knowAddresses);
if (!sendData(&addressesData, ip)) {
return false;
}
}
}
return true;
}
void NetworkNode::nodeConnected(const HostAddress &node) {
DataBaseNode::nodeConnected(node);
welcomeAddress(node);
}
void NetworkNode::nodeConfirmend(const HostAddress &node) {
DataBaseNode::nodeConfirmend(node);
auto nodeInfo = dynamic_cast<NetworkNodeInfo*>(getInfoPtr(node));
if (!nodeInfo) {
return;
}
_connectionsMutex.lock();
NetworkNodeInfo* oldNodeInfo = _connections.value(nodeInfo->selfId(), nullptr);
_connectionsMutex.unlock();
if (oldNodeInfo) {
removeNode(node);
return;
}
_connectionsMutex.lock();
_connections.insert(nodeInfo->selfId(), nodeInfo);
_connectionsMutex.unlock();
}
void NetworkNode::nodeDisconnected(const HostAddress &node) {
AbstractNode::nodeDisconnected(node);
auto nodeInfo = dynamic_cast<BaseNodeInfo*>(getInfoPtr(node));
if (!nodeInfo) {
return;
}
_connectionsMutex.lock();
_connections.remove(nodeInfo->selfId());
_connectionsMutex.unlock();
}
void NetworkNode::incomingData(AbstractData *, const BaseId &) {}
QString NetworkNode::keyStorageLocation() const {
return _nodeKeys->storageLocation();
}
ParserResult NetworkNode::parsePackage(const Package &pkg,
const AbstractNodeInfo *sender) {
auto parentResult = AbstractNode::parsePackage(pkg, sender);
if (parentResult != ParserResult::NotProcessed) {
return parentResult;
}
auto baseSender = dynamic_cast<const BaseNodeInfo*>(sender);
if (!baseSender) {
QuasarAppUtils::Params::log("Sender is not basenode info!",
QuasarAppUtils::Error);
return ParserResult::Error;
}
if (H_16<BadNodeRequest>() == pkg.hdr.command) {
BadNodeRequest cmd(pkg);
incomingData(&cmd, baseSender->selfId());
emit requestError(cmd.err());
return ParserResult::Processed;
} else if (H_16<TransportData>() == pkg.hdr.command) {
TransportData cmd(pkg);
return workWithTransportData(&cmd, sender, pkg);
} else if (H_16<NodeObject>() == pkg.hdr.command) {
NodeObject obj(pkg);
if (!obj.isValid()) {
badRequest(sender->networkAddress(), pkg.hdr);
return ParserResult::Error;
}
if (!workWithNodeObjectData(obj, sender)) {
badRequest(obj.senderID(), pkg.hdr);
return ParserResult::Error;
}
return ParserResult::Processed;
} else if (H_16<KnowAddresses>() == pkg.hdr.command) {
KnowAddresses obj(pkg);
if (!obj.isValid()) {
badRequest(sender->networkAddress(), pkg.hdr);
return ParserResult::Error;
}
if (!workWithKnowAddresses(obj, sender)) {
badRequest(sender->networkAddress(), pkg.hdr);
return ParserResult::Error;
}
return ParserResult::Processed;
} else if (H_16<LongPing>() == pkg.hdr.command) {
LongPing cmd(pkg);
if (!cmd.ansver()) {
cmd.setAnsver(true);
sendData(&cmd, cmd.senderID(), &pkg.hdr);
}
incomingData(&cmd, baseSender->selfId());
return ParserResult::Processed;
} else if (H_16<NetworkRequest>() == pkg.hdr.command) {
NetworkRequest cmd(pkg);
if (!cmd.isValid()) {
badRequest(baseSender->selfId(), pkg.hdr);
return ParserResult::Error;
}
workWithNetworkRequest(&cmd, baseSender);
return ParserResult::Processed;
}
return ParserResult::NotProcessed;
}
bool NetworkNode::workWithNodeObjectData(NodeObject &node,
const AbstractNodeInfo* nodeInfo) {
if (!db()) {
return false;
}
auto localObjec = db()->getObject(node);
if (localObjec) {
node.setTrust(std::min(node.trust(), localObjec->trust()));
} else {
node.setTrust(0);
}
if (!db()->saveObject(&node)) {
return false;
};
auto peerNodeInfo = dynamic_cast<NetworkNodeInfo*>(getInfoPtr(nodeInfo->networkAddress()));
if (!peerNodeInfo)
return false;
peerNodeInfo->setSelfId(node.getId());
return true;
}
bool NetworkNode::workWithKnowAddresses(const KnowAddresses &obj,
const AbstractNodeInfo *nodeInfo) {
auto peerNodeInfo = dynamic_cast<NetworkNodeInfo*>(getInfoPtr(nodeInfo->networkAddress()));
if (!peerNodeInfo)
return false;
peerNodeInfo->addKnowAddresses(obj.knowAddresses());
return true;
}
ParserResult NetworkNode::workWithTransportData(AbstractData *transportData,
const AbstractNodeInfo* sender,
const Package& pkg) {
// convert transoprt pakcage
auto cmd = dynamic_cast<TransportData*>(transportData);
if (!cmd)
return ParserResult::Error;
// ignore processed packages
if (_router->isProcessed(cmd->packageId()))
return ParserResult::Processed;
// check distanation
if (cmd->targetAddress() == nodeId()) {
// inversion route and update route to sender
_router->updateRoute(cmd->senderID(),
{cmd->route().rbegin(), cmd->route().rend()});
return parsePackage(cmd->data(), sender);
}
bool fRouteIsValid = false;
// find route if transport command do not have own route.
if (!cmd->isHaveRoute() && _router->contains(cmd->targetAddress())) {
auto route = _router->getRoute(cmd->targetAddress());
auto cmdRute = cmd->route();
cmdRute.push_back(address());
cmdRute.append(route);
cmd->setRoute(cmdRute);
}
// check exists route
if (cmd->isHaveRoute()) {
// if package have a route then remove all nodes from sender to this node from route and update route
if (!sender)
return ParserResult::Error;
cmd->strip(sender->networkAddress(), address());
// send this package to first available node of knownnodes route nodes
auto it = cmd->route().rbegin();
while (it != cmd->route().rend() && !sendData(cmd, *it, &pkg.hdr)) {
it++;
}
fRouteIsValid = it != cmd->route().rend();
} else {
// if command not have a route or route is not completed then add this node to end route
cmd->addNodeToRoute(address());
}
// save route for sender node from this node
auto routeFromSenderToHere = cmd->route();
int index = routeFromSenderToHere.indexOf(address());
if (index < 0) {
QuasarAppUtils::Params::log("own node no findet on route.",
QuasarAppUtils::Error);
}
routeFromSenderToHere.erase(routeFromSenderToHere.begin(), routeFromSenderToHere.begin() + index);
// inversion route and update route to sender
_router->updateRoute(cmd->senderID(),
{routeFromSenderToHere.rbegin(), routeFromSenderToHere.rend()});
// remove invalid route nodes and fix exists route.
if (!fRouteIsValid) {
cmd->setRoute(routeFromSenderToHere);
cmd->completeRoute(false);
// send bodcast if route is invalid
if (!sendData(cmd, cmd->targetAddress(), &pkg.hdr)) {
return ParserResult::Error;
}
}
_router->addProcesedPackage(cmd->packageId());
return ParserResult::Processed;
}
ParserResult NetworkNode::workWithNetworkRequest(AbstractData *networkRequest,
const AbstractNodeInfo *sender) {
// convert transoprt pakcage
auto cmd = dynamic_cast<NetworkRequest*>(networkRequest);
if (!cmd)
return ParserResult::Error;
if (cmd->isComplete()) {
if (cmd->askedNodes().contains(nodeId())) {
return parsePackage(cmd->dataResponce(), sender);
}
return ParserResult::Processed;
}
return parsePackage(cmd->dataRequest(), sender);
}
void NetworkNode::incomingData(AbstractData *pkg, const HostAddress &sender) {
AbstractNode::incomingData(pkg, sender);
}
AbstractNodeInfo *NetworkNode::createNodeInfo(QAbstractSocket *socket,
const HostAddress* clientAddress) const {
return new NetworkNodeInfo(socket, clientAddress);
}
bool NetworkNode::sendData(const AbstractData *resp, const BaseId &nodeId, const Header *req) {
auto nodes = connections();
for (auto it = nodes.begin(); it != nodes.end(); ++it) {
auto info = dynamic_cast<NetworkNodeInfo*>(it.value());
if (info && info->isKnowAddress(nodeId)) {
return sendData(resp, it.key(), req);
}
}
auto brodcast = [this, &nodes, req](const AbstractData *data){
bool result = false;
for (auto it = nodes.begin(); it != nodes.end(); ++it) {
result = result || sendData(data, it.key(), req);
}
return result;
};
if (resp->cmd() != H_16<TransportData>()) {
TransportData data(address());
data.setTargetAddress(nodeId);
if (!data.setData(*resp)) {
return false;
}
data.setRoute(_router->getRoute(nodeId));
data.setSenderID(this->nodeId());
data.prepareToSend();
return brodcast(&data);
}
return brodcast(resp);
}
bool NetworkNode::sendData(AbstractData *resp, const BaseId &nodeId, const Header *req) {
return DataBaseNode::sendData(resp, nodeId, req);
}
bool NetworkNode::sendData(const AbstractData *resp, const HostAddress &nodeId, const Header *req) {
return DataBaseNode::sendData(resp, nodeId, req);
}
bool NetworkNode::sendData(AbstractData *resp, const HostAddress &nodeId, const Header *req) {
return DataBaseNode::sendData(resp, nodeId, req);
}
bool NetworkNode::ping(const BaseId &id) {
LongPing cmd(nodeId());
return sendData(&cmd, id);
}
}

View File

@ -0,0 +1,256 @@
/*
* Copyright (C) 2018-2020 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 NETWORKNODE_H
#define NETWORKNODE_H
#include <databasenode.h>
#include <dbobject.h>
#include <hostaddress.h>
#include <nodeobject.h>
namespace NP {
class NetworkMember;
class MemberPermisionObject;
class KnowAddresses;
class KeyStorage;
class Router;
class NetworkNodeInfo;
/**
* @brief The BaseNode class - base inplementation of nodes. This implementation contains methods for work with database and work with data transopt on network.
* BaseNode - is thread save class
*/
class NETWORKPROTOCOLSHARED_EXPORT NetworkNode : public DataBaseNode
{
Q_OBJECT
public:
/**
* @brief BaseNode
* @param mode
* @param ptr
*/
NetworkNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr);
~NetworkNode() override;
/**
* @brief run server on address an port
* @param addres - If address is empty then serve weel be listen all addreses of all interfaces
* @param port
* @return recomendet befor invoke this method call the intSqlDb.
* If you skeap a call of intSqlDb method then data base inited with default parameters.
*/
bool run(const QString &addres, unsigned short port) override;
/**
* @brief run server on address an port with local name of storage of keys
* @param addres - network address of node
* @param port - port of node
* @return true if node is deployed successful
*/
bool run(const QString &addres, unsigned short port,
const QString &localNodeName) override;
/**
* @brief stop - this implementation stop work database and push to database all cache data.
*/
void stop() override;
/**
* @brief ping - ping node by node id
* @param address
* @return
*/
bool ping( const BaseId& id);
/**
* @brief nodeId
* @return
*/
BaseId nodeId() const;
protected:
/**
* @brief sendDataToId - send data to node or clientby them id.
* @param resp - responce package
* @param nodeId - id of target node
* @param req - header of request
* @return true if data sendet seccussful
*/
bool sendData(const AbstractData *resp, const BaseId &nodeId,
const Header *req = nullptr) override;
bool sendData(AbstractData *resp, const BaseId &nodeId,
const Header *req = nullptr) override;
bool sendData(const AbstractData *resp, const HostAddress &nodeId,
const Header *req = nullptr) override;
bool sendData(AbstractData *resp, const HostAddress &nodeId,
const Header *req = nullptr) override;
/**
* @brief initDefaultDbObjects create default cache and db writer if pointer is null
* @param cache
* @param writer
*/
void initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer);
/**
* @brief parsePackage
* @param pkg
* @param sender
* @return
*/
ParserResult parsePackage(const Package &pkg,
const AbstractNodeInfo* sender) override;
/**
* @brief createNodeInfo - this method create a new node from socket. override this mehod if you want to create a own clasess of nodes.
* @param socket
* @return pointer to new node info
*/
AbstractNodeInfo* createNodeInfo(QAbstractSocket *socket, const HostAddress *clientAddress) const override;
/**
* @brief savePermision - this method save a new changes in to permisions table.
* Befor save new data node can be validate new data with consensus.
* @param permision - data of new permision
* @return true if new cghanges saved successful.
*/
bool savePermision(const NodeObject &node, const MemberPermisionObject& permision);
/**
* @brief checkSignOfRequest
* @param request - package
* @return true if request signed.
*/
virtual bool checkSignOfRequest(const AbstractData *request);
/**
* @brief thisNode
* @return This node object value.
*/
NodeObject thisNode() const;
/**
* @brief myKnowAddresses
* @return set of know addresses
*/
QSet<BaseId> myKnowAddresses() const;
/**
* @brief welcomeAddress - this method send to the ip information about yaster self.
* @param ip - host address of the peer node obeject
* @return true if all iformation sendet succesful
*/
bool welcomeAddress(const HostAddress &ip) override;
/**
* @brief connectionRegistered - this impletation send incomming node welcom message with information about yaster self.
* @param info incominng node info.
*/
void nodeConnected(const HostAddress& node) override;
/**
* @brief nodeConfirmend - this implementation test nodes to double connections
* @param mode
*/
void nodeConfirmend(const HostAddress& sender) override;
/**
* @brief nodeDisconnected - this implementation remove nodes info from connection cache
* @param sender
*/
void nodeDisconnected(const HostAddress& node) override;
/**
* @brief incomingData - this signal invoked when node get command or ansver
* @param pkg - received package
* @param sender - sender of the package
* @note override this method for get a signals.
*/
virtual void incomingData(AbstractData* pkg,
const BaseId& sender);
/**
* @brief keyStorageLocation - return location of storagge of keys.
* @return path to the location of keys storage
*/
QString keyStorageLocation() const;
private:
/**
* @brief workWithNodeObjectData - this method working with received node object data.
* @param node
* @param nodeInfo
* @return true if function finished successful
*/
bool workWithNodeObjectData(NodeObject &node, const AbstractNodeInfo *nodeInfo);
/**
* @brief workWithKnowAddresses
* @param node
* @param nodeInfo
* @return
*/
bool workWithKnowAddresses(const KnowAddresses &obj, const AbstractNodeInfo *nodeInfo);
/**
* @brief workWithTransportData
* @param transportData
* @param sender
* @param pkg
* @return
*/
ParserResult workWithTransportData(AbstractData* transportData, const AbstractNodeInfo *sender, const Package &pkg);
/**
* @brief workWithNetworkRequest
* @param networkRequest
* @param sender
* @param pkg
* @return
*/
ParserResult workWithNetworkRequest(AbstractData* networkRequest, const AbstractNodeInfo *sender);
/**
* @brief optimizeRoute - this method reduces the size of the route by removing unnecessary nodes.
* @param node
* @param rawRoute
* @return
*/
bool optimizeRoute(const BaseId& node,
const HostAddress& currentNodeAddress, const AbstractNodeInfo *sender,
QList<HostAddress> rawRoute);
/**
* @brief incomingData - this implementation move old incoming method into private section
* becouse base node work with BaseID addresses.
* @warning Do not call this implementation on this class,
* use the ncomingData(AbstractData* pkg, const HostAddress& sender) implementation.
*/
void incomingData(AbstractData* pkg,
const HostAddress& sender) override final;
KeyStorage *_nodeKeys = nullptr;
Router *_router = nullptr;
QHash<BaseId, NetworkNodeInfo*> _connections;
mutable QMutex _connectionsMutex;
};
}
#endif // NETWORKNODE_H

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2018-2020 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 "networknodeinfo.h"
#include "dbaddress.h"
#include <QTcpSocket>
#include <hostaddress.h>
namespace NP {
NetworkNodeInfo::NetworkNodeInfo(QAbstractSocket *tcp, const HostAddress* address):
BaseNodeInfo(tcp, address){}
NetworkNodeInfo::~NetworkNodeInfo() = default;
bool NetworkNodeInfo::isValid() const {
return BaseNodeInfo::isValid();
}
bool NetworkNodeInfo::isKnowAddress(const BaseId &address) const {
return _knowAddresses.contains(address);
}
void NetworkNodeInfo::setSelfId(const BaseId &selfId) {
BaseNodeInfo::setSelfId(selfId);
_knowAddresses.insert(_selfId);
}
void NetworkNodeInfo::addKnowAddresses(const QSet<BaseId> &newAddressses) {
_knowAddresses += newAddressses;
}
bool NetworkNodeInfo::confirmData() const {
return BaseNodeInfo::confirmData() && _selfId.isValid();
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2018-2020 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 NETWORKCONNECTIONINFO_H
#define NETWORKCONNECTIONINFO_H
#include "basenodeinfo.h"
#include "accesstoken.h"
#include "baseid.h"
#include "heart_global.h"
#include <QByteArray>
class QAbstractSocket;
namespace NP {
class DbAddress;
/**
* @brief The BaseNodeInfo class contaisn list of nodes id of know this node.
*/
class NETWORKPROTOCOLSHARED_EXPORT NetworkNodeInfo: public BaseNodeInfo {
public:
/**
* @brief NetworkNodeInfo - create node info from the tcp descriptor
* @param tcp - tcp socket dsscriptor
*/
explicit NetworkNodeInfo(QAbstractSocket * tcp = nullptr,
const HostAddress* clientAddress = nullptr);
~NetworkNodeInfo() override;
/**
* @brief isValid
* @return true if node is valid.
*/
bool isValid() const override;
/**
* @brief isKnowAddress
* @param address
* @return
*/
bool isKnowAddress(const BaseId& address) const;
/**
* @brief setSelfId
* @param selfId
*/
void setSelfId(const BaseId &selfId);
/**
* @brief addKnowAddresses
*/
void addKnowAddresses(const QSet<BaseId> &newAddressses);
/**
* @brief confirmData - this implementaton check self id of node.
* @return true if node contains valid self id.
*/
bool confirmData() const override;
protected:
QSet<BaseId> _knowAddresses;
};
}
#endif // NETWORKCONNECTIONINFO_H

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2018-2020 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 "badnoderequest.h"
namespace NP {
BadNodeRequest::BadNodeRequest() {
}
BadNodeRequest::BadNodeRequest(const QString &err):BadRequest(err) {
}
BadNodeRequest::BadNodeRequest(const Package &package): BadRequest(package) {
}
bool BadNodeRequest::isValid() const {
return BadRequest::isValid() && senderID().isValid();
}
bool BadNodeRequest::copyFrom(const AbstractData * other) {
if (!BadRequest::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const BadNodeRequest*>(other);
if (!otherObject)
return false;
setSenderID(otherObject->senderID());
return true;
}
QDataStream &BadNodeRequest::fromStream(QDataStream &stream) {
BadRequest::fromStream(stream);
BaseId senderNode;
stream >> senderNode;
setSenderID(senderNode);
return stream;
}
QDataStream &BadNodeRequest::toStream(QDataStream &stream) const {
BadRequest::toStream(stream);
stream << senderID();
return stream;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2018-2020 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 BADNODEREQUEST_H
#define BADNODEREQUEST_H
#include "senderdata.h"
#include <badrequest.h>
namespace NP {
/**
* @brief The BadNodeRequest class - bad request command for bae node level
*/
class NETWORKPROTOCOLSHARED_EXPORT BadNodeRequest: public BadRequest, public SenderData
{
public:
explicit BadNodeRequest();
explicit BadNodeRequest(const QString & err = "");
explicit BadNodeRequest(const Package& package);
// AbstractData interface
bool isValid() const;
bool copyFrom(const AbstractData *);
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream);
QDataStream &toStream(QDataStream &stream) const;
};
}
#endif // BADNODEREQUEST_H

View File

@ -0,0 +1,57 @@
#include "knowaddresses.h"
#include <QDataStream>
namespace NP {
KnowAddresses::KnowAddresses() {
}
KnowAddresses::KnowAddresses(const Package &pkg) {
fromBytes(pkg.toBytes());
}
bool KnowAddresses::isValid() const {
return AbstractData::isValid();
}
bool KnowAddresses::copyFrom(const AbstractData * other) {
if (!AbstractData::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const KnowAddresses*>(other);
if (!otherObject)
return false;
this->_knowAddresses = otherObject->_knowAddresses;
return true;
}
QDataStream &KnowAddresses::fromStream(QDataStream &stream) {
AbstractData::fromStream(stream);
stream >> _knowAddresses;
return stream;
}
QDataStream &KnowAddresses::toStream(QDataStream &stream) const {
AbstractData::toStream(stream);
stream << _knowAddresses;
return stream;
}
QSet<BaseId> KnowAddresses::knowAddresses() const {
return _knowAddresses;
}
void KnowAddresses::setKnowAddresses(const QSet<BaseId> &knowAddresses) {
_knowAddresses = knowAddresses;
}
}

View File

@ -0,0 +1,36 @@
#ifndef KNOWADDRESSES_H
#define KNOWADDRESSES_H
#include <QSet>
#include <abstractdata.h>
#include <baseid.h>
namespace NP {
/**
* @brief The KnowAddresses class - this class is package for send the list of know addresses of node to other node object.
*/
class NETWORKPROTOCOLSHARED_EXPORT KnowAddresses: public AbstractData
{
public:
KnowAddresses();
KnowAddresses(const Package &pkg);
// AbstractData interface
bool isValid() const override;
bool copyFrom(const AbstractData *) override;
QSet<BaseId> knowAddresses() const;
void setKnowAddresses(const QSet<BaseId> &knowAddresses);
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
private:
QSet<BaseId> _knowAddresses;
};
}
#endif // KNOWADDRESSES_H

View File

@ -0,0 +1,42 @@
#include "longping.h"
namespace NP {
LongPing::LongPing(const BaseId& sender) {
setSenderID(sender);
}
LongPing::LongPing(const Package &from) {
fromBytes(from.data);
}
bool LongPing::isValid() const {
return Ping::isValid() && _senderID.isValid();
}
bool LongPing::copyFrom(const AbstractData * other) {
if (!Ping::copyFrom(other))
return false;
auto otherObject = dynamic_cast<const LongPing*>(other);
if (!otherObject)
return false;
this->_senderID = otherObject->_senderID;
return true;
}
QDataStream &NP::LongPing::fromStream(QDataStream &stream) {
Ping::fromStream(stream);
stream >> _senderID;
return stream;
}
QDataStream &LongPing::toStream(QDataStream &stream) const {
Ping::toStream(stream);
stream << _senderID;
return stream;
}
}

View File

@ -0,0 +1,29 @@
#ifndef LONGPING_H
#define LONGPING_H
#include "ping.h"
#include <senderdata.h>
namespace NP {
/**
* @brief The LongPing class - test class for big network with return addresse
*/
class NETWORKPROTOCOLSHARED_EXPORT LongPing: public Ping, public SenderData
{
public:
LongPing(const BaseId &sender);
LongPing(const Package& from);
// AbstractData interface
bool isValid() const override;
bool copyFrom(const AbstractData *) override;
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
};
}
#endif // LONGPING_H

Some files were not shown because too many files have changed in this diff Show More