diff --git a/chain/wallet/DapChainConvertor.cpp b/chain/wallet/DapChainConvertor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34d7d318247b2cc7635370e5b2b52acc1112930e --- /dev/null +++ b/chain/wallet/DapChainConvertor.cpp @@ -0,0 +1,28 @@ +#include "DapChainConvertor.h" + +DapChainConvertor::DapChainConvertor(QObject *parent) : QObject(parent) +{ + +} + +DapChainConvertor& DapChainConvertor::getInstance() +{ + static DapChainConvertor instance; + return instance; +} + +QString DapChainConvertor::toConvertCurrency(const QString& aMoney) +{ + QString money; + + QStringList major = aMoney.split("."); + if(!major.isEmpty()) money = major.at(0); + else money = aMoney; + + for (int i = money.size() - 3; i >= 1; i -= 3) + money.insert(i, ' '); + + if(major.count() > 1) money.append("." + major.at(1)); + + return money; +} diff --git a/chain/wallet/DapChainConvertor.h b/chain/wallet/DapChainConvertor.h new file mode 100644 index 0000000000000000000000000000000000000000..25dcd861f5ab7b7acb1cc0d8fbe28c47245229f9 --- /dev/null +++ b/chain/wallet/DapChainConvertor.h @@ -0,0 +1,20 @@ +#ifndef DAPCHAINCONVERTOR_H +#define DAPCHAINCONVERTOR_H + +#include <QObject> + +class DapChainConvertor : public QObject +{ + Q_OBJECT + +public: + explicit DapChainConvertor(QObject *parent = nullptr); + /// Get instance of this class + /// @param instance of this class + static DapChainConvertor &getInstance(); + +public slots: + Q_INVOKABLE QString toConvertCurrency(const QString& aMoney); +}; + +#endif // DAPCHAINCONVERTOR_H diff --git a/chain/wallet/DapHistoryType.cpp b/chain/wallet/DapHistoryType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0eec6f6350910fb07a97c14dac4f3a711fb0728a --- /dev/null +++ b/chain/wallet/DapHistoryType.cpp @@ -0,0 +1,47 @@ +#include "DapHistoryType.h" + +const QMap<DapTransactionStatus, QStringList> DapTransactionStatusConvertor::m_statusMap = +{ + {stSent, QStringList() << "send" << "Sent" << "#959CA6"}, + {stReceived, QStringList() << "recv" << "Received" << "#454E63"}, +}; + +QString DapTransactionStatusConvertor::getShortStatus(const DapTransactionStatus aStatus) +{ + if(!m_statusMap.contains(aStatus)) return QString(); + return m_statusMap[aStatus].at(0); +} + +QString DapTransactionStatusConvertor::getLongStatus(const DapTransactionStatus aStatus) +{ + if(!m_statusMap.contains(aStatus)) return QString(); + return m_statusMap[aStatus].at(1); +} + +DapTransactionStatus DapTransactionStatusConvertor::getStatusByShort(const QString& aShortStatus) +{ + for(auto item = m_statusMap.constBegin(); item != m_statusMap.constEnd(); item++) + { + if(item.value().at(0) == aShortStatus) + return item.key(); + } + + return stUnknow; +} + +DapTransactionStatus DapTransactionStatusConvertor::getStatusByLong(const QString& aLongStatus) +{ + for(auto item = m_statusMap.constBegin(); item != m_statusMap.constEnd(); item++) + { + if(item.value().at(1) == aLongStatus) + return item.key(); + } + + return stUnknow; +} + +QColor DapTransactionStatusConvertor::getStatusColor(const DapTransactionStatus aStatus) +{ + if(!m_statusMap.contains(aStatus)) return QColor(); + return QColor(m_statusMap[aStatus].at(2)); +} diff --git a/chain/wallet/DapHistoryType.h b/chain/wallet/DapHistoryType.h new file mode 100644 index 0000000000000000000000000000000000000000..cdd0b02ce524cfd99d9766ce9a3f443a3e7181c1 --- /dev/null +++ b/chain/wallet/DapHistoryType.h @@ -0,0 +1,60 @@ +#ifndef DAPHISTORYTYPE_H +#define DAPHISTORYTYPE_H + +#include <QDateTime> +#include <QImage> +#include <QMap> +#include <QStringList> + +/// Enumeration of transaction status +enum DapTransactionStatus { + stUnknow, + stPending, + stSent, + stReceived, + stError +}; + +/// Structure for transaction item +struct DapTransactionItem { + QDateTime Date; + QImage TokenPic; + DapTransactionStatus Status; + QString TokenName; + QString WalletNumber; + QString Cryptocurrency; + QString Currency; +}; + +/// Class-convertor transaction status +/// @todo This class does not have all statuses +class DapTransactionStatusConvertor +{ + +private: + static const QMap<DapTransactionStatus, QStringList> m_statusMap; + +public: + /// Get short text of status. CLI uses short text of transaction + /// @param enum status of transaction + /// @return short text of status + static QString getShortStatus(const DapTransactionStatus aStatus); + /// Get long text of status. Client uses long text of status + /// @param enum status of transaction + /// @return long text of status + static QString getLongStatus(const DapTransactionStatus aStatus); + /// Get enum status tranaction by short text of status tranasction + /// @param short text of trasaction + /// @return enum status of tranaction + static DapTransactionStatus getStatusByShort(const QString& aShortStatus); + /// Get enum status of tranaction by long text of transaction + /// @param long text of transaction + /// @return enum status of transaction + static DapTransactionStatus getStatusByLong(const QString& aLongStatus); + /// Get color for status of transaction + /// @param enum status of transaction + /// @return color for status of transaction + static QColor getStatusColor(const DapTransactionStatus aStatus); +}; + +#endif // DAPHISTORYTYPE_H diff --git a/chain/wallet/DapLogMessage.cpp b/chain/wallet/DapLogMessage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9899438053115744fe35871653e4fdbcc704e010 --- /dev/null +++ b/chain/wallet/DapLogMessage.cpp @@ -0,0 +1,57 @@ +#include "DapLogMessage.h" + +DapLogMessage::DapLogMessage(const QString &asType, const QString &asTimestamp, const QString &asFile, const QString &asMessage, QObject *parent) : QObject(parent) +{ + m_type = asType; + m_sTimeStamp = asTimestamp; + m_sFile = asFile; + m_sMessage = asMessage; +} + +QString DapLogMessage::getType() const +{ + return m_type; +} + +void DapLogMessage::setType(const QString &asType) +{ + m_type = asType; + + emit typeChanged(m_type); +} + +QString DapLogMessage::getTimeStamp() const +{ + return m_sTimeStamp; +} + +void DapLogMessage::setTimeStamp(const QString &asTimeStamp) +{ + m_sTimeStamp = asTimeStamp; + + emit timeStampChanged(m_sTimeStamp); +} + +QString DapLogMessage::getFile() const +{ + return m_sFile; +} + +void DapLogMessage::setFile(const QString &asFile) +{ + m_sFile = asFile; + + emit fileChanged(m_sFile); +} + +QString DapLogMessage::getMessage() const +{ + return m_sMessage; +} + +void DapLogMessage::setMessage(const QString &asMessage) +{ + m_sMessage = asMessage; + + emit messageChanged(m_sMessage); +} diff --git a/chain/wallet/DapLogMessage.h b/chain/wallet/DapLogMessage.h new file mode 100644 index 0000000000000000000000000000000000000000..ad6d5c3485e43886e75410c162f641ec7c7e4982 --- /dev/null +++ b/chain/wallet/DapLogMessage.h @@ -0,0 +1,89 @@ +#ifndef DAPLOGMESSAGE_H +#define DAPLOGMESSAGE_H + +#include <QObject> + +// TODO: I think it's useless enum +enum Type +{ + Info, + Warning, + Debug, + Error +}; + +class DapLogMessage : public QObject +{ + Q_OBJECT + + /// type of log message + QString m_type; + /// timestamp + QString m_sTimeStamp; + /// name of file where log message was occur + QString m_sFile; + /// text of log message + QString m_sMessage; + +public: + /// standard constructor + explicit DapLogMessage(QObject *parent = nullptr) { Q_UNUSED(parent) } + /// overloaded constructor + /// @param asType Еype of log message + /// @param asTimestamp Timestamp of log message + /// @param asFile Name if file where log message was occur + /// @param asMessage Text of log message + DapLogMessage(const QString &asType, const QString &asTimestamp, + const QString &asFile, const QString &asMessage, QObject *parent = nullptr); + + + Q_PROPERTY(QString type READ getType WRITE setType NOTIFY typeChanged) + Q_PROPERTY(QString timestamp READ getTimeStamp WRITE setTimeStamp NOTIFY timeStampChanged) + Q_PROPERTY(QString file READ getFile WRITE setFile NOTIFY fileChanged) + Q_PROPERTY(QString message READ getMessage WRITE setMessage NOTIFY messageChanged) + + /// Get type + /// @return Type of log message + QString getType() const; + /// Set type to message + /// @param asType Type of log message + void setType(const QString &asType); + + /// Get timestamp + /// @return Timestamp of log message + QString getTimeStamp() const; + /// Set timestamp to log message + /// @param asTimeStamp Timestamp of log message + void setTimeStamp(const QString &asTimeStamp); + + /// Get name of file + /// @return Name of file where log message was occur + QString getFile() const; + /// Set name of file + /// @param asFile Name of file + void setFile(const QString &asFile); + + /// Get text of log message + /// @return Text of log message + QString getMessage() const; + /// Set text to log message + /// @param asMessage Text of log message + void setMessage(const QString &asMessage); + +signals: + /// The signal emitted in case when type of log message was changed + /// @param asType type of log message + void typeChanged(const QString& asType); + /// The signal emitted in case when timestamp of log message was changed + /// @param asTimeStamp Timestamp of log message + void timeStampChanged(const QString& asTimeStamp); + /// The signal emitted in case when file og log message was changed + /// @param asFile Name of log message was changed + void fileChanged(const QString& asFile); + /// The signal emitted in case when message was changed + /// @param asMessage Text of log message + void messageChanged(const QString& asMessage); + +}; + +#endif // DAPLOGMESSAGE_H diff --git a/chain/wallet/DapNodeType.h b/chain/wallet/DapNodeType.h new file mode 100644 index 0000000000000000000000000000000000000000..4dfaa833dc86fbaef0673eb2744b593ff95fb203 --- /dev/null +++ b/chain/wallet/DapNodeType.h @@ -0,0 +1,60 @@ +#ifndef DAPNODETYPE_H +#define DAPNODETYPE_H + +#include <QString> +#include <QStringList> +#include <QDataStream> + +/// Structure for node network data +struct DapNodeData { + quint32 Cell; + QString Ipv4; + QString Alias; + QStringList Link; + bool Status; + bool isCurrentNode; + + DapNodeData() + { + Status = false; + isCurrentNode = false; + } + + DapNodeData& operator = (const DapNodeData& AData) { + Cell = AData.Cell; + Alias = AData.Alias; + Ipv4 = AData.Ipv4; + Link = AData.Link; + Status = AData.Status; + isCurrentNode = AData.isCurrentNode; + return *this; + } + + friend QDataStream& operator<< (QDataStream& out, const DapNodeData& aData) + { + out << aData.Cell + << aData.Ipv4 + << aData.Alias + << aData.Link + << aData.Status + << aData.isCurrentNode; + + return out; + } + + friend QDataStream& operator>> (QDataStream& in, DapNodeData& aData) + { + in >> aData.Cell + >> aData.Ipv4 + >> aData.Alias + >> aData.Link + >> aData.Status + >> aData.isCurrentNode; + return in; + } +}; + +typedef QMap<QString /*Address*/, DapNodeData /*Data*/> DapNodeMap; + + +#endif // DAPNODETYPE_H diff --git a/chain/wallet/DapWallet.cpp b/chain/wallet/DapWallet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..422cf709b58dd66b523a50d09d86202d3b503a02 --- /dev/null +++ b/chain/wallet/DapWallet.cpp @@ -0,0 +1,203 @@ +#include "DapWallet.h" + +DapWallet::DapWallet(QObject * parent) + : QObject(parent) +{ + +} + +DapWallet::DapWallet(const DapWallet &aWallet) + : m_sName(aWallet.m_sName), m_dBalance(aWallet.m_dBalance), m_sIcon(aWallet.m_sIcon), m_sAddress(aWallet.m_sAddress), + m_aNetworks(aWallet.m_aNetworks), m_aAddresses(aWallet.m_aAddresses), m_aTokens(aWallet.m_aTokens) +{ + +} + +DapWallet &DapWallet::operator=(const DapWallet &aWallet) +{ + m_sName = aWallet.m_sName; + m_dBalance = aWallet.m_dBalance; + m_sIcon = aWallet.m_sIcon; + m_sAddress = aWallet.m_sAddress; + m_aNetworks = aWallet.m_aNetworks; + m_aAddresses = aWallet.m_aAddresses; + m_aTokens = aWallet.m_aTokens; + return (*this); +} + +QString DapWallet::getName() const +{ + return m_sName; +} + +void DapWallet::setName(const QString &asName) +{ + m_sName = asName; + + emit nameChanged(m_sName); +} + +double DapWallet::getBalance() const +{ + return m_dBalance; +} + +void DapWallet::setBalance(const double& adBalance) +{ + m_dBalance = adBalance; + + emit balanceChanged(m_dBalance); +} + +QString DapWallet::getIcon() const +{ + return m_sIcon; +} + +void DapWallet::setIcon(const QString &sIcon) +{ + m_sIcon = sIcon; + + emit iconChanged(m_sIcon); +} + +void DapWallet::addNetwork(const QString &asNetwork) +{ + m_aNetworks.append(asNetwork); + + emit networkAdded(asNetwork); + emit networksChanged(m_aNetworks); +} + +QStringList DapWallet::getNetworks() const +{ + return m_aNetworks; +} + +void DapWallet::setAddress(const QString &asNetwork) +{ + m_sAddress = m_aAddresses.find(asNetwork).value(); + + emit addressChanged(m_sAddress); +} + +QString DapWallet::getAddress() const +{ + return m_sAddress; +} + +void DapWallet::addAddress(const QString& aiAddress, const QString &asNetwork) +{ + m_aAddresses.insert(asNetwork, aiAddress); +} + +QString DapWallet::findAddress(const QString &asNetwork) const +{ + if(asNetwork.isNull() || asNetwork.isNull()) + return QString(); + + QString s=m_aAddresses.find(asNetwork).value(); + return m_aAddresses.find(asNetwork) != m_aAddresses.end() ? m_aAddresses.find(asNetwork).value() : QString(); +} + +QMap<QString, QString> DapWallet::getAddresses() const +{ + return m_aAddresses; +} + +void DapWallet::addToken(DapWalletToken *asToken) +{ + m_aTokens.append(asToken); + + emit tokenAdded(*asToken); + + QList<QObject*> tokens; + auto begin = m_aTokens.begin(); + auto end = m_aTokens.end(); + for(;begin != end; ++begin) + { + tokens.append(*begin); + } + emit tokensChanged(tokens); +} + +QList<DapWalletToken*> DapWallet::findTokens(const QString &asNetwork) +{ + QList<DapWalletToken*> tokens; + auto begin = m_aTokens.begin(); + auto end = m_aTokens.end(); + for(;begin != end; ++begin) + { + if((*begin)->getNetwork() == asNetwork) + { + tokens.append(*begin); + } + } + return tokens; +} + +QList<QObject *> DapWallet::getTokens() const +{ + QList<QObject*> tokens; + auto begin = m_aTokens.begin(); + auto end = m_aTokens.end(); + for(;begin != end; ++begin) + { + tokens.append(*begin); + } + return tokens; +} + +DapWallet DapWallet::fromVariant(const QVariant &aWallet) +{ + DapWallet wallet; + QByteArray data = QByteArray::fromStdString(aWallet.toString().toStdString()); + QDataStream in(&data, QIODevice::ReadOnly); + in >> wallet; + return wallet; +} + +QDataStream& operator << (QDataStream& aOut, const DapWallet& aWallet) +{ + QList<DapWalletToken> tokens; + for(int x{0}; x < aWallet.m_aTokens.size(); ++x) + { + tokens.append(*aWallet.m_aTokens.at(x)); + } + + aOut << aWallet.m_sName + << aWallet.m_dBalance + << aWallet.m_sIcon + << aWallet.m_sAddress + << aWallet.m_aNetworks + << aWallet.m_aAddresses + << tokens; + + return aOut; +} + +QDataStream& operator >> (QDataStream& aIn, DapWallet& aWallet) +{ + QList<DapWalletToken> tokens; + + aIn >> aWallet.m_sName; + aIn.setFloatingPointPrecision(QDataStream::DoublePrecision); + aIn >> aWallet.m_dBalance + >> aWallet.m_sIcon + >> aWallet.m_sAddress + >> aWallet.m_aNetworks + >> aWallet.m_aAddresses + >> tokens; + + + auto begin = tokens.begin(); + auto end = tokens.end(); + for(;begin != end; ++begin) + aWallet.addToken(new DapWalletToken(*begin)); + return aIn; +} + +bool operator ==(const DapWallet &aWalletFirst, const DapWallet &aWalletSecond) +{ + return aWalletFirst.m_sName == aWalletSecond.m_sName; +} diff --git a/chain/wallet/DapWallet.h b/chain/wallet/DapWallet.h new file mode 100644 index 0000000000000000000000000000000000000000..1cdcf71cb14cd895c911ea3d8c7e76de74d8fd30 --- /dev/null +++ b/chain/wallet/DapWallet.h @@ -0,0 +1,75 @@ +#ifndef DAPWALLET_H +#define DAPWALLET_H + +#include <QObject> +#include <QString> +#include <QList> +#include <QQmlEngine> + +#include "DapWalletToken.h" + +class DapWallet : public QObject +{ + Q_OBJECT + + QString m_sName; + double m_dBalance {0.0}; + QString m_sIcon; + QString m_sAddress = "private"; + QStringList m_aNetworks; + QMap<QString, QString> m_aAddresses; + mutable QList<DapWalletToken*> m_aTokens; + +public: + Q_INVOKABLE explicit DapWallet(QObject * parent = nullptr); + Q_INVOKABLE DapWallet(const DapWallet& aWallet); + Q_INVOKABLE DapWallet& operator=(const DapWallet& aToken); + + + Q_PROPERTY(QString Name MEMBER m_sName READ getName WRITE setName NOTIFY nameChanged) + Q_PROPERTY(double Balance MEMBER m_dBalance READ getBalance WRITE setBalance NOTIFY balanceChanged) + Q_PROPERTY(QString Icon MEMBER m_sIcon READ getIcon WRITE setIcon NOTIFY iconChanged) + Q_PROPERTY(QString Address MEMBER m_sAddress READ getAddress NOTIFY addressChanged) + Q_PROPERTY(QStringList Networks MEMBER m_aNetworks READ getNetworks NOTIFY networksChanged) + Q_PROPERTY(QList<QObject*> Tokens READ getTokens NOTIFY tokensChanged) + + + friend QDataStream& operator << (QDataStream& aOut, const DapWallet& aToken); + friend QDataStream& operator >> (QDataStream& aOut, DapWallet& aToken); + friend bool operator == (const DapWallet &aWalletFirst, const DapWallet &aWalletSecond); + + static DapWallet fromVariant(const QVariant& aWallet); + +signals: + void nameChanged(const QString& asName); + void balanceChanged(const double& adBalance); + void iconChanged(const QString &asIcon); + void addressChanged(const QString& asAddress); + void networkAdded(const QString& asNetwork); + void networksChanged(const QStringList& asNetworks); + void tokensChanged(const QList<QObject*> asTokens); + void tokenAdded(const DapWalletToken& asNetwork); + +public slots: + QString getName() const; + void setName(const QString &asName); + double getBalance() const; + void setBalance(const double& adBalance); + QString getIcon() const; + void setIcon(const QString &sIcon); + void addNetwork(const QString& asNetwork); + QStringList getNetworks() const; + Q_INVOKABLE void setAddress(const QString& asNetwork); + QString getAddress() const; + void addAddress(const QString &aiAddress, const QString& asNetwork); + Q_INVOKABLE QString findAddress(const QString &asNetwork) const; + QMap<QString, QString> getAddresses() const; + void addToken(DapWalletToken *asToken); + Q_INVOKABLE QList<DapWalletToken*> findTokens(const QString& asNetwork); + Q_INVOKABLE QList<QObject*> getTokens() const; +}; + +Q_DECLARE_METATYPE(DapWallet) + + +#endif // DAPWALLET_H diff --git a/chain/wallet/DapWalletHistoryEvent.cpp b/chain/wallet/DapWalletHistoryEvent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e56e150211ebcbe88dd365d2c1dba9c3998029e2 --- /dev/null +++ b/chain/wallet/DapWalletHistoryEvent.cpp @@ -0,0 +1,113 @@ +#include "DapWalletHistoryEvent.h" + +DapWalletHistoryEvent::DapWalletHistoryEvent(QObject *parent) : QObject(parent) +{ + +} + +DapWalletHistoryEvent::DapWalletHistoryEvent(const DapWalletHistoryEvent &aHistoryEvent) + : QObject(aHistoryEvent.parent()),m_sWallet(aHistoryEvent.m_sWallet), m_sName(aHistoryEvent.m_sName), m_sStatus(aHistoryEvent.m_sStatus), + m_dAmount(aHistoryEvent.m_dAmount), m_sDate(aHistoryEvent.m_sDate) +{ + +} + +DapWalletHistoryEvent &DapWalletHistoryEvent::operator=(const DapWalletHistoryEvent &aHistoryEvent) +{ + m_sWallet = aHistoryEvent.m_sWallet; + m_sName = aHistoryEvent.m_sName; + m_sStatus = aHistoryEvent.m_sStatus; + m_dAmount = aHistoryEvent.m_dAmount; + m_sDate = aHistoryEvent.m_sDate; + return (*this); +} + +bool DapWalletHistoryEvent::operator==(const DapWalletHistoryEvent &aHistoryEvent) const +{ + return (m_sWallet == aHistoryEvent.m_sWallet) + && (m_sName == aHistoryEvent.m_sName) + && (m_sStatus == aHistoryEvent.m_sStatus) + && (m_dAmount == aHistoryEvent.m_dAmount) + && (m_sDate == aHistoryEvent.m_sDate); +} + +QString DapWalletHistoryEvent::getWallet() const +{ + return m_sWallet; +} + +void DapWalletHistoryEvent::setWallet(const QString &sWallet) +{ + m_sWallet = sWallet; + + emit walletChanged(m_sWallet); +} + +QString DapWalletHistoryEvent::getName() const +{ + return m_sName; +} + +void DapWalletHistoryEvent::setName(const QString &sName) +{ + m_sName = sName; + + emit nameChanged(m_sName); +} + +double DapWalletHistoryEvent::getAmount() const +{ + return m_dAmount; +} + +void DapWalletHistoryEvent::setAmount(double dAmount) +{ + m_dAmount = dAmount; + + emit amountChanged(m_dAmount); +} + +QString DapWalletHistoryEvent::getStatus() const +{ + return m_sStatus; +} + +void DapWalletHistoryEvent::setStatus(const QString &sStatus) +{ + m_sStatus = sStatus; + + emit statusChanged(m_sStatus); +} + +QString DapWalletHistoryEvent::getDate() const +{ + return m_sDate; +} + +void DapWalletHistoryEvent::setDate(const QString &sDate) +{ + m_sDate = sDate; + + emit dateChanged(m_sDate); +} + +QDataStream& operator << (QDataStream& aOut, const DapWalletHistoryEvent& aHistoryEvent) +{ + aOut << aHistoryEvent.m_sWallet + << aHistoryEvent.m_sName + << aHistoryEvent.m_dAmount + << aHistoryEvent.m_sStatus + << aHistoryEvent.m_sDate; + return aOut; +} + +QDataStream& operator >> (QDataStream& aOut, DapWalletHistoryEvent& aHistoryEvent) +{ + aOut >> aHistoryEvent.m_sWallet + >> aHistoryEvent.m_sName; + aOut.setFloatingPointPrecision(QDataStream::DoublePrecision); + aOut >> aHistoryEvent.m_dAmount; + aOut >> aHistoryEvent.m_sStatus + >> aHistoryEvent.m_sDate; + return aOut; +} diff --git a/chain/wallet/DapWalletHistoryEvent.h b/chain/wallet/DapWalletHistoryEvent.h new file mode 100644 index 0000000000000000000000000000000000000000..5e6c1b45ca9b6e00d669cb7df9a06727e99694ea --- /dev/null +++ b/chain/wallet/DapWalletHistoryEvent.h @@ -0,0 +1,57 @@ +#ifndef DAPWALLETHISTORYEVENT_H +#define DAPWALLETHISTORYEVENT_H + +#include <QObject> +#include <QString> +#include <QDataStream> + +class DapWalletHistoryEvent : public QObject +{ + Q_OBJECT + + QString m_sWallet; + /// Token name. + QString m_sName; + /// Token balance. + QString m_sStatus; + + double m_dAmount {0.0}; + + QString m_sDate; + +public: + explicit DapWalletHistoryEvent(QObject *parent = nullptr); + DapWalletHistoryEvent(const DapWalletHistoryEvent& aHistoryEvent); + DapWalletHistoryEvent& operator=(const DapWalletHistoryEvent& aHistoryEvent); + bool operator==(const DapWalletHistoryEvent& aHistoryEvent) const; + + Q_PROPERTY(QString Wallet MEMBER m_sWallet READ getWallet WRITE setWallet NOTIFY walletChanged) + Q_PROPERTY(QString Name MEMBER m_sName READ getName WRITE setName NOTIFY nameChanged) + Q_PROPERTY(double Amount MEMBER m_dAmount READ getAmount WRITE setAmount NOTIFY amountChanged) + Q_PROPERTY(QString Status MEMBER m_sName READ getStatus WRITE setStatus NOTIFY statusChanged) + Q_PROPERTY(QString Date MEMBER m_dAmount READ getDate WRITE setDate NOTIFY dateChanged) + + friend QDataStream& operator << (QDataStream& aOut, const DapWalletHistoryEvent& aHistoryEvent); + friend QDataStream& operator >> (QDataStream& aOut, DapWalletHistoryEvent& aHistoryEvent); + +signals: + void walletChanged(const QString& asWallet); + void nameChanged(const QString& asName); + void amountChanged(const double& adAmount); + void statusChanged(const QString& asStatus); + void dateChanged(const QString& asDate); + +public slots: + QString getWallet() const; + void setWallet(const QString &sWallet); + QString getName() const; + void setName(const QString &sName); + double getAmount() const; + void setAmount(double dAmount); + QString getStatus() const; + void setStatus(const QString &sStatus); + QString getDate() const; + void setDate(const QString &sDate); +}; + +#endif // DAPWALLETHISTORYEVENT_H diff --git a/chain/wallet/DapWalletToken.cpp b/chain/wallet/DapWalletToken.cpp new file mode 100644 index 0000000000000000000000000000000000000000..beb3c270554869389a8c8e46cc06b91da152741e --- /dev/null +++ b/chain/wallet/DapWalletToken.cpp @@ -0,0 +1,113 @@ +#include "DapWalletToken.h" + +DapWalletToken::DapWalletToken(const QString &asName, QObject *parent) + : QObject(parent), m_sName(asName) +{ + +} + +DapWalletToken::DapWalletToken(const DapWalletToken &aToken) + : QObject(aToken.parent()), m_sName(aToken.m_sName), m_dBalance(aToken.m_dBalance), + m_iEmission(aToken.m_iEmission), m_sNetwork(aToken.m_sNetwork) +{ + +} + +DapWalletToken &DapWalletToken::operator=(const DapWalletToken &aToken) +{ + m_sName = aToken.m_sName; + m_dBalance = aToken.m_dBalance; + m_iEmission = aToken.m_iEmission; + m_sNetwork = aToken.m_sNetwork; + return (*this); +} + +bool DapWalletToken::operator==(const DapWalletToken &aToken) const +{ + return m_sName == aToken.m_sName + && m_dBalance == aToken.m_dBalance + && m_iEmission == aToken.m_iEmission + && m_sNetwork == aToken.m_sNetwork; +} + +QString DapWalletToken::getName() const +{ + return m_sName; +} + +void DapWalletToken::setName(const QString &sName) +{ + m_sName = sName; + + emit nameChanged(m_sName); +} + +double DapWalletToken::getBalance() const +{ + return m_dBalance; +} + +void DapWalletToken::setBalance(double dBalance) +{ + m_dBalance = dBalance; + + emit balanceChanged(m_dBalance); +} + +quint64 DapWalletToken::getEmission() const +{ + return m_iEmission; +} + +void DapWalletToken::setEmission(const quint64 &iEmission) +{ + m_iEmission = iEmission; + + emit emissionChanged(m_iEmission); +} + +QString DapWalletToken::getNetwork() const +{ + return m_sNetwork; +} + +void DapWalletToken::setNetwork(const QString &sNetwork) +{ + m_sNetwork = sNetwork; + + emit networkChanged(m_sNetwork); +} + +QString DapWalletToken::getIcon() const +{ + return m_sIcon; +} + +void DapWalletToken::setIcon(const QString &sIcon) +{ + m_sIcon = sIcon; + + emit iconChanged(m_sIcon); +} + +QDataStream& operator << (QDataStream& aOut, const DapWalletToken& aToken) +{ + aOut << aToken.m_sName + << aToken.m_dBalance + << aToken.m_iEmission + << aToken.m_sNetwork; + return aOut; +} + +QDataStream& operator >> (QDataStream& aOut, DapWalletToken& aToken) +{ + aOut >> aToken.m_sName; + aOut.setFloatingPointPrecision(QDataStream::DoublePrecision); + aOut >> aToken.m_dBalance; + aOut.setFloatingPointPrecision(QDataStream::SinglePrecision); + aOut >> aToken.m_iEmission + >> aToken.m_sNetwork; + return aOut; +} + + diff --git a/chain/wallet/DapWalletToken.h b/chain/wallet/DapWalletToken.h new file mode 100644 index 0000000000000000000000000000000000000000..5de45c4f30422415184db6f5d4c373205c62bd54 --- /dev/null +++ b/chain/wallet/DapWalletToken.h @@ -0,0 +1,61 @@ +#ifndef DAPWALLETTOKEN_H +#define DAPWALLETTOKEN_H + +#include <QObject> +#include <QString> +#include <QDataStream> + +class DapWalletToken : public QObject +{ + Q_OBJECT + + /// Token name. + QString m_sName; + /// Token balance. + double m_dBalance {0.0}; + /// Token emission. + quint64 m_iEmission {0}; + /// Network. + QString m_sNetwork; + /// Icon path. + QString m_sIcon; + +public: + explicit DapWalletToken(const QString& asName = QString(), QObject *parent = nullptr); + DapWalletToken(const DapWalletToken& aToken); + DapWalletToken& operator=(const DapWalletToken& aToken); + bool operator==(const DapWalletToken& aToken) const; + + Q_PROPERTY(QString Name MEMBER m_sName READ getName WRITE setName NOTIFY nameChanged) + Q_PROPERTY(double Balance MEMBER m_dBalance READ getBalance WRITE setBalance NOTIFY balanceChanged) + Q_PROPERTY(quint64 Emission MEMBER m_iEmission READ getEmission WRITE setEmission NOTIFY emissionChanged) + Q_PROPERTY(QString Network MEMBER m_sNetwork READ getNetwork WRITE setNetwork NOTIFY networkChanged) + Q_PROPERTY(QString Icon MEMBER m_sIcon READ getIcon WRITE setIcon NOTIFY iconChanged) + + + friend QDataStream& operator << (QDataStream& aOut, const DapWalletToken& aToken); + friend QDataStream& operator >> (QDataStream& aOut, DapWalletToken& aToken); + +signals: + void nameChanged(const QString & asName); + void balanceChanged(const double & adBalance); + void emissionChanged(const qint64& aiEmission); + void networkChanged(const QString &asNetwork); + void iconChanged(const QString &asIcon); + +public slots: + QString getName() const; + void setName(const QString &sName); + double getBalance() const; + void setBalance(double dBalance); + quint64 getEmission() const; + void setEmission(const quint64 &iEmission); + QString getNetwork() const; + void setNetwork(const QString &sNetwork); + QString getIcon() const; + void setIcon(const QString &sIcon); +}; + +Q_DECLARE_METATYPE(DapWalletToken) + +#endif // DAPWALLETTOKEN_H diff --git a/chain/wallet/README.md b/chain/wallet/README.md new file mode 100644 index 0000000000000000000000000000000000000000..81f98b27cdeabfdda59c92fec76fda9a5a99048b --- /dev/null +++ b/chain/wallet/README.md @@ -0,0 +1,2 @@ +# libdap-qt-chain-wallet + diff --git a/chain/wallet/dapRPCProtocol/DapRPCProtocol.pri b/chain/wallet/dapRPCProtocol/DapRPCProtocol.pri new file mode 100644 index 0000000000000000000000000000000000000000..c6899ffaeda20af18e162318bfcdf8b75c5f6227 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRPCProtocol.pri @@ -0,0 +1,25 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/DapRpcAbstractServer.h \ + $$PWD/DapRpcLocalServer.h \ + $$PWD/DapRpcMessage.h \ + $$PWD/DapRpcService.h \ + $$PWD/DapRpcServiceProvider.h \ + $$PWD/DapRpcServiceReply.h \ + $$PWD/DapRpcServiceRequest.h \ + $$PWD/DapRpcSocket.h \ + $$PWD/DapRpcTCPServer.h + +SOURCES += \ + $$PWD/DapRpcAbstractServer.cpp \ + $$PWD/DapRpcLocalServer.cpp \ + $$PWD/DapRpcMessage.cpp \ + $$PWD/DapRpcService.cpp \ + $$PWD/DapRpcServiceProvider.cpp \ + $$PWD/DapRpcServiceReply.cpp \ + $$PWD/DapRpcServiceRequest.cpp \ + $$PWD/DapRpcSocket.cpp \ + $$PWD/DapRpcTCPServer.cpp + + diff --git a/chain/wallet/dapRPCProtocol/DapRpcAbstractServer.cpp b/chain/wallet/dapRPCProtocol/DapRpcAbstractServer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..025cf8ff069a7344f4d4a82523e73ad5cd0b3953 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcAbstractServer.cpp @@ -0,0 +1,31 @@ +#include "DapRpcAbstractServer.h" + +DapRpcAbstractServer::DapRpcAbstractServer() +{ + +} + +DapRpcAbstractServer::~DapRpcAbstractServer() +{ + +} + +int DapRpcAbstractServer::connectedClientCount() const +{ + return m_clients.size(); +} + +DapRpcServiceReply* DapRpcAbstractServer::notifyConnectedClients(const DapRpcMessage &message) +{ + DapRpcServiceReply * reply {nullptr}; + for (int i = 0; i < m_clients.size(); ++i) + reply = m_clients[i]->sendMessage(message); + return reply; +} + +void DapRpcAbstractServer::notifyConnectedClients(const QString &method, const QJsonArray ¶ms) +{ + DapRpcMessage notification = + DapRpcMessage::createNotification(method, params); + notifyConnectedClients(notification); +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcAbstractServer.h b/chain/wallet/dapRPCProtocol/DapRpcAbstractServer.h new file mode 100644 index 0000000000000000000000000000000000000000..b5d85122f19f8c35d2446fc69a87411581b9a6b6 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcAbstractServer.h @@ -0,0 +1,54 @@ +#ifndef DapRPCABSTRACTSERVER_H +#define DapRPCABSTRACTSERVER_H + +#include <QList> +#include <QHostAddress> + +#include "DapRpcSocket.h" +#include "DapRpcMessage.h" +#include "DapRpcServiceProvider.h" + +/** + * @brief The DapRpcAbstractServer class + * Class of abstract RPC server. Include information about all clients + * Server can send/receive message to/from client by RPC protocol + */ +class DapRpcAbstractServer : public DapRpcServiceProvider +{ +protected: + /// List of clients + QList<DapRpcSocket*> m_clients; + +public: + /// Standard constructor + DapRpcAbstractServer(); + /// Virtual destructor + virtual ~DapRpcAbstractServer(); + /// Connected clients count + /// @return Clients count + virtual int connectedClientCount() const; + /// Tells to server to listen incoming connections on address and port. + /// @param asAddress Address + /// @param aPort Port + /// @return If Server is currently listening then it will return false. + /// Otherwise return true. + virtual bool listen(const QString &asAddress = QString(), quint16 aPort = 0) = 0; +// signals: + /// The signal is emitted when client was connected + virtual void onClientConnected() = 0; + /// The signal is emitted when client was disconnected + virtual void onClientDisconnected() = 0; + +// public slots: + /// Notify connected clients. Send all message + /// @param message Message to client + virtual DapRpcServiceReply *notifyConnectedClients(const DapRpcMessage &message); + /// Notify connected clients. Send all message + /// @param method Method which clients were notified + /// @param params Parameters of message in JSON format + virtual void notifyConnectedClients(const QString &method, const QJsonArray ¶ms); + + +}; + +#endif // DapRPCABSTRACTSERVER_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcLocalServer.cpp b/chain/wallet/dapRPCProtocol/DapRpcLocalServer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63b7e0e1e97f54f627052494260ffc918047093f --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcLocalServer.cpp @@ -0,0 +1,113 @@ +#include "DapRpcLocalServer.h" + +DapRpcLocalServer::DapRpcLocalServer(QObject *apParent) + : QLocalServer(apParent) +{ + this->setSocketOptions(QLocalServer::WorldAccessOption); +} + +DapRpcLocalServer::~DapRpcLocalServer() +{ + foreach (QLocalSocket *socket, m_socketLookup.keys()) { + socket->flush(); + socket->deleteLater(); + } + m_socketLookup.clear(); + + foreach (DapRpcSocket *client, m_clients) + client->deleteLater(); + m_clients.clear(); +} + +bool DapRpcLocalServer::listen(const QString &asAddress, quint16 aPort) +{ + Q_UNUSED(aPort) + + return QLocalServer::listen(asAddress); +} + +DapRpcService *DapRpcLocalServer::addService(DapRpcService *apService) +{ + if (!DapRpcServiceProvider::addService(apService)) + return nullptr; + + connect(apService, SIGNAL(notifyConnectedClients(DapRpcMessage)), + this, SLOT(notifyConnectedClients(DapRpcMessage))); + connect(apService, SIGNAL(notifyConnectedClients(QString,QJsonArray)), + this, SLOT(notifyConnectedClients(QString,QJsonArray))); + return apService; +} + +bool DapRpcLocalServer::removeService(DapRpcService *apService) +{ + if (!DapRpcServiceProvider::removeService(apService)) + return false; + + disconnect(apService, SIGNAL(notifyConnectedClients(DapRpcMessage)), + this, SLOT(notifyConnectedClients(DapRpcMessage))); + disconnect(apService, SIGNAL(notifyConnectedClients(QString,QJsonArray)), + this, SLOT(notifyConnectedClients(QString,QJsonArray))); + return true; +} + +DapRpcService *DapRpcLocalServer::findService(const QString &asServiceName) +{ + return DapRpcServiceProvider::findService(asServiceName); +} + +void DapRpcLocalServer::clientDisconnected() +{ + QLocalSocket *localSocket = static_cast<QLocalSocket*>(sender()); + if (!localSocket) { + qJsonRpcDebug() << "called with invalid socket"; + return; + } + if (m_socketLookup.contains(localSocket)) { + DapRpcSocket *socket = m_socketLookup.take(localSocket); + m_clients.removeAll(socket); + socket->deleteLater(); + } + + localSocket->deleteLater(); + emit onClientDisconnected(); +} + +void DapRpcLocalServer::messageProcessing(const DapRpcMessage &asMessage) +{ + DapRpcSocket *socket = static_cast<DapRpcSocket*>(sender()); + if (!socket) { + qJsonRpcDebug() << "called without service socket"; + return; + } + + processMessage(socket, asMessage); +} + +DapRpcServiceReply *DapRpcLocalServer::notifyConnectedClients(const DapRpcMessage &message) +{ + return DapRpcAbstractServer::notifyConnectedClients(message); +} + +void DapRpcLocalServer::notifyConnectedClients(const QString &method, const QJsonArray ¶ms) +{ + DapRpcAbstractServer::notifyConnectedClients(method, params); +} + +void DapRpcLocalServer::incomingConnection(quintptr aSocketDescriptor) +{ + QLocalSocket *localSocket = new QLocalSocket(this); + if (!localSocket->setSocketDescriptor(aSocketDescriptor)) { + qJsonRpcDebug() << "nextPendingConnection is null"; + localSocket->deleteLater(); + return; + } + + QIODevice *device = qobject_cast<QIODevice*>(localSocket); + DapRpcSocket *socket = new DapRpcSocket(device, this); + connect(socket, SIGNAL(messageReceived(DapRpcMessage)), + this, SLOT(messageProcessing(DapRpcMessage))); + m_clients.append(socket); + connect(localSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + m_socketLookup.insert(localSocket, socket); + emit onClientConnected(); +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcLocalServer.h b/chain/wallet/dapRPCProtocol/DapRpcLocalServer.h new file mode 100644 index 0000000000000000000000000000000000000000..e72bf9225b30a37295b2fd8d7cbe2098f92e98da --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcLocalServer.h @@ -0,0 +1,78 @@ +#ifndef DapRPCLOCALSERVER_H +#define DapRPCLOCALSERVER_H + +#include <QObject> +#include <QLocalSocket> +#include <QLocalServer> + +#include "DapRpcSocket.h" +#include "DapRpcService.h" +#include "DapRpcAbstractServer.h" + +/** + * @brief The DapRpcLocalServer class + * Local RPC server. inheritance from DapRpcAbstractServer + * @see DapRpcAbstractServer + * @see QLocalServer + */ +class DapRpcLocalServer : public QLocalServer, public DapRpcAbstractServer +{ + Q_OBJECT + Q_DISABLE_COPY(DapRpcLocalServer) + + /// Hash map socket lookups. LocalSocket according to RPC socket + QHash<QLocalSocket*, DapRpcSocket*> m_socketLookup; + +protected: + /// Call when new connection is available + /// @param aSocketDescriptor SocketDescriptor is the native socket descriptor for the accepted connection + virtual void incomingConnection(quintptr aSocketDescriptor); + +public: + /// Standard constructor + explicit DapRpcLocalServer(QObject *apParent = nullptr); + /// Virtual overrided descriptor + virtual ~DapRpcLocalServer(); + + /// Tells to server to listen incoming connections on address and port. + /// @param asAddress Address + /// @param aPort Port + /// @return If Server is currently listening then it will return false. + /// Otherwise return true. + virtual bool listen(const QString &asAddress = QString(), quint16 aPort = 0); + /// Add new service + /// @param apService New service + /// @return If service add successfully return true. Otherwise return false + DapRpcService * addService(DapRpcService *apService); + /// Remove service + /// @param apService Service for removing + /// @return If service add successfully return true. Otherwise return false + bool removeService(DapRpcService *apService); + + + DapRpcService* findService(const QString& asServiceName); +signals: + /// The signal is emitted when client was connected + void onClientConnected(); + /// The signal is emitted when client was disconnected + void onClientDisconnected(); + +private slots: + /// Calls when client disconnected + void clientDisconnected(); + /// When receive message from client prepare message by type of message + /// @param asMessage Message + void messageProcessing(const DapRpcMessage &asMessage); + + // DapRpcAbstractServer interface +public slots: + /// Notify connected clients. Send all message + /// @param message Message to client + DapRpcServiceReply * notifyConnectedClients(const DapRpcMessage &message); + /// Notify connected clients. Send all message + /// @param method Method which clients were notified + /// @param params Parameters of message in JSON format + void notifyConnectedClients(const QString &method, const QJsonArray ¶ms); +}; + +#endif // DapRPCLOCALSERVER_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcMessage.cpp b/chain/wallet/dapRPCProtocol/DapRpcMessage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2a835937a4d58cc4614b05cfc73b67a2ad77ad5 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcMessage.cpp @@ -0,0 +1,391 @@ +#include "DapRpcMessage.h" + +class DapRpcMessagePrivate : public QSharedData +{ +public: + DapRpcMessagePrivate(); + ~DapRpcMessagePrivate(); + DapRpcMessagePrivate(const DapRpcMessagePrivate &aDapRpcMessagePrivate); + + void initializeWithObject(const QJsonObject &aMessage); + static DapRpcMessage createBasicRequest(const QString &asMethod, const QJsonArray &aParams); + static DapRpcMessage createBasicRequest(const QString &asMethod, + const QJsonObject &aNamedParameters); + + DapRpcMessage::Type m_type; + QScopedPointer<QJsonObject> m_pObject; + + static int uniqueRequestCounter; +}; + +int DapRpcMessagePrivate::uniqueRequestCounter = 0; + +DapRpcMessagePrivate::DapRpcMessagePrivate() + : m_type(DapRpcMessage::Invalid), + m_pObject(nullptr) +{ +} + +DapRpcMessagePrivate::DapRpcMessagePrivate(const DapRpcMessagePrivate &aDapRpcMessagePrivate) + : QSharedData(aDapRpcMessagePrivate), + m_type(aDapRpcMessagePrivate.m_type), + m_pObject(aDapRpcMessagePrivate.m_pObject ? new QJsonObject(*aDapRpcMessagePrivate.m_pObject) : nullptr) +{ +} + +void DapRpcMessagePrivate::initializeWithObject(const QJsonObject &aMessage) +{ + m_pObject.reset(new QJsonObject(aMessage)); + if (aMessage.contains(QLatin1String("id"))) { + if (aMessage.contains(QLatin1String("result")) || + aMessage.contains(QLatin1String("error"))) { + if (aMessage.contains(QLatin1String("error")) && + !aMessage.value(QLatin1String("error")).isNull()) + m_type = DapRpcMessage::Error; + else + m_type = DapRpcMessage::Response; + } else if (aMessage.contains(QLatin1String("method"))) { + m_type = DapRpcMessage::Request; + } + } else { + if (aMessage.contains(QLatin1String("method"))) + m_type = DapRpcMessage::Notification; + } +} + +DapRpcMessagePrivate::~DapRpcMessagePrivate() +{ +} + +DapRpcMessage::DapRpcMessage() + : d(new DapRpcMessagePrivate) +{ + d->m_pObject.reset(new QJsonObject); +} + +DapRpcMessage::DapRpcMessage(const DapRpcMessage &aDapRPCMessage) + : d(aDapRPCMessage.d) +{ +} + +DapRpcMessage::~DapRpcMessage() +{ +} + +DapRpcMessage &DapRpcMessage::operator=(const DapRpcMessage &aDapRPCMessage) +{ + d = aDapRPCMessage.d; + return *this; +} + +bool DapRpcMessage::operator==(const DapRpcMessage &aDapRpcMessage) const +{ + if (aDapRpcMessage.d == d) + return true; + + if (aDapRpcMessage.type() == type()) { + if (aDapRpcMessage.type() == DapRpcMessage::Error) { + return (aDapRpcMessage.errorCode() == errorCode() && + aDapRpcMessage.errorMessage() == errorMessage() && + aDapRpcMessage.errorData() == errorData()); + } else { + if (aDapRpcMessage.type() == DapRpcMessage::Notification) { + return (aDapRpcMessage.method() == method() && + aDapRpcMessage.params() == params()); + } else { + return (aDapRpcMessage.id() == id() && + aDapRpcMessage.method() == method() && + aDapRpcMessage.params() == params()); + } + } + } + + return false; +} + +DapRpcMessage DapRpcMessage::fromJson(const QByteArray &aData) +{ + DapRpcMessage result; + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(aData, &error); + if (error.error != QJsonParseError::NoError) { + qJsonRpcDebug() << error.errorString(); + return result; + } + + if (!document.isObject()) { + qJsonRpcDebug() << "invalid message: " << aData; + return result; + } + + result.d->initializeWithObject(document.object()); + return result; +} + +DapRpcMessage DapRpcMessage::fromObject(const QJsonObject &aObject) +{ + DapRpcMessage result; + result.d->initializeWithObject(aObject); + return result; +} + +QJsonObject DapRpcMessage::toObject() const +{ + if (d->m_pObject) + return QJsonObject(*d->m_pObject); + return QJsonObject(); +} + +QByteArray DapRpcMessage::toJson() const +{ + if (d->m_pObject) { + QJsonDocument doc(*d->m_pObject); + return doc.toJson(); + } + + return QByteArray(); +} + +bool DapRpcMessage::isValid() const +{ + return d->m_type != DapRpcMessage::Invalid; +} + +DapRpcMessage::Type DapRpcMessage::type() const +{ + return d->m_type; +} + +DapRpcMessage DapRpcMessagePrivate::createBasicRequest(const QString &asMethod, const QJsonArray &aParams) +{ + DapRpcMessage request; + request.d->m_pObject->insert(QLatin1String("jsonrpc"), QLatin1String("2.0")); + request.d->m_pObject->insert(QLatin1String("method"), asMethod); + if (!aParams.isEmpty()) + request.d->m_pObject->insert(QLatin1String("params"), aParams); + return request; +} + +DapRpcMessage DapRpcMessagePrivate::createBasicRequest(const QString &asMethod, + const QJsonObject &aNamedParameters) +{ + DapRpcMessage request; + request.d->m_pObject->insert(QLatin1String("jsonrpc"), QLatin1String("2.0")); + request.d->m_pObject->insert(QLatin1String("method"), asMethod); + if (!aNamedParameters.isEmpty()) + request.d->m_pObject->insert(QLatin1String("params"), aNamedParameters); + return request; +} + +DapRpcMessage DapRpcMessage::createRequest(const QString &asMethod, const QJsonArray &aParams) +{ + DapRpcMessage request = DapRpcMessagePrivate::createBasicRequest(asMethod, aParams); + request.d->m_type = DapRpcMessage::Request; + DapRpcMessagePrivate::uniqueRequestCounter++; + request.d->m_pObject->insert(QLatin1String("id"), DapRpcMessagePrivate::uniqueRequestCounter); + return request; +} + +DapRpcMessage DapRpcMessage::createRequest(const QString &asMethod, const QJsonValue &aParam) +{ + QJsonArray params; + params.append(aParam); + return createRequest(asMethod, params); +} + +DapRpcMessage DapRpcMessage::createRequest(const QString &asMethod, + const QJsonObject &aNamedParameters) +{ + DapRpcMessage request = + DapRpcMessagePrivate::createBasicRequest(asMethod, aNamedParameters); + request.d->m_type = DapRpcMessage::Request; + DapRpcMessagePrivate::uniqueRequestCounter++; + request.d->m_pObject->insert(QLatin1String("id"), DapRpcMessagePrivate::uniqueRequestCounter); + return request; +} + +DapRpcMessage DapRpcMessage::createRequest(const QString& asMethod, const QByteArray& aStream) +{ + DapRpcMessage request = createRequest(asMethod, QJsonValue::fromVariant(aStream)); + return request; +} + +DapRpcMessage DapRpcMessage::createNotification(const QString &asMethod, const QJsonArray &aParams) +{ + DapRpcMessage notification = DapRpcMessagePrivate::createBasicRequest(asMethod, aParams); + notification.d->m_type = DapRpcMessage::Notification; + return notification; +} + +DapRpcMessage DapRpcMessage::createNotification(const QString &asMethod, const QJsonValue &aParam) +{ + QJsonArray params; + params.append(aParam); + return createNotification(asMethod, params); +} + +DapRpcMessage DapRpcMessage::createNotification(const QString &asMethod, + const QJsonObject &aNamedParameters) +{ + DapRpcMessage notification = + DapRpcMessagePrivate::createBasicRequest(asMethod, aNamedParameters); + notification.d->m_type = DapRpcMessage::Notification; + return notification; +} + +DapRpcMessage DapRpcMessage::createNotification(const QString& asMethod, const QByteArray& aStream) +{ + DapRpcMessage notification = createNotification(asMethod, QJsonValue::fromVariant(aStream)); + return notification; +} + +DapRpcMessage DapRpcMessage::createResponse(const QJsonValue &aResult) const +{ + DapRpcMessage response; + if (d->m_pObject->contains(QLatin1String("id"))) { + QJsonObject *object = response.d->m_pObject.data(); + object->insert(QLatin1String("jsonrpc"), QLatin1String("2.0")); + object->insert(QLatin1String("id"), d->m_pObject->value(QLatin1String("id"))); + object->insert(QLatin1String("result"), aResult); + response.d->m_type = DapRpcMessage::Response; + } + + return response; +} + +DapRpcMessage DapRpcMessage::createErrorResponse(DapErrorCode aCode, + const QString &asMessage, + const QJsonValue &aData) const +{ + DapRpcMessage response; + QJsonObject error; + error.insert(QLatin1String("code"), aCode); + if (!asMessage.isEmpty()) + error.insert(QLatin1String("message"), asMessage); + if (!aData.isUndefined()) + error.insert(QLatin1String("data"), aData); + + response.d->m_type = DapRpcMessage::Error; + QJsonObject *object = response.d->m_pObject.data(); + object->insert(QLatin1String("jsonrpc"), QLatin1String("2.0")); + if (d->m_pObject->contains(QLatin1String("id"))) + object->insert(QLatin1String("id"), d->m_pObject->value(QLatin1String("id"))); + else + object->insert(QLatin1String("id"), 0); + object->insert(QLatin1String("error"), error); + return response; +} + +int DapRpcMessage::id() const +{ + if (d->m_type == DapRpcMessage::Notification || !d->m_pObject) + return -1; + + const QJsonValue &value = d->m_pObject->value(QLatin1String("id")); + if (value.isString()) + return value.toString().toInt(); + return value.toInt(); +} + +QString DapRpcMessage::method() const +{ + if (d->m_type == DapRpcMessage::Response || !d->m_pObject) + return QString(); + + return d->m_pObject->value(QLatin1String("method")).toString(); +} + +QJsonValue DapRpcMessage::params() const +{ + if (d->m_type == DapRpcMessage::Response || d->m_type == DapRpcMessage::Error) + return QJsonValue(QJsonValue::Undefined); + if (!d->m_pObject) + return QJsonValue(QJsonValue::Undefined); + + return d->m_pObject->value(QLatin1String("params")); +} + +QJsonValue DapRpcMessage::toJsonValue() const +{ + if (d->m_type != DapRpcMessage::Response || !d->m_pObject) + return QJsonValue(QJsonValue::Undefined); + + return d->m_pObject->value(QLatin1String("result")); +} + +QByteArray DapRpcMessage::toByteArray() const +{ + QJsonValue value = toJsonValue(); + return QByteArray::fromHex(value.toVariant().toByteArray()); +} + +int DapRpcMessage::errorCode() const +{ + if (d->m_type != DapRpcMessage::Error || !d->m_pObject) + return 0; + + QJsonObject error = + d->m_pObject->value(QLatin1String("error")).toObject(); + const QJsonValue &value = error.value(QLatin1String("code")); + if (value.isString()) + return value.toString().toInt(); + return value.toInt(); +} + +QString DapRpcMessage::errorMessage() const +{ + if (d->m_type != DapRpcMessage::Error || !d->m_pObject) + return QString(); + + QJsonObject error = + d->m_pObject->value(QLatin1String("error")).toObject(); + return error.value(QLatin1String("message")).toString(); +} + +QJsonValue DapRpcMessage::errorData() const +{ + if (d->m_type != DapRpcMessage::Error || !d->m_pObject) + return QJsonValue(QJsonValue::Undefined); + + QJsonObject error = + d->m_pObject->value(QLatin1String("error")).toObject(); + return error.value(QLatin1String("data")); +} + +static QDebug operator<<(QDebug dbg, DapRpcMessage::Type type) +{ + switch (type) { + case DapRpcMessage::Request: + return dbg << "DapRpcMessage::Request"; + case DapRpcMessage::Response: + return dbg << "DapRpcMessage::Response"; + case DapRpcMessage::Notification: + return dbg << "DapRpcMessage::Notification"; + case DapRpcMessage::Error: + return dbg << "DapRpcMessage::Error"; + default: + return dbg << "DapRpcMessage::Invalid"; + } +} + +QDebug operator<<(QDebug dbg, const DapRpcMessage &msg) +{ + dbg.nospace() << "DapRpcMessage(type=" << msg.type(); + if (msg.type() != DapRpcMessage::Notification) { + dbg.nospace() << ", id=" << msg.id(); + } + + if (msg.type() == DapRpcMessage::Request || + msg.type() == DapRpcMessage::Notification) { + dbg.nospace() << ", method=" << msg.method() + << ", params=" << msg.params(); + } else if (msg.type() == DapRpcMessage::Response) { + dbg.nospace() << ", result=" << msg.toJsonValue(); + } else if (msg.type() == DapRpcMessage::Error) { + dbg.nospace() << ", code=" << msg.errorCode() + << ", message=" << msg.errorMessage() + << ", data=" << msg.errorData(); + } + dbg.nospace() << ")"; + return dbg.space(); +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcMessage.h b/chain/wallet/dapRPCProtocol/DapRpcMessage.h new file mode 100644 index 0000000000000000000000000000000000000000..786530697a46dfa139fd86239521f774a38fb737 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcMessage.h @@ -0,0 +1,183 @@ +#ifndef DapRPCMESSAGE_H +#define DapRPCMESSAGE_H + +#include <QSharedDataPointer> +#include <QMetaType> +#include <QJsonDocument> +#include <QJsonValue> +#include <QJsonObject> +#include <QJsonArray> +#include <QDebug> + +#define qJsonRpcDebug if (qgetenv("QJSONRPC_DEBUG").isEmpty()); else qDebug + +/** + * @brief The DapErrorCode enum + * This enum values are used to mark code of error + */ +enum DapErrorCode { + NoError = 0, ///< No error + ParseError = -32700, /*!< Invalid JSON was received by the server. + An error occurred on the server while parsing the JSON text. */ + InvalidRequest = -32600, ///< The JSON sent is not a valid Request object. + MethodNotFound = -32601, ///< The method does not exist / is not available. + InvalidParams = -32602, ///< Invalid method parameter(s). + InternalError = -32603, ///< Internal JSON-RPC error. + ServerErrorBase = -32000, ///< Reserved for implementation-defined server-errors. + UserError = -32099, ///< Anything after this is user defined + TimeoutError = -32100 ///< Timeout +}; +Q_DECLARE_METATYPE(DapErrorCode) + +class DapRpcMessagePrivate; +/// Class of message type by RPC protocol +class DapRpcMessage +{ + friend class DapRpcMessagePrivate; + QSharedDataPointer<DapRpcMessagePrivate> d; + +public: + /// Standard constructor + DapRpcMessage(); + /// Copy constructor + /// @param aDapRPCMessage Other message + DapRpcMessage(const DapRpcMessage &aDapRPCMessage); + /// Assignment operator + /// @param aDapRPCMessage Other message + /// @return RPC message + DapRpcMessage &operator=(const DapRpcMessage &aDapRPCMessage); + /// Standard destructor + ~DapRpcMessage(); + + /// Swap message + /// @param aDapRPCMessage Swaped message + inline void swap(DapRpcMessage &aDapRPCMessage) { qSwap(d, aDapRPCMessage.d); } + + /** + * @brief The Type enum + * Type of message + */ + enum Type { + Invalid, ///< Invalid + Request, ///< Request + Response, ///< Responce + Notification, ///< Notification + Error ///< Error + }; + + /// Create new request message + /// @param asMethod Remote method + /// @param aParams Params message in format JsonArray + /// @return aParams New RPC message + static DapRpcMessage createRequest(const QString &asMethod, const QJsonArray &aParams = QJsonArray()); + /// Create new request message + /// @param asMethod Remote method + /// @param aParams Params message in format JsonValue + /// @return aParam New RPC message + static DapRpcMessage createRequest(const QString &asMethod, const QJsonValue &aParam); + /// Create new request message + /// @param asMethod Remote method + /// @param aNamedParameters Named params message in format JsonObject + /// @return New RPC message + static DapRpcMessage createRequest(const QString &asMethod, const QJsonObject &aNamedParameters); + /// Create new request message + /// @param asMethod Remote method + /// @param aStream Message stream + /// @return New RPC message + static DapRpcMessage createRequest(const QString &asMethod, const QByteArray& aStream); + /// Create new notification message + /// @param asMethod Remote method + /// @param aParams Params message in format JsonArray. + /// @return aParams New RPC message + static DapRpcMessage createNotification(const QString &asMethod, const QJsonArray &aParams = QJsonArray()); + /// Create new notification message + /// @param asMethod Remote method + /// @param aParams Params message in format JsonValue + /// @return aParam New RPC message + static DapRpcMessage createNotification(const QString &asMethod, const QJsonValue &aParam); + /// Create new notification message + /// @param asMethod Remote method + /// @param aNamedParameters Named params message in format JsonObject + /// @return New RPC message + static DapRpcMessage createNotification(const QString &asMethod, const QJsonObject &aNamedParameters); + /// Create new notification message + /// @param asMethod Remote method + /// @param aStream Message stream + /// @return New RPC message + static DapRpcMessage createNotification(const QString &asMethod, const QByteArray& aStream); + + /// Create new response message + /// @param aResult Result of operation + /// @return aParams Response RPC message + DapRpcMessage createResponse(const QJsonValue &aResult) const; + /// Create new error responce + /// @param aCode Code of error + /// @see DapErrorCode + /// @param asMessage Message + /// @param aData Data of message + /// @return Rpc message + DapRpcMessage createErrorResponse(DapErrorCode aCode, + const QString &asMessage = QString(), + const QJsonValue &aData = QJsonValue()) const; + /// Get type of message + /// @return Type of message + DapRpcMessage::Type type() const; + /// Validation of message + /// @return True if message is valid. False otherwise + bool isValid() const; + /// Get id message + /// @return id message + int id() const; + /// Remote method from request message + /// @return Remote method + QString method() const; + /// Params from request message + /// @return Params of message as JsonValue + QJsonValue params() const; + /// Get result of response message + /// @return Result of response message as JsonValue + QJsonValue toJsonValue() const; + /// Get result of response message + /// @return Result of response message as yteArray + QByteArray toByteArray() const; + /// Get error code. @see DapErrorCode + /// @return Error code + int errorCode() const; + /// Get text of error message + /// @return Text of error message. If message isn't error type return default string; + QString errorMessage() const; + /// Get data of error message + /// @return Data of error. If message isn't error type return default JsonValue + QJsonValue errorData() const; + + /// Convert message to JsonObject + /// @return Message as JsonObject + QJsonObject toObject() const; + /// Static method to convert JsonObject to Rpc message + /// @param aObject Message as JsonObject + /// @return Converted message + static DapRpcMessage fromObject(const QJsonObject &aObject); + + /// Serilize message + /// @return Message as byte array + QByteArray toJson() const; + /// Static method to convert serilisation message to Rpc message + /// @param aData Data of message + /// @return Converted message + static DapRpcMessage fromJson(const QByteArray &aData); + + /// Overloaded relational operator (equal) + /// @param aDapRpcMessage Other message + /// @return True if equal and false when not + bool operator==(const DapRpcMessage &aDapRpcMessage) const; + /// Overloaded relational operator (not equal) + /// @param aDapRpcMessage Other message + /// @return True if not equal and false when yes + inline bool operator!=(const DapRpcMessage &aDapRpcMessage) const { return !(operator==(aDapRpcMessage)); } +}; + +QDebug operator<<(QDebug, const DapRpcMessage &); +Q_DECLARE_METATYPE(DapRpcMessage) +Q_DECLARE_SHARED(DapRpcMessage) + +#endif // DapRPCMESSAGE_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcService.cpp b/chain/wallet/dapRPCProtocol/DapRpcService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05826c00e3912ac73ce224243355702241829ee8 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcService.cpp @@ -0,0 +1,351 @@ +#include "DapRpcService.h" +#include "DapRpcSocket.h" + +ParameterInfo::ParameterInfo(const QString &asName, int aType, bool aOut) + : type(aType), + jsType(DapRpcService::convertVariantTypeToJSType(aType)), + name(asName), + out(aOut) +{ +} + +MethodInfo::MethodInfo() + : returnType(QMetaType::Void), + valid(false), + hasOut(false) +{ +} + +MethodInfo::MethodInfo(const QMetaMethod &aMethod) + : returnType(QMetaType::Void), + valid(true), + hasOut(false) +{ + returnType = aMethod.returnType(); + if (returnType == QMetaType::UnknownType) { + qJsonRpcDebug() << "DapRpcService: can't bind method's return type" + << QString(aMethod.name()); + valid = false; + return; + } + + parameters.reserve(aMethod.parameterCount()); + + const QList<QByteArray> &types = aMethod.parameterTypes(); + const QList<QByteArray> &names = aMethod.parameterNames(); + for (int i = 0; i < types.size(); ++i) { + QByteArray parameterType = types.at(i); + const QByteArray ¶meterName = names.at(i); + bool out = parameterType.endsWith('&'); + + if (out) { + hasOut = true; + parameterType.resize(parameterType.size() - 1); + } + + int type = QMetaType::type(parameterType); + if (type == 0) { + qJsonRpcDebug() << "DapRpcService: can't bind method's parameter" + << QString(parameterType); + valid = false; + break; + } + + parameters.append(ParameterInfo(parameterName, type, out)); + } +} + +void DapRpcService::setCurrentRequest(const DapRpcServiceRequest &aCurrentRequest) +{ + m_currentRequest = aCurrentRequest; +} + +QString DapRpcService::getName() const +{ + return m_sName; +} + +DapRpcService::DapRpcService(const QString &asName, QObject *apParent) + : QObject(apParent), m_sName(asName) +{ +} + +DapRpcService::~DapRpcService() +{ +} + +DapRpcServiceRequest DapRpcService::currentRequest() const +{ + return m_currentRequest; +} + +void DapRpcService::beginDelayedResponse() +{ + m_delayedResponse = true; +} + +int DapRpcService::convertVariantTypeToJSType(int aType) +{ + switch (aType) { + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::Double: + case QMetaType::Long: + case QMetaType::LongLong: + case QMetaType::Short: + case QMetaType::Char: + case QMetaType::ULong: + case QMetaType::ULongLong: + case QMetaType::UShort: + case QMetaType::UChar: + case QMetaType::Float: + return QJsonValue::Double; // all numeric types in js are doubles + case QMetaType::QVariantList: + case QMetaType::QStringList: + return QJsonValue::Array; + case QMetaType::QVariantMap: + return QJsonValue::Object; + case QMetaType::QByteArray: + case QMetaType::QString: + return QJsonValue::String; + case QMetaType::Bool: + return QJsonValue::Bool; + default: break; + } + + return QJsonValue::Undefined; +} + +int DapRpcService::qjsonRpcMessageType = qRegisterMetaType<DapRpcMessage>("DapRpcMessage"); +void DapRpcService::cacheInvokableInfo() +{ + const QMetaObject *obj = metaObject(); + int startIdx = staticMetaObject.methodCount(); // skip QObject slots + for (int idx = startIdx; idx < obj->methodCount(); ++idx) { + const QMetaMethod method = obj->method(idx); + if ((method.methodType() == QMetaMethod::Slot && + method.access() == QMetaMethod::Public) || + method.methodType() == QMetaMethod::Signal) { + + QByteArray signature = method.methodSignature(); + QByteArray methodName = method.name(); + + MethodInfo info(method); + if (!info.valid) + continue; + + if (signature.contains("QVariant")) + m_invokableMethodHash[methodName].append(idx); + else + m_invokableMethodHash[methodName].prepend(idx); + m_methodInfoHash[idx] = info; + } + } +} + +static bool jsParameterCompare(const QJsonArray ¶meters, + const MethodInfo &info) +{ + int j = 0; + for (int i = 0; i < info.parameters.size() && j < parameters.size(); ++i) { + int jsType = info.parameters.at(i).jsType; + if (jsType != QJsonValue::Undefined && jsType != parameters.at(j).type()) { + if (!info.parameters.at(i).out) + return false; + } else { + ++j; + } + } + + return (j == parameters.size()); +} + +static bool jsParameterCompare(const QJsonObject ¶meters, + const MethodInfo &info) +{ + for (int i = 0; i < info.parameters.size(); ++i) { + int jsType = info.parameters.at(i).jsType; + QJsonValue value = parameters.value(info.parameters.at(i).name); + if (value == QJsonValue::Undefined) { + if (!info.parameters.at(i).out) + return false; + } else if (jsType == QJsonValue::Undefined) { + continue; + } else if (jsType != value.type()) { + return false; + } + } + + return true; +} + +static inline QVariant convertArgument(const QJsonValue &argument, + const ParameterInfo &info) +{ + if (argument.isUndefined()) + return QVariant(info.type, Q_NULLPTR); + + if (info.type == QMetaType::QJsonValue || info.type == QMetaType::QVariant || + info.type >= QMetaType::User) { + + if (info.type == QMetaType::QVariant) + return argument.toVariant(); + + QVariant result(argument); + if (info.type >= QMetaType::User && result.canConvert(info.type)) + result.convert(info.type); + return result; + } + + QVariant result = argument.toVariant(); + if (result.userType() == info.type || info.type == QMetaType::QVariant) { + return result; + } else if (result.canConvert(info.type)) { + result.convert(info.type); + return result; + } else if (info.type < QMetaType::User) { + // already tried for >= user, this is the last resort + QVariant result(argument); + if (result.canConvert(info.type)) { + result.convert(info.type); + return result; + } + } + + return QVariant(); +} + +QJsonValue DapRpcService::convertReturnValue(QVariant &aReturnValue) +{ + if (static_cast<int>(aReturnValue.type()) == qMetaTypeId<QJsonObject>()) + return QJsonValue(aReturnValue.toJsonObject()); + else if (static_cast<int>(aReturnValue.type()) == qMetaTypeId<QJsonArray>()) + return QJsonValue(aReturnValue.toJsonArray()); + + switch (static_cast<QMetaType::Type>(aReturnValue.type())) { + case QMetaType::Bool: + case QMetaType::Int: + case QMetaType::Double: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::UInt: + case QMetaType::QString: + case QMetaType::QStringList: + case QMetaType::QVariantList: + case QMetaType::QVariantMap: + return QJsonValue::fromVariant(aReturnValue); + case QMetaType::QByteArray: + { + QJsonValue var = QJsonValue::fromVariant(aReturnValue); + return var; + } + default: + // if a conversion operator was registered it will be used + if (aReturnValue.convert(QMetaType::QJsonValue)) + return aReturnValue.toJsonValue(); + else + return QJsonValue(); + } +} + +static inline QByteArray methodName(const DapRpcMessage &request) +{ + const QString &methodPath(request.method()); + return methodPath.midRef(methodPath.lastIndexOf('.') + 1).toLatin1(); +} + +DapRpcMessage DapRpcService::dispatch(const DapRpcMessage &aRequest) +{ + if (aRequest.type() != DapRpcMessage::Request && + aRequest.type() != DapRpcMessage::Notification) { + return aRequest.createErrorResponse(DapErrorCode::InvalidRequest, "invalid request"); + } + + const QByteArray &method(methodName(aRequest)); + qDebug() << method; + if (!m_invokableMethodHash.contains(method)) { + return aRequest.createErrorResponse(DapErrorCode::MethodNotFound, "invalid method called"); + } + + int idx = -1; + QVariantList arguments; + const QList<int> &indexes = m_invokableMethodHash.value(method); + const QJsonValue ¶ms = aRequest.params(); + QVarLengthArray<void *, 10> parameters; + QVariant returnValue; + QMetaType::Type returnType = QMetaType::Void; + + bool usingNamedParameters = params.isObject(); + foreach (int methodIndex, indexes) { + MethodInfo &info = m_methodInfoHash[methodIndex]; + bool methodMatch = usingNamedParameters ? + jsParameterCompare(params.toObject(), info) : + jsParameterCompare(params.toArray(), info); + + if (methodMatch) { + idx = methodIndex; + arguments.reserve(info.parameters.size()); + returnType = static_cast<QMetaType::Type>(info.returnType); + returnValue = (returnType == QMetaType::Void) ? + QVariant() : QVariant(returnType, Q_NULLPTR); + if (returnType == QMetaType::QVariant) + parameters.append(&returnValue); + else + parameters.append(returnValue.data()); + + for (int i = 0; i < info.parameters.size(); ++i) { + const ParameterInfo ¶meterInfo = info.parameters.at(i); + QJsonValue incomingArgument = usingNamedParameters ? + params.toObject().value(parameterInfo.name) : + params.toArray().at(i); + + QVariant argument = convertArgument(incomingArgument, parameterInfo); + if (!argument.isValid()) { + QString message = incomingArgument.isUndefined() ? + QString("failed to construct default object for '%1'").arg(parameterInfo.name) : + QString("failed to convert from JSON for '%1'").arg(parameterInfo.name); + return aRequest.createErrorResponse(DapErrorCode::InvalidParams, message); + } + + arguments.push_back(argument); + if (parameterInfo.type == QMetaType::QVariant) + parameters.append(static_cast<void *>(&arguments.last())); + else + parameters.append(const_cast<void *>(arguments.last().constData())); + } + break; + } + } + + if (idx == -1) { + return aRequest.createErrorResponse(DapErrorCode::InvalidParams, "invalid parameters"); + } + + MethodInfo &info = m_methodInfoHash[idx]; + + bool success = + const_cast<DapRpcService*>(this)->qt_metacall(QMetaObject::InvokeMetaMethod, idx, parameters.data()) < 0; + if (!success) { + QString message = QString("dispatch for method '%1' failed").arg(method.constData()); + return aRequest.createErrorResponse(DapErrorCode::InvalidRequest, message); + } + + if (m_delayedResponse) { + m_delayedResponse = false; + return DapRpcMessage(); + } + + if (info.hasOut) { + QJsonArray ret; + if (info.returnType != QMetaType::Void) + ret.append(convertReturnValue(returnValue)); + for (int i = 0; i < info.parameters.size(); ++i) + if (info.parameters.at(i).out) + ret.append(convertReturnValue(arguments[i])); + if (ret.size() > 1) + return aRequest.createResponse(ret); + return aRequest.createResponse(ret.first()); + } + + return aRequest.createResponse(convertReturnValue(returnValue)); +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcService.h b/chain/wallet/dapRPCProtocol/DapRpcService.h new file mode 100644 index 0000000000000000000000000000000000000000..6e348b96658456681ece13ed7d12e31bcb2027c9 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcService.h @@ -0,0 +1,75 @@ +#ifndef DapRPCSERVICE_H +#define DapRPCSERVICE_H + +#include <QObject> +#include <QVariant> +#include <QPointer> +#include <QVarLengthArray> +#include <QMetaMethod> +#include <QEventLoop> +#include <QDebug> + + +#include "DapRpcMessage.h" +#include "DapRpcServiceRequest.h" + +struct ParameterInfo +{ + ParameterInfo(const QString &asName = QString(), int aType = 0, bool aOut = false); + + int type; + int jsType; + QString name; + bool out; +}; + +struct MethodInfo +{ + MethodInfo(); + MethodInfo(const QMetaMethod &aMethod); + + QVarLengthArray<ParameterInfo> parameters; + int returnType; + bool valid; + bool hasOut; +}; + +class DapRpcService : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(DapRpcService) + + QHash<int, MethodInfo > m_methodInfoHash; + QHash<QByteArray, QList<int> > m_invokableMethodHash; + DapRpcServiceRequest m_currentRequest; + bool m_delayedResponse {false}; + QString m_sName; + +protected: + DapRpcServiceRequest currentRequest() const; + void beginDelayedResponse(); + +public: + explicit DapRpcService(const QString &asName, QObject *apParent = nullptr); + ~DapRpcService(); + + void cacheInvokableInfo(); + static int qjsonRpcMessageType; + static int convertVariantTypeToJSType(int aType); + static QJsonValue convertReturnValue(QVariant &aReturnValue); + + void setCurrentRequest(const DapRpcServiceRequest &aCurrentRequest); + + QString getName() const; + +signals: + void result(const DapRpcMessage &aDapRpcMessage); + void notifyConnectedClients(const DapRpcMessage &aDapRpcMessage); + void notifyConnectedClients(const QString &asMethod, const QJsonArray &aParams = QJsonArray()); + +public slots: + DapRpcMessage dispatch(const DapRpcMessage &aRequest); +}; + +#endif // DapRPCSERVICE_H + diff --git a/chain/wallet/dapRPCProtocol/DapRpcServiceProvider.cpp b/chain/wallet/dapRPCProtocol/DapRpcServiceProvider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7032c37d8a05e298a4ba6afad27dfadb709d49d7 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcServiceProvider.cpp @@ -0,0 +1,107 @@ +#include "DapRpcServiceProvider.h" +#include "DapRpcSocket.h" + +DapRpcServiceProvider::DapRpcServiceProvider() +{ +} + +DapRpcServiceProvider::~DapRpcServiceProvider() +{ +} + +QByteArray DapRpcServiceProvider::getServiceName(DapRpcService *apService) +{ + const QMetaObject *mo = apService->metaObject(); + for (int i = 0; i < mo->classInfoCount(); i++) + { + const QMetaClassInfo mci = mo->classInfo(i); + if (mci.name() == QLatin1String("serviceName")) + return mci.value(); + } + + return QByteArray(mo->className()).toLower(); +} + +DapRpcService * DapRpcServiceProvider::addService(DapRpcService *apService) +{ + QByteArray serviceName = apService->getName().toUtf8(); + if (serviceName.isEmpty()) { + qJsonRpcDebug() << "service added without serviceName classinfo, aborting"; + return nullptr; + } + + if (m_services.contains(serviceName)) { + qJsonRpcDebug() << "service with name " << serviceName << " already exist"; + return nullptr; + } + + apService->cacheInvokableInfo(); + m_services.insert(serviceName, apService); + if (!apService->parent()) + m_cleanupHandler.add(apService); + return apService; +} + +bool DapRpcServiceProvider::removeService(DapRpcService *apService) +{ + QByteArray serviceName = getServiceName(apService); + if (!m_services.contains(serviceName)) { + qJsonRpcDebug() << "can not find service with name " << serviceName; + return false; + } + + m_cleanupHandler.remove(m_services.value(serviceName)); + m_services.remove(serviceName); + return true; +} + +DapRpcService* DapRpcServiceProvider::findService(const QString &asServiceName) +{ + if (!m_services.contains(QByteArray::fromStdString(asServiceName.toStdString()))) + { + qJsonRpcDebug() << "can not find service with name " << asServiceName; + return nullptr; + } + return m_services.value(QByteArray::fromStdString(asServiceName.toStdString())); +} + +void DapRpcServiceProvider::processMessage(DapRpcSocket *apSocket, const DapRpcMessage &aMessage) +{ + switch (aMessage.type()) { + case DapRpcMessage::Request: + case DapRpcMessage::Notification: { + QByteArray serviceName = aMessage.method().section(".", 0, -2).toLatin1(); + bool b = m_services.contains(serviceName); + if (serviceName.isEmpty() || !m_services.contains(serviceName)) + { + if (aMessage.type() == DapRpcMessage::Request) + { + DapRpcMessage error = + aMessage.createErrorResponse(DapErrorCode::MethodNotFound, + QString("service '%1' not found").arg(serviceName.constData())); + apSocket->notify(error); + } + } else { + DapRpcService *service = m_services.value(serviceName); + service->setCurrentRequest(DapRpcServiceRequest(aMessage, apSocket)); + if (aMessage.type() == DapRpcMessage::Request) + QObject::connect(service, SIGNAL(result(DapRpcMessage)), + apSocket, SLOT(notify(DapRpcMessage)), Qt::UniqueConnection); + DapRpcMessage response = service->dispatch(aMessage); + if (response.isValid()) + apSocket->notify(response); + } + } + break; + + case DapRpcMessage::Response: + break; + + default: { + DapRpcMessage error = + aMessage.createErrorResponse(DapErrorCode::InvalidRequest, QString("invalid request")); + apSocket->notify(error); + break; + } + } +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcServiceProvider.h b/chain/wallet/dapRPCProtocol/DapRpcServiceProvider.h new file mode 100644 index 0000000000000000000000000000000000000000..6377d1bf3e8fb06ffea963d1373872eb511e69c0 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcServiceProvider.h @@ -0,0 +1,51 @@ +#ifndef DapRPCSERVICEPROVIDER_H +#define DapRPCSERVICEPROVIDER_H + +#include <QScopedPointer> +#include <QObjectCleanupHandler> +#include <QHash> +#include <QMetaObject> +#include <QMetaClassInfo> +#include <QDebug> + +#include "DapRpcService.h" + +/** + * @brief The DapRpcServiceProvider class + * Class provides to add/remove services and store them. + */ +class DapRpcServiceProvider +{ + /// Store pointers to service by the name + QHash<QByteArray, DapRpcService*> m_services; + /// Handle service to cleanup + QObjectCleanupHandler m_cleanupHandler; + +protected: + /// Standard constructor + DapRpcServiceProvider(); + /// Process message to send by socket interface + /// @param apSocket Remote socket + /// aMessage Rpc message + void processMessage(DapRpcSocket *apSocket, const DapRpcMessage &aMessage); + +public: + /// Virtual destructor + virtual ~DapRpcServiceProvider(); + /// Add new service + /// @param apService New service + /// @return True if service add successfullym false if not + virtual DapRpcService *addService(DapRpcService *apService); + /// Remove existing service + /// @param apService Service to remove + /// @return If service alreade removing or not existing return false, else return true + virtual bool removeService(DapRpcService *apService); + + virtual DapRpcService *findService(const QString& asServiceName); + /// Get service name + /// @param apService Service + /// @return Serilization name of service + QByteArray getServiceName(DapRpcService *apService); +}; + +#endif // DapRPCSERVICEPROVIDER_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcServiceReply.cpp b/chain/wallet/dapRPCProtocol/DapRpcServiceReply.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba26f389bbad1cde1d328fbe6ea12d6a1e1e70e8 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcServiceReply.cpp @@ -0,0 +1,31 @@ +#include "DapRpcServiceReply.h" + +DapRpcServiceReply::DapRpcServiceReply(QObject *apParent) + : QObject(apParent) +{ +} + +DapRpcServiceReply::~DapRpcServiceReply() +{ + +} + +void DapRpcServiceReply::setRequest(const DapRpcMessage &aRequest) +{ + m_request = aRequest; +} + +void DapRpcServiceReply::setResponse(const DapRpcMessage &aResponse) +{ + m_response = aResponse; +} + +DapRpcMessage DapRpcServiceReply::request() const +{ + return m_request; +} + +DapRpcMessage DapRpcServiceReply::response() const +{ + return m_response; +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcServiceReply.h b/chain/wallet/dapRPCProtocol/DapRpcServiceReply.h new file mode 100644 index 0000000000000000000000000000000000000000..c608ab95872e4368d702fd2b30d686de5a527c64 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcServiceReply.h @@ -0,0 +1,48 @@ +#ifndef DapRPCSERVICEREPLY_H +#define DapRPCSERVICEREPLY_H + +#include <QObject> +#include <QNetworkReply> + +#include "DapRpcMessage.h" + +/** + * @brief The DapRpcServiceReply class + * Class provides service reply from sender. + * Class has methods to operate with response and request + */ +class DapRpcServiceReply : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(DapRpcServiceReply) + /// Request message + DapRpcMessage m_request; + /// Response message + DapRpcMessage m_response; + +public: + /// Standard constructor + explicit DapRpcServiceReply(QObject *apParent = nullptr); + /// Virtual destructor + virtual ~DapRpcServiceReply(); + + /// Get request message + /// @return Request message + DapRpcMessage request() const; + /// Get response message + /// @return Response message + DapRpcMessage response() const; + + /// Set request message + /// @param aRequest New request message + void setRequest(const DapRpcMessage &aRequest); + /// Set response message + /// @param aResponse Responce message + void setResponse(const DapRpcMessage &aResponse); + +signals: + /// The signal is emitted when reply finished + void finished(); +}; + +#endif // DapRPCSERVICEREPLY_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcServiceRequest.cpp b/chain/wallet/dapRPCProtocol/DapRpcServiceRequest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a00a07b5b8d984bea7e0f74f0182eca4886b364 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcServiceRequest.cpp @@ -0,0 +1,69 @@ +#include "DapRpcSocket.h" +#include "DapRpcServiceRequest.h" + + +DapRpcServiceRequest::DapRpcServiceRequest() +{ +} + +DapRpcServiceRequest::~DapRpcServiceRequest() +{ +} + +DapRpcServiceRequest::DapRpcServiceRequest(const DapRpcServiceRequest &aDapRpcServiceRequest) +{ + m_request = aDapRpcServiceRequest.m_request; + m_socket = aDapRpcServiceRequest.m_socket; +} + +DapRpcServiceRequest::DapRpcServiceRequest(const DapRpcMessage &aRequest, + DapRpcSocket *apSocket) +{ + m_request = aRequest; + m_socket = apSocket; +} + +DapRpcServiceRequest &DapRpcServiceRequest::operator=(const DapRpcServiceRequest &other) +{ + m_request = other.m_request; + m_socket = other.m_socket; + return *this; +} + +bool DapRpcServiceRequest::isValid() const +{ + return (m_request.isValid() && !m_socket.isNull()); +} + +DapRpcMessage DapRpcServiceRequest::request() const +{ + return m_request; +} + +DapRpcSocket *DapRpcServiceRequest::socket() const +{ + return m_socket; +} + +bool DapRpcServiceRequest::respond(QVariant aReturnValue) +{ + if (!m_socket) { + qJsonRpcDebug() << "socket was closed"; + return false; + } + + DapRpcMessage response = + m_request.createResponse(DapRpcService::convertReturnValue(aReturnValue)); + return respond(response); +} + +bool DapRpcServiceRequest::respond(const DapRpcMessage &aResponse) +{ + if (!m_socket) { + qJsonRpcDebug() << "socket was closed"; + return false; + } + + QMetaObject::invokeMethod(m_socket, "notify", Q_ARG(DapRpcMessage, aResponse)); + return true; +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcServiceRequest.h b/chain/wallet/dapRPCProtocol/DapRpcServiceRequest.h new file mode 100644 index 0000000000000000000000000000000000000000..0949ff6a386c20ff6bdb03efcb2685f613798fe8 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcServiceRequest.h @@ -0,0 +1,60 @@ +#ifndef DapRPCSERVICEREQUEST_H +#define DapRPCSERVICEREQUEST_H + +#include <QPointer> +#include <QMetaObject> +#include <QDebug> + +#include "DapRpcMessage.h" + +class DapRpcSocket; +/** + * @brief The DapRpcServiceRequest class + * Class provides to operate with request message by socket interface + * @see DapRpcSocket + */ +class DapRpcServiceRequest +{ + /// Request message + DapRpcMessage m_request; + /// RPC socket + QPointer<DapRpcSocket> m_socket; + +public: + /// Standard constructor + DapRpcServiceRequest(); + /// Copy constructor + DapRpcServiceRequest(const DapRpcServiceRequest &aDapRpcServiceRequest); + /// Overloaded constructor + /// @param aRequest Request message + /// @param apSocket Pointer to RPC socket + DapRpcServiceRequest(const DapRpcMessage &aRequest, DapRpcSocket *apSocket); + /// Overloaded assignment operator + /// @param aDapRpcServiceRequest Other DapRpcServiceRequest object + /// @return Reference to this object + DapRpcServiceRequest &operator=(const DapRpcServiceRequest &aDapRpcServiceRequest); + /// Standard destructor + ~DapRpcServiceRequest(); + + /// Validation of request message + /// @return If request message is valid or socket is not null return true. + /// Otherwise return false + bool isValid() const; + /// Get request message + /// @return Request message + DapRpcMessage request() const; + /// Get current socket + /// @return Socket + DapRpcSocket *socket() const; + + /// Create response to following respont by socket + /// @param aReturnValue Return value from service + /// @return False if socket is closed + bool respond(QVariant aReturnValue); + /// Send response to socket + /// @param aResponse Response message + /// @return False if socket is closed + bool respond(const DapRpcMessage &aResponse); +}; + +#endif // DapRPCSERVICEREQUEST_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcSocket.cpp b/chain/wallet/dapRPCProtocol/DapRpcSocket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3de0fcaea872994ad856381d17e2d0cdb60c2c1 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcSocket.cpp @@ -0,0 +1,266 @@ +#include "DapRpcSocket.h" +#include "DapRpcService.h" + +DapRpcSocket::DapRpcSocket(QObject *apParent) + : QObject(apParent) +{ + +} + +DapRpcSocket::DapRpcSocket(QIODevice *apDevice, QObject *apParent) + : QObject(apParent) +{ + m_pDevice = apDevice; + connect(m_pDevice, SIGNAL(readyRead()), this, SLOT(processIncomingData())); +} + +DapRpcSocket::~DapRpcSocket() +{ +} + +int DapRpcSocket::findJsonDocumentEnd(const QByteArray &aJsonData) +{ + const char* pos = aJsonData.constData(); + const char* end = pos + aJsonData.length(); + + char blockStart = 0; + char blockEnd = 0; + int index = 0; + + while (true) { + if (pos == end) { + return -1; + } else if (*pos == '{') { + blockStart = '{'; + blockEnd = '}'; + break; + } else if(*pos == '[') { + blockStart = '['; + blockEnd = ']'; + break; + } + + pos++; + index++; + } + + pos++; + index++; + int depth = 1; + bool inString = false; + while (depth > 0 && pos <= end) { + if (*pos == '\\') { + pos += 2; + index += 2; + continue; + } else if (*pos == '"') { + inString = !inString; + } else if (!inString) { + if (*pos == blockStart) + depth++; + else if (*pos == blockEnd) + depth--; + } + + pos++; + index++; + } + + return depth == 0 ? index-1 : -1; +} + +void DapRpcSocket::writeData(const DapRpcMessage &asMessage) +{ + QJsonDocument doc = QJsonDocument(asMessage.toObject()); + QByteArray data = doc.toJson(QJsonDocument::Compact); + + m_pDevice.data()->write(data); + qJsonRpcDebug() << "sending: " << data; +} + +void DapRpcSocket::setDefaultRequestTimeout(int aiMsecs) +{ + if (aiMsecs < 0) { + qJsonRpcDebug() << "Cannot set a negative request timeout msecs value"; + return; + } + + m_defaultRequestTimeout = aiMsecs; +} + +int DapRpcSocket::getDefaultRequestTimeout() const +{ + return m_defaultRequestTimeout; +} + +bool DapRpcSocket::isValid() const +{ + return m_pDevice && m_pDevice.data()->isOpen(); +} + +DapRpcMessage DapRpcSocket::sendMessageBlocking(const DapRpcMessage &asMessage, int aMsecs) +{ + DapRpcServiceReply *reply = sendMessage(asMessage); + QScopedPointer<DapRpcServiceReply> replyPtr(reply); + + QEventLoop responseLoop; + connect(reply, SIGNAL(finished()), &responseLoop, SLOT(quit())); + QTimer::singleShot(aMsecs, &responseLoop, SLOT(quit())); + responseLoop.exec(); + + if (!reply->response().isValid()) { + m_replies.remove(asMessage.id()); + return asMessage.createErrorResponse(DapErrorCode::TimeoutError, "request timed out"); + } + + return reply->response(); +} + +DapRpcServiceReply *DapRpcSocket::sendMessage(const DapRpcMessage &asMessage) +{ + if (!m_pDevice) { + qJsonRpcDebug() << "trying to send message without device"; + return nullptr; + } + + notify(asMessage); + QPointer<DapRpcServiceReply> reply(new DapRpcServiceReply); + reply->setRequest(asMessage); + m_replies.insert(asMessage.id(), reply); + return reply; +} + +void DapRpcSocket::notify(const DapRpcMessage &asMessage) +{ + if (!m_pDevice) { + qJsonRpcDebug() << "trying to send message without device"; + return; + } + + DapRpcService *service = qobject_cast<DapRpcService*>(sender()); + if (service) + disconnect(service, SIGNAL(result(DapRpcMessage)), this, SLOT(notify(DapRpcMessage))); + + writeData(asMessage); +} + +DapRpcMessage DapRpcSocket::invokeRemoteMethodBlocking(const QString &asMethod, int aMsecs, const QVariant ¶m1, + const QVariant ¶m2, const QVariant ¶m3, + const QVariant ¶m4, const QVariant ¶m5, + const QVariant ¶m6, const QVariant ¶m7, + const QVariant ¶m8, const QVariant ¶m9, + const QVariant ¶m10) +{ + QVariantList params; + if (param1.isValid()) params.append(param1); + if (param2.isValid()) params.append(param2); + if (param3.isValid()) params.append(param3); + if (param4.isValid()) params.append(param4); + if (param5.isValid()) params.append(param5); + if (param6.isValid()) params.append(param6); + if (param7.isValid()) params.append(param7); + if (param8.isValid()) params.append(param8); + if (param9.isValid()) params.append(param9); + if (param10.isValid()) params.append(param10); + + DapRpcMessage request = + DapRpcMessage::createRequest(asMethod, QJsonArray::fromVariantList(params)); + return sendMessageBlocking(request, aMsecs); +} + +DapRpcMessage DapRpcSocket::invokeRemoteMethodBlocking(const QString &asMethod, const QVariant ¶m1, + const QVariant ¶m2, const QVariant ¶m3, + const QVariant ¶m4, const QVariant ¶m5, + const QVariant ¶m6, const QVariant ¶m7, + const QVariant ¶m8, const QVariant ¶m9, + const QVariant ¶m10) +{ + return invokeRemoteMethodBlocking(asMethod, m_defaultRequestTimeout, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); +} + +DapRpcServiceReply *DapRpcSocket::invokeRemoteMethod(const QString &asMethod, const QVariant ¶m1, + const QVariant ¶m2, const QVariant ¶m3, + const QVariant ¶m4, const QVariant ¶m5, + const QVariant ¶m6, const QVariant ¶m7, + const QVariant ¶m8, const QVariant ¶m9, + const QVariant ¶m10) +{ + QVariantList params; + if (param1.isValid()) params.append(param1); + if (param2.isValid()) params.append(param2); + if (param3.isValid()) params.append(param3); + if (param4.isValid()) params.append(param4); + if (param5.isValid()) params.append(param5); + if (param6.isValid()) params.append(param6); + if (param7.isValid()) params.append(param7); + if (param8.isValid()) params.append(param8); + if (param9.isValid()) params.append(param9); + if (param10.isValid()) params.append(param10); + + DapRpcMessage request = + DapRpcMessage::createRequest(asMethod, QJsonArray::fromVariantList(params)); + return invokeRemoteMethod(request); +} + +DapRpcServiceReply *DapRpcSocket::invokeRemoteMethod(const DapRpcMessage &message) +{ + return sendMessage(message); +} + +void DapRpcSocket::processIncomingData() +{ + if (!m_pDevice) { + qJsonRpcDebug() << "called without device"; + return; + } + + m_aBuffer.append(m_pDevice.data()->readAll()); + while (!m_aBuffer.isEmpty()) { + int dataSize = findJsonDocumentEnd(m_aBuffer); + if (dataSize == -1) { + return; + } + + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(m_aBuffer.mid(0, dataSize + 1), &error); + if (document.isEmpty()) { + if (error.error != QJsonParseError::NoError) { + qJsonRpcDebug() << error.errorString(); + } + + break; + } + + m_aBuffer = m_aBuffer.mid(dataSize + 1); + if (document.isArray()) { + qJsonRpcDebug() << "bulk support is current disabled"; + } else if (document.isObject()){ + qJsonRpcDebug() << "received: " << document.toJson(QJsonDocument::Compact); + DapRpcMessage message = DapRpcMessage::fromObject(document.object()); + Q_EMIT messageReceived(message); + if (message.type() == DapRpcMessage::Response || + message.type() == DapRpcMessage::Error) { + if (m_replies.contains(message.id())) { + QPointer<DapRpcServiceReply> reply = m_replies.take(message.id()); + if (!reply.isNull()) { + reply->setResponse(message); + reply->finished(); + } + } + } else { + processRequestMessage(message); + } + } + } +} + +void DapRpcSocket::setIODevice(QIODevice *pDevice) +{ + m_pDevice = pDevice; + connect(m_pDevice, SIGNAL(readyRead()), this, SLOT(processIncomingData())); +} + +void DapRpcSocket::processRequestMessage(const DapRpcMessage &asMessage) +{ + processMessage(this, asMessage); +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcSocket.h b/chain/wallet/dapRPCProtocol/DapRpcSocket.h new file mode 100644 index 0000000000000000000000000000000000000000..52aff7ac768a97759e38996ba1c4a552a07dbc99 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcSocket.h @@ -0,0 +1,157 @@ +#ifndef DapRPCSOCKET_H +#define DapRPCSOCKET_H + +#include <QObject> +#include <QIODevice> +#include <QPointer> +#include <QTimer> +#include <QEventLoop> +#include <QDebug> +#include <QJsonDocument> + +#include "DapRpcServiceProvider.h" +#include "DapRpcMessage.h" +#include "DapRpcServiceReply.h" + +#define DEFAULT_MSECS_REQUEST_TIMEOUT (30000) + +/** + * @brief The DapRpcSocket class + * Realization socket interface: + * - Store information about device and data + * - Sending/receiving messages + * - Control sending request by timeout + */ +class DapRpcSocket : public QObject, public DapRpcServiceProvider +{ + Q_OBJECT + Q_DISABLE_COPY(DapRpcSocket) + + /// Pointer to IO device + QPointer<QIODevice> m_pDevice; + /// Buffer + QByteArray m_aBuffer; + /// Storage to replies by id + QHash<int, QPointer<DapRpcServiceReply>> m_replies; + /// Default request timeout + int m_defaultRequestTimeout; + +protected: + /// TODO: not implement + /// @param asMessage Request message + virtual void processRequestMessage(const DapRpcMessage &asMessage); + +public: + /// Standard constructor + explicit DapRpcSocket(QObject *apParent = nullptr); + /// Overloaded constructor + /// @param apDevice Device whick provides both a common implementation and + /// an abstract interface for devices that support reading and writing of blocks of data + explicit DapRpcSocket(QIODevice *apDevice, QObject *apParent = nullptr); + /// Virtual destructor + virtual ~DapRpcSocket(); + + /// Validation initialization and open device + /// @return True if device initilized and opened. Otherwise return false + virtual bool isValid() const; + /// Set default request timeout + /// @param aiMsecs Miliseconds + void setDefaultRequestTimeout(int aiMsecs); + /// Get default request timeout + /// @return Default request timeout + int getDefaultRequestTimeout() const; + /// Set IO Device + /// @param Pointer to IO device + void setIODevice(QIODevice *pDevice); + +signals: + /// The signal emitted when message was received + /// @param asMessage Request message + void messageReceived(const DapRpcMessage &asMessage); + +private slots: + /// Read data from device and prepare reply + virtual void processIncomingData(); + /// Find end of Json document + /// @param aJsonData Json data where need to find end + /// @return Index of end json document. If file empty return -1 + int findJsonDocumentEnd(const QByteArray &aJsonData); + /// Write data from message to device + /// @param asMessage Request message + void writeData(const DapRpcMessage &asMessage); + +public slots: + /// Notify to new request message and try to send to device + /// @param asMessage Request message + virtual void notify(const DapRpcMessage &asMessage); + /// Send message with delay for sending message + /// @param asMessage Request message + /// @param aMsecs Delay request timeout. If not pass parameter uses default value + /// @return Response from reply + virtual DapRpcMessage sendMessageBlocking(const DapRpcMessage &asMessage, int aMsecs = DEFAULT_MSECS_REQUEST_TIMEOUT); + /// Send request message to device + /// @param asMessage Request message + /// @return Pointer of service reply + virtual DapRpcServiceReply *sendMessage(const DapRpcMessage &asMessage); + /// Invoke remote method and create response to send to IO device with delay + /// @param asMethod Method's name + /// @param aMsecs Delay time for send + /// @param arg1 First argument + /// @param arg2 Second argument + /// @param arg3 Third argument + /// @param arg4 Fourth argument + /// @param arg5 Fifth argument + /// @param arg6 Six argument + /// @param arg7 Seven argument + /// @param arg8 Eight argument + /// @param arg9 Nine argument + /// @param arg10 Ten argument + /// @return Response from reply + DapRpcMessage invokeRemoteMethodBlocking(const QString &asMethod, int aMsecs, const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Invoke remote method and create response to send to IO device with default delay time + /// @param asMethod Method's name + /// @param arg1 First argument + /// @param arg2 Second argument + /// @param arg3 Third argument + /// @param arg4 Fourth argument + /// @param arg5 Fifth argument + /// @param arg6 Six argument + /// @param arg7 Seven argument + /// @param arg8 Eight argument + /// @param arg9 Nine argument + /// @param arg10 Ten argument + /// @return Response from reply + DapRpcMessage invokeRemoteMethodBlocking(const QString &asMethod, const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Invoke remote method and create response to send to IO device + /// @param asMethod Method's name + /// @param arg1 First argument + /// @param arg2 Second argument + /// @param arg3 Third argument + /// @param arg4 Fourth argument + /// @param arg5 Fifth argument + /// @param arg6 Six argument + /// @param arg7 Seven argument + /// @param arg8 Eight argument + /// @param arg9 Nine argument + /// @param arg10 Ten argument + /// @return Pointer to service reply + DapRpcServiceReply *invokeRemoteMethod(const QString &asMethod, const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + DapRpcServiceReply *invokeRemoteMethod(const DapRpcMessage &message); +}; + +#endif // DapRPCSOCKET_H diff --git a/chain/wallet/dapRPCProtocol/DapRpcTCPServer.cpp b/chain/wallet/dapRPCProtocol/DapRpcTCPServer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad70badf24abf81a1512c99f3f8d7e5b632c1591 --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcTCPServer.cpp @@ -0,0 +1,110 @@ +#include "DapRpcTCPServer.h" + +DapRpcTCPServer::DapRpcTCPServer(QObject *apParent) + : QTcpServer(apParent) +{ + +} + +DapRpcServiceReply *DapRpcTCPServer::notifyConnectedClients(const DapRpcMessage &message) +{ + DapRpcAbstractServer::notifyConnectedClients(message); +} + +void DapRpcTCPServer::notifyConnectedClients(const QString &method, const QJsonArray ¶ms) +{ + DapRpcAbstractServer::notifyConnectedClients(method, params); +} + +DapRpcTCPServer::~DapRpcTCPServer() +{ + foreach (QTcpSocket *socket, m_socketLookup.keys()) { + socket->flush(); + socket->deleteLater(); + } + m_socketLookup.clear(); + + foreach (DapRpcSocket *client, m_clients) + client->deleteLater(); + m_clients.clear(); +} + +bool DapRpcTCPServer::listen(const QString &asAddress, quint16 aPort) +{ + return ((asAddress.isNull() || asAddress.isEmpty()) ? + QTcpServer::listen(QHostAddress::Any, aPort) : + QTcpServer::listen(QHostAddress(asAddress), aPort)); +} + +DapRpcService *DapRpcTCPServer::addService(DapRpcService *apService) +{ + if (!DapRpcServiceProvider::addService(apService)) + return nullptr; + + connect(apService, SIGNAL(notifyConnectedClients(DapRpcMessage)), + this, SLOT(notifyConnectedClients(DapRpcMessage))); + connect(apService, SIGNAL(notifyConnectedClients(QString,QJsonArray)), + this, SLOT(notifyConnectedClients(QString,QJsonArray))); + return apService; +} + +bool DapRpcTCPServer::removeService(DapRpcService *apService) +{ + if (!DapRpcServiceProvider::removeService(apService)) + return false; + + disconnect(apService, SIGNAL(notifyConnectedClients(DapRpcMessage)), + this, SLOT(notifyConnectedClients(DapRpcMessage))); + disconnect(apService, SIGNAL(notifyConnectedClients(QString,QJsonArray)), + this, SLOT(notifyConnectedClients(QString,QJsonArray))); + return true; +} + +void DapRpcTCPServer::clientDisconnected() +{ + QTcpSocket *tcpSocket = static_cast<QTcpSocket*>(sender()); + if (!tcpSocket) { + qJsonRpcDebug() << "called with invalid socket"; + return; + } + + if (m_socketLookup.contains(tcpSocket)) { + DapRpcSocket *socket = m_socketLookup.take(tcpSocket); + m_clients.removeAll(socket); + socket->deleteLater(); + } + + tcpSocket->deleteLater(); + emit onClientDisconnected(); +} + +void DapRpcTCPServer::messageProcessing(const DapRpcMessage &asMessage) +{ + DapRpcSocket *socket = static_cast<DapRpcSocket*>(sender()); + if (!socket) { + qJsonRpcDebug() << "called without service socket"; + return; + } + + processMessage(socket, asMessage); +} + +void DapRpcTCPServer::incomingConnection(qintptr aSocketDescriptor) +{ + QTcpSocket *tcpSocket = new QTcpSocket(this); + if (!tcpSocket->setSocketDescriptor(aSocketDescriptor)) + { + qJsonRpcDebug() << "can't set socket descriptor"; + tcpSocket->deleteLater(); + return; + } + + QIODevice *device = qobject_cast<QIODevice*>(tcpSocket); + DapRpcSocket *socket = new DapRpcSocket(device, this); + connect(socket, SIGNAL(messageReceived(DapRpcMessage)), + this, SLOT(_q_processMessage(DapRpcMessage))); + m_clients.append(socket); + connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(_q_clientDisconnected())); + m_socketLookup.insert(tcpSocket, socket); + emit onClientConnected(); +} diff --git a/chain/wallet/dapRPCProtocol/DapRpcTCPServer.h b/chain/wallet/dapRPCProtocol/DapRpcTCPServer.h new file mode 100644 index 0000000000000000000000000000000000000000..e2b0c59d5f43a9789fb52cc6ad18b6ccdf94683b --- /dev/null +++ b/chain/wallet/dapRPCProtocol/DapRpcTCPServer.h @@ -0,0 +1,76 @@ +#ifndef DapRPCTCPSERVER_H +#define DapRPCTCPSERVER_H + +#include <QObject> +#include <QTcpSocket> +#include <QTcpServer> + +#include "DapRpcSocket.h" +#include "DapRpcAbstractServer.h" + +/** + * @brief The DapRpcTCPServer class + * TCP server class realize interface DapRpcAbstractServer + * @see DapRpcAbstractServer + * @see QTcpServer + */ +class DapRpcTCPServer : public QTcpServer, public DapRpcAbstractServer +{ + Q_OBJECT + Q_DISABLE_COPY(DapRpcTCPServer) + /// Lookup's tcp sockets witj Rpc sockets + QHash<QTcpSocket*, DapRpcSocket*> m_socketLookup; + +protected: + /// This virtual function is called by QTcpServer when a new connection is available + /// @param aSocketDescriptor The socketDescriptor argument is the native socket + /// descriptor for the accepted connection + virtual void incomingConnection(qintptr aSocketDescriptor); + +public: + /// Standard constructor + explicit DapRpcTCPServer(QObject *apParent = nullptr); + /// Virtual destructor + virtual ~DapRpcTCPServer(); + + /// Tells the server to listen for incoming connections on address + /// @param asAddress Address + /// @param aPort Port. If port is 0, a port is chosen automatically + /// @param If address is QHostAddress::Any, the server will listen on all network interfaces + /// @return Returns true on success; otherwise returns false. + /// @see isListening() + virtual bool listen(const QString &asAddress = QString(), quint16 aPort = 0); + /// Add new service + /// @param apService New service + /// @return If service add successfully return true. Otherwise return false + DapRpcService * addService(DapRpcService *apService); + /// Remove service + /// @param apService Service for removing + /// @return If service add successfully return true. Otherwise return false + bool removeService(DapRpcService *apService); + +signals: + /// The signal is emitted when client was connected + void onClientConnected(); + /// The signal is emitted when client was disconnected + void onClientDisconnected(); + +protected slots: + /// Calls when client disconnected + void clientDisconnected(); + /// When receive message from client prepare message by type of message + /// @param asMessage Message + void messageProcessing(const DapRpcMessage &asMessage); + + // DapRpcAbstractServer interface +public slots: + /// Notify connected clients. Send all message + /// @param message Message to client + DapRpcServiceReply* notifyConnectedClients(const DapRpcMessage &message); + /// Notify connected clients. Send all message + /// @param method Method which clients were notified + /// @param params Parameters of message in JSON format + void notifyConnectedClients(const QString &method, const QJsonArray ¶ms); +}; + +#endif // DapRPCTCPSERVER_H diff --git a/chain/wallet/handlers/DapAbstractCommand.cpp b/chain/wallet/handlers/DapAbstractCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa1ab2217feaf02a2a20bd636b82fc99528f3d02 --- /dev/null +++ b/chain/wallet/handlers/DapAbstractCommand.cpp @@ -0,0 +1,232 @@ +#include "DapAbstractCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapAbstractCommand::DapAbstractCommand(const QString &asServiceName, QObject *parent, const QString &asCliPath) + : DapCommand(asServiceName, parent), m_parent(parent), m_sCliPath(asCliPath) +{ + +} + +/// Send a notification to the client. At the same time, you should not expect a response from the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +void DapAbstractCommand::notifyToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + QVariantList params; + if (arg1.isValid()) params.append(arg1); + if (arg2.isValid()) params.append(arg2); + if (arg3.isValid()) params.append(arg3); + if (arg4.isValid()) params.append(arg4); + if (arg5.isValid()) params.append(arg5); + if (arg6.isValid()) params.append(arg6); + if (arg7.isValid()) params.append(arg7); + if (arg8.isValid()) params.append(arg8); + if (arg9.isValid()) params.append(arg9); + if (arg10.isValid()) params.append(arg10); + + DapRpcLocalServer * server = dynamic_cast<DapRpcLocalServer *>(m_parent); + + Q_ASSERT(server); + + DapRpcMessage request = DapRpcMessage::createNotification(QString("%1.%2").arg(this->getName()).arg("notifedFromService"), QJsonArray::fromVariantList(params)); + server->notifyConnectedClients(request); +} + +/// Process the notification from the service on the client side. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +void DapAbstractCommand::notifedFromService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1); + Q_UNUSED(arg2); + Q_UNUSED(arg3); + Q_UNUSED(arg4); + Q_UNUSED(arg5); + Q_UNUSED(arg6); + Q_UNUSED(arg7); + Q_UNUSED(arg8); + Q_UNUSED(arg9); + Q_UNUSED(arg10); + + emit clientNotifed(QVariant()); +} + +/// Send request to client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +void DapAbstractCommand::requestToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + QVariantList params; + if (arg1.isValid()) params.append(arg1); + if (arg2.isValid()) params.append(arg2); + if (arg3.isValid()) params.append(arg3); + if (arg4.isValid()) params.append(arg4); + if (arg5.isValid()) params.append(arg5); + if (arg6.isValid()) params.append(arg6); + if (arg7.isValid()) params.append(arg7); + if (arg8.isValid()) params.append(arg8); + if (arg9.isValid()) params.append(arg9); + if (arg10.isValid()) params.append(arg10); + + DapRpcLocalServer * server = dynamic_cast<DapRpcLocalServer *>(m_parent); + + Q_ASSERT(server); + + DapRpcMessage request = DapRpcMessage::createRequest(QString("%1.%2").arg(this->getName()).arg("respondToService"), QJsonArray::fromVariantList(params)); + DapRpcServiceReply * reply = server->notifyConnectedClients(request); + connect(reply, SIGNAL(finished()), this, SLOT(replyFromClient())); +} + +/// Send a response to the service. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +/// @return Reply to service. +QVariant DapAbstractCommand::respondToService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + return QVariant(); +} + +/// Reply from client. +/// @details Performed on the service side. +/// @return Client reply. +QVariant DapAbstractCommand::replyFromClient() +{ + DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); + emit clientResponded(reply->response().toJsonValue().toVariant()); + return QVariant(); +} + +/// Send a notification to the service. At the same time, you should not expect a response from the service. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +void DapAbstractCommand::notifyToService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + QVariantList params; + if (arg1.isValid()) params.append(arg1); + if (arg2.isValid()) params.append(arg2); + if (arg3.isValid()) params.append(arg3); + if (arg4.isValid()) params.append(arg4); + if (arg5.isValid()) params.append(arg5); + if (arg6.isValid()) params.append(arg6); + if (arg7.isValid()) params.append(arg7); + if (arg8.isValid()) params.append(arg8); + if (arg9.isValid()) params.append(arg9); + if (arg10.isValid()) params.append(arg10); + + DapRpcSocket * socket = dynamic_cast<DapRpcSocket *>(m_parent); + + Q_ASSERT(socket); + + DapRpcMessage notify = DapRpcMessage::createNotification(QString("%1.%2").arg(this->getName()).arg("notifedFromClient"), QJsonArray::fromVariantList(params)); + socket->notify(notify); +} + +/// Process the notification from the client on the service side. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +void DapAbstractCommand::notifedFromClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1); + Q_UNUSED(arg2); + Q_UNUSED(arg3); + Q_UNUSED(arg4); + Q_UNUSED(arg5); + Q_UNUSED(arg6); + Q_UNUSED(arg7); + Q_UNUSED(arg8); + Q_UNUSED(arg9); + Q_UNUSED(arg10); + + emit serviceNotifed(QVariant()); +} + +/// Send request to service. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +void DapAbstractCommand::requestToService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, + const QVariant &arg6, const QVariant &arg7, + const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + QVariantList params; + if (arg1.isValid()) params.append(arg1); + if (arg2.isValid()) params.append(arg2); + if (arg3.isValid()) params.append(arg3); + if (arg4.isValid()) params.append(arg4); + if (arg5.isValid()) params.append(arg5); + if (arg6.isValid()) params.append(arg6); + if (arg7.isValid()) params.append(arg7); + if (arg8.isValid()) params.append(arg8); + if (arg9.isValid()) params.append(arg9); + if (arg10.isValid()) params.append(arg10); + + DapRpcServiceReply *reply = dynamic_cast<DapRpcSocket *>(m_parent)->invokeRemoteMethod(QString("%1.%2").arg(this->getName()).arg("respondToClient"), + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + connect(reply, SIGNAL(finished()), this, SLOT(replyFromService())); +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapAbstractCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + return QVariant(); +} + +/// Reply from service. +/// @details Performed on the service side. +/// @return Service reply. +QVariant DapAbstractCommand::replyFromService() +{ + DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); + + emit serviceResponded(reply->response().toJsonValue().toVariant()); + + return reply->response().toJsonValue().toVariant(); +} diff --git a/chain/wallet/handlers/DapAbstractCommand.h b/chain/wallet/handlers/DapAbstractCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..70b2d9825095e430483ddaf5f0e8e4220b648777 --- /dev/null +++ b/chain/wallet/handlers/DapAbstractCommand.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** This file is part of the libdap-qt-ui-chain-wallet library. +** +** The class implements the command interface. +** +****************************************************************************/ + +#ifndef DAPABSTRACTCOMMAND_H +#define DAPABSTRACTCOMMAND_H + +#include <QObject> +#include <QVariant> + +#include "DapRpcSocket.h" +#include "DapRpcLocalServer.h" + +typedef DapRpcService DapCommand; + +class DapAbstractCommand : public DapCommand +{ + Q_OBJECT + +protected: + /// Parent. + QObject * m_parent {nullptr}; + /// The path to cli nodes. + QString m_sCliPath; + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + explicit DapAbstractCommand(const QString &asServiceName, QObject *parent = nullptr, const QString &asCliPath = QString()); + +signals: + /// The signal is emitted in case of successful notification of the client by the service. + /// @param aNotify Notification. + void clientNotifed(const QVariant& aNotify); + /// The signal is emitted if the client has successfully received + /// a request from the service and responded to the service. + /// @param asRespond Client response. + void clientResponded(const QVariant& aRespond); + /// The signal is emitted if the client successfully notifies the service. + /// @param aNotify Notification. + void serviceNotifed(const QVariant& aNotify); + /// The signal is emitted if the service has successfully received + /// a request from the client and responded to the client + /// @param asRespond Service response. + void serviceResponded(const QVariant& aRespond); + +public slots: + /// Send a notification to the client. At the same time, you should not expect a response from the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifyToClient(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Process the notification from the service on the client side. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifedFromService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Send request to client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void requestToClient(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Send a response to the service. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + /// @return Reply to service. + virtual QVariant respondToService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Reply from client. + /// @details Performed on the service side. + /// @return Client reply. + virtual QVariant replyFromClient(); + + /// Send a notification to the service. At the same time, you should not expect a response from the service. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifyToService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Process the notification from the client on the service side. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifedFromClient(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Send request to service. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void requestToService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + virtual QVariant respondToClient(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()); + /// Reply from service. + /// @details Performed on the service side. + /// @return Service reply. + virtual QVariant replyFromService(); +}; + +#endif // DAPABSTRACTCOMMAND_H diff --git a/chain/wallet/handlers/DapActivateClientCommand.cpp b/chain/wallet/handlers/DapActivateClientCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c1a2fa9c1b5569725a66486deba392ad637912a --- /dev/null +++ b/chain/wallet/handlers/DapActivateClientCommand.cpp @@ -0,0 +1,13 @@ +#include "DapActivateClientCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +DapActivateClientCommand::DapActivateClientCommand(const QString &asServicename, QObject *parent) + : DapAbstractCommand(asServicename, parent) +{ + +} + + diff --git a/chain/wallet/handlers/DapActivateClientCommand.h b/chain/wallet/handlers/DapActivateClientCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..05e8f1c4ea8dbee484c77fe923488404eb4d5e5e --- /dev/null +++ b/chain/wallet/handlers/DapActivateClientCommand.h @@ -0,0 +1,28 @@ +/**************************************************************************** +** +** This file is part of the libdap-qt-ui-chain-wallet library. +** +** The class implements the command to activate the GUI client. That is, +** by clicking on the icon in the system tray, the main window of the GUI +** client is minimized / expanded. +** +****************************************************************************/ + +#ifndef DAPACTIVATECLIENTCOMMAND_H +#define DAPACTIVATECLIENTCOMMAND_H + +#include <QObject> + +#include "DapAbstractCommand.h" + +class DapActivateClientCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + DapActivateClientCommand(const QString &asServicename, QObject *parent = nullptr); +}; + +#endif // DAPACTIVATECLIENTCOMMAND_H diff --git a/chain/wallet/handlers/DapAddWalletCommand.cpp b/chain/wallet/handlers/DapAddWalletCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0570ed61330ca8ef27b7ac0d7a97740f84b0e51c --- /dev/null +++ b/chain/wallet/handlers/DapAddWalletCommand.cpp @@ -0,0 +1,46 @@ +#include "DapAddWalletCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +DapAddWalletCommand::DapAddWalletCommand(const QString &asServicename, QObject *parent) + : DapAbstractCommand(asServicename, parent) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapAddWalletCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QProcess process; + QJsonArray result; + process.start(QString("%1 wallet new -w %2 -sign %3 -net %4 -restore %5").arg(CLI_PATH).arg(arg1.toString()).arg(arg2.toString()).arg(arg3.toString()).arg(arg4.toString())); + process.waitForFinished(-1); + QString resources = QString::fromLatin1(process.readAll()); + if(resources.contains("already exists")) + { + result.append(QJsonValue(false)); + result.append(QJsonValue("Wallet already exists")); + } + else + { + result.append(QJsonValue(true)); + result.append(QJsonValue(arg1.toString())); + result.append(QJsonValue("Wallet successfully created")); + } + return result.toVariantList(); +} diff --git a/chain/wallet/handlers/DapAddWalletCommand.h b/chain/wallet/handlers/DapAddWalletCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..f76cc0d6e6cbe0ef46b46b4655bebdbb109828d7 --- /dev/null +++ b/chain/wallet/handlers/DapAddWalletCommand.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** This file is part of the libdap-qt-ui-chain-wallet library. +** +** The class implements the functionality of creating a new wallet. +** +****************************************************************************/ + +#ifndef DAPADDWALLETCOMMAND_H +#define DAPADDWALLETCOMMAND_H + +#include <QProcess> +#include <QString> + +#include "DapAbstractCommand.h" + +class DapAddWalletCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + explicit DapAddWalletCommand(const QString &asServicename, QObject *parent = nullptr); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()); +}; + +#endif // DAPADDWALLETCOMMAND_H diff --git a/chain/wallet/handlers/DapCreateTransactionCommand.cpp b/chain/wallet/handlers/DapCreateTransactionCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba563b0ebb604d63119a5fa81279a9ccc2c9a011 --- /dev/null +++ b/chain/wallet/handlers/DapCreateTransactionCommand.cpp @@ -0,0 +1,51 @@ +#include "DapCreateTransactionCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapCreateTransactionCommand::DapCreateTransactionCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1 Network. +/// @param arg2 Chain. +/// @param arg3 Wallet sender. +/// @param arg4 Recipient's wallet address. +/// @param arg5 Token. +/// @param arg6 Transfer amount. +/// @return Reply to client. +QVariant DapCreateTransactionCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QProcess processCreate; + processCreate.start(QString("%1 tx_create -net %2 -chain %3 -from_wallet %4 -to_addr %5 -token %6 -value %7") + .arg(m_sCliPath) + .arg(arg1.toString()) + .arg(arg2.toString()) + .arg(arg3.toString()) + .arg(arg4.toString()) + .arg(arg5.toString()) + .arg(arg6.toString())); + + processCreate.waitForFinished(-1); + QByteArray result = processCreate.readAll(); + + QRegExp rx("transfer=(\\w+)"); + rx.indexIn(result, 0); + + if(rx.cap(1) == "Ok") + { + return true; + } + return false; +} diff --git a/chain/wallet/handlers/DapCreateTransactionCommand.h b/chain/wallet/handlers/DapCreateTransactionCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..de3ec67440b7e3179b851c01150a7b368684b84f --- /dev/null +++ b/chain/wallet/handlers/DapCreateTransactionCommand.h @@ -0,0 +1,35 @@ +#ifndef DAPCREATETRANSACTIONCOMMAND_H +#define DAPCREATETRANSACTIONCOMMAND_H + +#include <QProcess> + +#include "DapAbstractCommand.h" + +class DapCreateTransactionCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapCreateTransactionCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1 Network. + /// @param arg2 Chain. + /// @param arg3 Wallet sender. + /// @param arg4 Recipient's wallet address. + /// @param arg5 Token. + /// @param arg6 Transfer amount. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPCREATETRANSACTIONCOMMAND_H diff --git a/chain/wallet/handlers/DapExportLogCommand.cpp b/chain/wallet/handlers/DapExportLogCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f26d85d8d9a34494fab73e499bfd38253844423 --- /dev/null +++ b/chain/wallet/handlers/DapExportLogCommand.cpp @@ -0,0 +1,42 @@ +#include "DapExportLogCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param apSocket Client connection socket with service. +/// @param parent Parent. +DapExportLogCommand::DapExportLogCommand(const QString &asServicename, QObject *parent) + : DapAbstractCommand(asServicename, parent) +{ + +} + +/// Send a response to the client. +/// A log file is saved from the GUI window. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapExportLogCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QFile saveDapLog(arg1.toString()); + if (!saveDapLog.open(QIODevice::WriteOnly | QIODevice::Text)) + { + qCritical("The file does not write."); + return false; + } + QTextStream saveLog(&saveDapLog); + saveLog << arg2.toString(); + + saveDapLog.close(); + return QVariant(); +} diff --git a/chain/wallet/handlers/DapExportLogCommand.h b/chain/wallet/handlers/DapExportLogCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..79d21af12cbdeb94dd3c6e20848c21577cd7b789 --- /dev/null +++ b/chain/wallet/handlers/DapExportLogCommand.h @@ -0,0 +1,30 @@ +#ifndef DAPSAVELOGCOMMAND_H +#define DAPSAVELOGCOMMAND_H + +#include <QFile> + +#include "DapAbstractCommand.h" + +class DapExportLogCommand : public DapAbstractCommand +{ + +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param apSocket Client connection socket with service. + /// @param parent Parent. + explicit DapExportLogCommand(const QString &asServicename, QObject *parent = nullptr); + +public slots: + /// Send a response to the client. + /// /// A log file is saved from the GUI window. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPSAVELOGCOMMAND_H diff --git a/chain/wallet/handlers/DapGetHistoryExecutedCmdCommand.cpp b/chain/wallet/handlers/DapGetHistoryExecutedCmdCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c10cb29d4cb923e38c1a2312bcd22d8ca192748 --- /dev/null +++ b/chain/wallet/handlers/DapGetHistoryExecutedCmdCommand.cpp @@ -0,0 +1,48 @@ +#include "DapGetHistoryExecutedCmdCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapGetHistoryExecutedCmdCommand::DapGetHistoryExecutedCmdCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + DapRpcLocalServer * server = dynamic_cast<DapRpcLocalServer *>(m_parent); + if(server) + { + QDir().mkpath(QFileInfo(asCliPath).path()); + m_File = new QFile(asCliPath, this); + } +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetHistoryExecutedCmdCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QJsonArray historyExecutedCmd; + + if(!m_File->open(QIODevice::ReadOnly | QIODevice::Text)) + return historyExecutedCmd; + + while (!m_File->atEnd()) + { + historyExecutedCmd.append(QJsonValue(QString::fromLatin1(m_File->readLine()).trimmed())); + } + m_File->close(); + + return historyExecutedCmd; +} diff --git a/chain/wallet/handlers/DapGetHistoryExecutedCmdCommand.h b/chain/wallet/handlers/DapGetHistoryExecutedCmdCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..df760d1996b50aa4cd06c6e887ce329a0c7ab5e9 --- /dev/null +++ b/chain/wallet/handlers/DapGetHistoryExecutedCmdCommand.h @@ -0,0 +1,35 @@ +#ifndef DAPGETHISTORYEXECUTEDCMDCOMMAND_H +#define DAPGETHISTORYEXECUTEDCMDCOMMAND_H + +#include <QProcess> +#include <QFile> +#include <QDir> + +#include "DapAbstractCommand.h" + +class DapGetHistoryExecutedCmdCommand : public DapAbstractCommand +{ + /// Command history file. + QFile * m_File {nullptr}; + +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapGetHistoryExecutedCmdCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPGETHISTORYEXECUTEDCMDCOMMAND_H diff --git a/chain/wallet/handlers/DapGetListNetworksCommand.cpp b/chain/wallet/handlers/DapGetListNetworksCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79adcecf8b2947390c21cf6774b0d0e87afa07fd --- /dev/null +++ b/chain/wallet/handlers/DapGetListNetworksCommand.cpp @@ -0,0 +1,42 @@ +#include "DapGetListNetworksCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapGetListNetworksCommand::DapGetListNetworksCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetListNetworksCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QStringList networkList; + QProcess process; + process.start(QString("%1 net list").arg(m_sCliPath)); + process.waitForFinished(-1); + QString result = QString::fromLatin1(process.readAll()); + if(!(result.isEmpty() || result.isNull() || result.contains('\''))) + { + QStringList str = result.remove(" ").remove("\n").remove("\r").split(":").at(1).split(","); + return str; + } + return QString(); +} diff --git a/chain/wallet/handlers/DapGetListNetworksCommand.h b/chain/wallet/handlers/DapGetListNetworksCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..ecfac60c62c7b9860819dedf65c0d68b35e993d0 --- /dev/null +++ b/chain/wallet/handlers/DapGetListNetworksCommand.h @@ -0,0 +1,30 @@ +#ifndef DAPGETLISTNETWORKSCOMMAND_H +#define DAPGETLISTNETWORKSCOMMAND_H + +#include <QProcess> + +#include "DapAbstractCommand.h" + +class DapGetListNetworksCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapGetListNetworksCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPGETLISTNETWORKSCOMMAND_H diff --git a/chain/wallet/handlers/DapGetListWalletsCommand.cpp b/chain/wallet/handlers/DapGetListWalletsCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2f514ecbd91ad60720937c6b0aac0817f266b12 --- /dev/null +++ b/chain/wallet/handlers/DapGetListWalletsCommand.cpp @@ -0,0 +1,49 @@ +#include "DapGetListWalletsCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapGetListWalletsCommand::DapGetListWalletsCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetListWalletsCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QStringList wallets; + + QProcess process; + process.start(QString("%1 wallet list").arg(m_sCliPath)); + process.waitForFinished(-1); + QString resources = QString::fromLocal8Bit(process.readAll()); + QRegularExpression rx("wallet:\\s(.+)\\s", QRegularExpression::MultilineOption); + QRegularExpressionMatchIterator itr = rx.globalMatch(resources); + while (itr.hasNext()) + { + QRegularExpressionMatch match = itr.next(); + wallets.append(match.captured(1)); + } + + return wallets; +} diff --git a/chain/wallet/handlers/DapGetListWalletsCommand.h b/chain/wallet/handlers/DapGetListWalletsCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..9805de41151c81d0f77cd7cea27289db5c0470ef --- /dev/null +++ b/chain/wallet/handlers/DapGetListWalletsCommand.h @@ -0,0 +1,34 @@ +#ifndef DAPGETLISTWALLETSCOMMAND_H +#define DAPGETLISTWALLETSCOMMAND_H + +#include <QProcess> +#include <QRegExp> +#include <QRegularExpression> +#include <QByteArray> + +#include "DapWallet.h" +#include "DapAbstractCommand.h" + +class DapGetListWalletsCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapGetListWalletsCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPGETLISTWALLETSCOMMAND_H diff --git a/chain/wallet/handlers/DapGetWalletAddressesCommand.cpp b/chain/wallet/handlers/DapGetWalletAddressesCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc42b0be9a084eda789e2ceacef1dae432c33c5d --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletAddressesCommand.cpp @@ -0,0 +1,68 @@ +#include "DapGetWalletAddressesCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +DapGetWalletAddressesCommand::DapGetWalletAddressesCommand(const QString &asServicename, QObject *parent) + : DapAbstractCommand(asServicename, parent) +{ + +} + +/// Send request to service. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +void DapGetWalletAddressesCommand::requestToService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, + const QVariant &arg6, const QVariant &arg7, + const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + + DapAbstractCommand::requestToService(arg1, arg2.toStringList(), arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetWalletAddressesCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QStringList walletAddress; + QStringList networkList = arg2.toStringList(); + if(!networkList.isEmpty()) + { + for(int i{0}; i < networkList.count(); ++i) + { + QProcess process; + process.start(QString("%1 wallet info -w %2 -net %3").arg(CLI_PATH).arg(arg1.toString()).arg(networkList[i])); + process.waitForFinished(-1); + QByteArray result = process.readAll(); + QRegExp regex("wallet: (.+)\\s+addr:\\s+(.+)\\s+(balance)|(\\d+.\\d+)\\s\\((\\d+)\\)\\s(\\w+)"); + + int pos = 0; + while((pos = regex.indexIn(result, pos)) != -1) + { + if(!regex.cap(2).isEmpty()) + { + walletAddress.append(networkList[i]); + walletAddress.append(regex.cap(2)); + } + pos += regex.matchedLength(); + } + } + } + + return walletAddress; +} diff --git a/chain/wallet/handlers/DapGetWalletAddressesCommand.h b/chain/wallet/handlers/DapGetWalletAddressesCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..adb8541f0be4b76ad7bdeef41de8f7a51fa55607 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletAddressesCommand.h @@ -0,0 +1,38 @@ +#ifndef DAPGETWALLETADDRESSESCOMMAND_H +#define DAPGETWALLETADDRESSESCOMMAND_H + +#include <QProcess> + +#include "DapAbstractCommand.h" + +class DapGetWalletAddressesCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + DapGetWalletAddressesCommand(const QString &asServicename, QObject *parent = nullptr); + +public slots: + /// Send request to service. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void requestToService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()) override; + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPGETWALLETADDRESSESCOMMAND_H diff --git a/chain/wallet/handlers/DapGetWalletHistoryCommand.cpp b/chain/wallet/handlers/DapGetWalletHistoryCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5007026c6647ebdb9d0019bb1bb11a43bea25d91 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletHistoryCommand.cpp @@ -0,0 +1,63 @@ +#include "DapGetWalletHistoryCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapGetWalletHistoryCommand::DapGetWalletHistoryCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1 Network. +/// @param arg2 Chain. +/// @param arg3 Wallet address. +/// @param arg4...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetWalletHistoryCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QList<DapWalletHistoryEvent> events; + QProcess process; + process.start(QString("%1 tx_history -net %2 -chain %3 -addr %4").arg(m_sCliPath).arg(arg1.toString()).arg(arg2.toString()).arg(arg3.toString())); + process.waitForFinished(-1); + QByteArray result = process.readAll(); + if(!result.isEmpty()) + { + QRegularExpression regular("((\\w{3}\\s+){2}\\d{1,2}\\s+(\\d{1,2}:*){3}\\s+\\d{4})\\s+(\\w+)\\s+(\\d+)\\s(\\w+)\\s+\\w+\\s+([\\w\\d]+)", QRegularExpression::MultilineOption); + QRegularExpressionMatchIterator matchItr = regular.globalMatch(result); + + while (matchItr.hasNext()) + { + DapWalletHistoryEvent event; + QRegularExpressionMatch match = matchItr.next(); + QLocale setLocale = QLocale(QLocale::English, QLocale::UnitedStates); + event.setDate(setLocale.toDateTime(match.captured(1), "ddd MMM d hh:mm:ss yyyy").toString("yyyy-MM-dd")); + event.setStatus(match.captured(4) == "send" ? "Sent" : "Received"); + event.setAmount(match.captured(5).toDouble()); + event.setName(match.captured(6)); + event.setWallet(arg4.toString()); + events.append(event); + } + } + + QByteArray datas; + QDataStream out(&datas, QIODevice::WriteOnly); + out << events; + + return QJsonValue::fromVariant(datas.toHex());; +} diff --git a/chain/wallet/handlers/DapGetWalletHistoryCommand.h b/chain/wallet/handlers/DapGetWalletHistoryCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..cbd1b2983c82c282cca8614b699319c1835402c4 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletHistoryCommand.h @@ -0,0 +1,38 @@ +#ifndef DAPGETWALLETHISTORYCOMMAND_H +#define DAPGETWALLETHISTORYCOMMAND_H + +#include <QProcess> +#include <QRegExp> +#include <QRegularExpression> +#include <QDate> + +#include "DapWallet.h" +#include "DapWalletHistoryEvent.h" +#include "DapAbstractCommand.h" + +class DapGetWalletHistoryCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapGetWalletHistoryCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1 Network. + /// @param arg2 Chain. + /// @param arg3 Wallet address. + /// @param arg4...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPGETWALLETHISTORYCOMMAND_H diff --git a/chain/wallet/handlers/DapGetWalletInfoCommand.cpp b/chain/wallet/handlers/DapGetWalletInfoCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..689a0bcea059fc509c3ad0aa95c15b2ebcdba4f0 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletInfoCommand.cpp @@ -0,0 +1,107 @@ +#include "DapGetWalletInfoCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapGetWalletInfoCommand::DapGetWalletInfoCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetWalletInfoCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QStringList list; + QProcess processGetNetworks; + processGetNetworks.start(QString("%1 net list").arg(m_sCliPath)); + processGetNetworks.waitForFinished(-1); + QString result = QString::fromLatin1(processGetNetworks.readAll()); + result.remove(' '); + if(!(result.isEmpty() || result.isNull() || result.contains('\''))) + { + list = result.remove("\n").remove("\r").split(":").at(1).split(","); + } + + DapWallet wallet; + wallet.setName(arg1.toString()); + auto begin = list.begin(); + auto end = list.end(); + for(; begin != end; ++begin) + { + + wallet.addNetwork(*begin); + + QProcess processGetTokkens; + processGetTokkens.start(QString("%1 wallet info -w %2 -net %3") + .arg(m_sCliPath) + .arg(wallet.getName()) + .arg(*begin)); + + processGetTokkens.waitForFinished(-1); + QByteArray result_tokens = processGetTokkens.readAll(); + QRegExp regex("wallet: (.+)\\s+addr:\\s+(.+)\\s+(balance)|(\\d+.\\d+)\\s\\((\\d+)\\)\\s(\\w+)"); + + int pos = 0; + DapWalletToken *token {nullptr}; + while((pos = regex.indexIn(result_tokens, pos)) != -1) + { + + if(!regex.cap(2).isEmpty()) + { + wallet.addAddress(regex.cap(2), *begin); + } + else + { + token = new DapWalletToken(); + token->setName(regex.cap(6).trimmed()); + token->setBalance(regex.cap(4).toDouble()); + QString str = regex.cap(5); + token->setEmission(regex.cap(5).toULongLong()); + token->setNetwork(*begin); + wallet.addToken(token); + } + + pos += regex.matchedLength(); + } + } + + QByteArray datas; + QDataStream out(&datas, QIODevice::WriteOnly); + out << wallet; + + return QJsonValue::fromVariant(datas.toHex()); +} + + +/// Reply from service. +/// @details Performed on the service side. +/// @return Service reply. +QVariant DapGetWalletInfoCommand::replyFromService() +{ + DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); + + emit serviceResponded(reply->response().toJsonValue().toVariant().toByteArray()); + + return reply->response().toJsonValue().toVariant(); +} + diff --git a/chain/wallet/handlers/DapGetWalletInfoCommand.h b/chain/wallet/handlers/DapGetWalletInfoCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..d92f5a09e1d3e3c4820103aea6a985d31e8bb2cf --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletInfoCommand.h @@ -0,0 +1,37 @@ +#ifndef DAPGETWALLETINFOCOMMAND_H +#define DAPGETWALLETINFOCOMMAND_H + +#include <QProcess> +#include <QRegExp> +#include <QRegularExpression> +#include <QByteArray> +#include <QDataStream> +#include <QBuffer> +#include <QTextCodec> + +#include "DapWallet.h" +#include "DapAbstractCommand.h" + +class DapGetWalletInfoCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapGetWalletInfoCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; + QVariant replyFromService() override; +}; + +#endif // DAPGETWALLETINFOCOMMAND_H diff --git a/chain/wallet/handlers/DapGetWalletTokenInfoCommand.cpp b/chain/wallet/handlers/DapGetWalletTokenInfoCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..276ce00443d300e8b39d6cf662efab5761a39be7 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletTokenInfoCommand.cpp @@ -0,0 +1,53 @@ +#include "DapGetWalletTokenInfoCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +DapGetWalletTokenInfoCommand::DapGetWalletTokenInfoCommand(const QString &asServicename, QObject *parent) + : DapAbstractCommand(asServicename, parent) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetWalletTokenInfoCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QStringList token; + if(!(arg1.toString().isEmpty() || arg1.toString().isNull() + || arg2.toString().isEmpty() || arg2.toString().isNull())) + { + QProcess process; + process.start(QString("%1 wallet info -w %2 -net %3").arg(CLI_PATH).arg(arg1.toString()).arg(arg2.toString())); + process.waitForFinished(-1); + QByteArray result = process.readAll(); + QRegExp regex("wallet: (.+)\\s+addr:\\s+(.+)\\s+(balance)|(\\d+.\\d+)\\s\\((\\d+)\\)\\s(\\w+)"); + + int pos = 0; + while((pos = regex.indexIn(result, pos)) != -1) + { + if(regex.cap(2).isEmpty()) + { + token.append(regex.cap(6)); + token.append(regex.cap(4)); + token.append(regex.cap(5)); + } + pos += regex.matchedLength(); + } + } + + return token; +} diff --git a/chain/wallet/handlers/DapGetWalletTokenInfoCommand.h b/chain/wallet/handlers/DapGetWalletTokenInfoCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..2ceaf209e90e25d93924d28e09ac1157dfc08059 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletTokenInfoCommand.h @@ -0,0 +1,30 @@ +#ifndef DAPGETWALLETTOKENINFOCOMMAND_H +#define DAPGETWALLETTOKENINFOCOMMAND_H + +#include <QProcess> +#include <QRegExp> + +#include "DapAbstractCommand.h" + +class DapGetWalletTokenInfoCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + DapGetWalletTokenInfoCommand(const QString &asServicename, QObject *parent = nullptr); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPGETWALLETTOKENINFOCOMMAND_H diff --git a/chain/wallet/handlers/DapGetWalletsInfoCommand.cpp b/chain/wallet/handlers/DapGetWalletsInfoCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b548e7c021a4fb8d5e03617da350a96c839c592 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletsInfoCommand.cpp @@ -0,0 +1,121 @@ +#include "DapGetWalletsInfoCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapGetWalletsInfoCommand::DapGetWalletsInfoCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +/// @return Reply to client. +QVariant DapGetWalletsInfoCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QList<DapWallet> wallets; + + QStringList list; + QProcess processN; + processN.start(QString("%1 net list").arg(m_sCliPath)); + processN.waitForFinished(-1); + QString result = QString::fromLatin1(processN.readAll()); + result.remove(' '); + if(!(result.isEmpty() || result.isNull() || result.contains('\''))) + { + list = result.remove("\n").remove("\r").split(":").at(1).split(","); + } + + QProcess process; + process.start(QString("%1 wallet list").arg(m_sCliPath)); + process.waitForFinished(-1); + QString res = QString::fromLocal8Bit(process.readAll()); + QRegularExpression rx("wallet:\\s(.+)\\s", QRegularExpression::MultilineOption); + QRegularExpressionMatchIterator itr = rx.globalMatch(res); + while (itr.hasNext()) + { + QRegularExpressionMatch match = itr.next(); + QString walletName = match.captured(1); + DapWallet wallet; + wallet.setName(walletName); + auto begin = list.begin(); + auto end = list.end(); + for(; begin != end; ++begin) + { + + wallet.addNetwork(*begin); + + QProcess process_token; + process_token.start(QString("%1 wallet info -w %2 -net %3") + .arg(m_sCliPath) + .arg(walletName) + .arg(*begin)); + + process_token.waitForFinished(-1); + QByteArray result_tokens = process_token.readAll(); + QRegExp regex("wallet: (.+)\\s+addr:\\s+(.+)\\s+(balance)|(\\d+.\\d+)\\s\\((\\d+)\\)\\s(\\w+)"); + + int pos = 0; + DapWalletToken *token {nullptr}; + while((pos = regex.indexIn(result_tokens, pos)) != -1) + { + + if(!regex.cap(2).isEmpty()) + { + wallet.addAddress(regex.cap(2), *begin); + } + else + { + token = new DapWalletToken(); + token->setName(regex.cap(6).trimmed()); + token->setBalance(regex.cap(4).toDouble()); + QString str = regex.cap(5); + token->setEmission(regex.cap(5).toULongLong()); + token->setNetwork(*begin); + wallet.addToken(token); + } + + pos += regex.matchedLength(); + } + + } + wallets.append(wallet); + } + + QByteArray datas; + QDataStream out(&datas, QIODevice::WriteOnly); + out << wallets; + + return QJsonValue::fromVariant(datas.toHex()); +} + + +/// Reply from service. +/// @details Performed on the service side. +/// @return Service reply. +QVariant DapGetWalletsInfoCommand::replyFromService() +{ + DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); + + emit serviceResponded(reply->response().toJsonValue().toVariant().toByteArray()); + + return reply->response().toJsonValue().toVariant(); +} diff --git a/chain/wallet/handlers/DapGetWalletsInfoCommand.h b/chain/wallet/handlers/DapGetWalletsInfoCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..75cdd97492d9a889c826e89321cdbfb5139cd1b4 --- /dev/null +++ b/chain/wallet/handlers/DapGetWalletsInfoCommand.h @@ -0,0 +1,38 @@ +#ifndef DAPGETWALLETSINFOCOMMAND_H +#define DAPGETWALLETSINFOCOMMAND_H + +#include <QProcess> +#include <QRegExp> +#include <QRegularExpression> +#include <QByteArray> +#include <QDataStream> +#include <QBuffer> +#include <QTextCodec> + +#include "DapWallet.h" +#include "DapAbstractCommand.h" + +class DapGetWalletsInfoCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapGetWalletsInfoCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; + QVariant replyFromService() override; +}; + +#endif // DAPGETWALLETSINFOCOMMAND_H diff --git a/chain/wallet/handlers/DapMempoolProcessCommand.cpp b/chain/wallet/handlers/DapMempoolProcessCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f08999f467cb131c1e723512136dda73f742646 --- /dev/null +++ b/chain/wallet/handlers/DapMempoolProcessCommand.cpp @@ -0,0 +1,43 @@ +#include "DapMempoolProcessCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapMempoolProcessCommand::DapMempoolProcessCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1 Network. +/// @param arg2 Chain. +/// @param arg3...arg10 Parameters. +/// @return Reply to client. +QVariant DapMempoolProcessCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + QProcess process; + process.start(QString("%1 mempool_proc -net %2 -chain %3").arg(m_sCliPath).arg(arg1.toString()).arg(arg2.toString())); + process.waitForFinished(-1); + process.readAll(); + QString result = QString::fromLatin1(process.readAll()); + if(result.isEmpty() || result.isNull() || result.contains("No records in mempool") ) + { + return false; + } + return true; +} diff --git a/chain/wallet/handlers/DapMempoolProcessCommand.h b/chain/wallet/handlers/DapMempoolProcessCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..3947203cc10e7d2615442ed9daad5117216cea94 --- /dev/null +++ b/chain/wallet/handlers/DapMempoolProcessCommand.h @@ -0,0 +1,32 @@ +#ifndef DAPMEMPOOLPROCESSCOMMAND_H +#define DAPMEMPOOLPROCESSCOMMAND_H + +#include <QProcess> + +#include "DapAbstractCommand.h" + +class DapMempoolProcessCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapMempoolProcessCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1 Network. + /// @param arg2 Chain. + /// @param arg3...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPMEMPOOLPROCESSCOMMAND_H diff --git a/chain/wallet/handlers/DapQuitApplicationCommand.cpp b/chain/wallet/handlers/DapQuitApplicationCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5147bd5ed97d8b10b3c5e6b445a31ffc6406d18 --- /dev/null +++ b/chain/wallet/handlers/DapQuitApplicationCommand.cpp @@ -0,0 +1,50 @@ +#include "DapQuitApplicationCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +DapQuitApplicationCommand::DapQuitApplicationCommand(const QString &asServicename, QObject *parent) + : DapAbstractCommand(asServicename, parent) +{ + +} + +/// Send a notification to the client. At the same time, you should not expect a response from the client. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +void DapQuitApplicationCommand::notifyToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + DapAbstractCommand::notifyToClient(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + + DapRpcLocalServer * server = dynamic_cast<DapRpcLocalServer *>(m_parent); + + Q_ASSERT(server); + + connect(server, SIGNAL(onClientDisconnected()), qApp, SLOT(quit())); +} + +/// Process the notification from the service on the client side. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +void DapQuitApplicationCommand::notifedFromService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1); + Q_UNUSED(arg2); + Q_UNUSED(arg3); + Q_UNUSED(arg4); + Q_UNUSED(arg5); + Q_UNUSED(arg6); + Q_UNUSED(arg7); + Q_UNUSED(arg8); + Q_UNUSED(arg9); + Q_UNUSED(arg10); + + qApp->quit(); +} diff --git a/chain/wallet/handlers/DapQuitApplicationCommand.h b/chain/wallet/handlers/DapQuitApplicationCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..3eaa3a8055bd1f1f7d13ea5cbd0fad7076578c08 --- /dev/null +++ b/chain/wallet/handlers/DapQuitApplicationCommand.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** This file is part of the libdap-qt-ui-chain-wallet library. +** +** The class implements the exit command of the application. Both the +** GUI client and the service complete the work. +** +****************************************************************************/ + +#ifndef DAPQUITAPPLICATIONCOMMAND_H +#define DAPQUITAPPLICATIONCOMMAND_H + +#include <QObject> +#include <QCoreApplication> + +#include "DapAbstractCommand.h" + +class DapQuitApplicationCommand : public DapAbstractCommand +{ + Q_OBJECT + +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + explicit DapQuitApplicationCommand(const QString &asServicename, QObject *parent = nullptr); + +public slots: + /// Send a notification to the client. At the same time, you should not expect a response from the client. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifyToClient(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()) override; + /// Process the notification from the service on the client side. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifedFromService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPQUITAPPLICATIONCOMMAND_H diff --git a/chain/wallet/handlers/DapRunCmdCommand.cpp b/chain/wallet/handlers/DapRunCmdCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0960e470237de64e1577f80db42669aab3eac160 --- /dev/null +++ b/chain/wallet/handlers/DapRunCmdCommand.cpp @@ -0,0 +1,42 @@ +#include "DapRunCmdCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to cli nodes. +DapRunCmdCommand::DapRunCmdCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + +} + +/// Send a response to the client. +/// @details Performed on the service side. +/// @param arg1 Command. +/// @param arg2...arg10 Parameters. +/// @return Reply to client. +QVariant DapRunCmdCommand::respondToClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + + QProcess process; + process.start(QString("%1 %2").arg(m_sCliPath).arg(arg1.toString())); + process.waitForFinished(-1); + QString result = QString::fromLatin1(process.readAll()); + QJsonArray response; + response.append(QJsonValue(arg1.toString())); + response.append(QJsonValue(result)); + + return response; +} diff --git a/chain/wallet/handlers/DapRunCmdCommand.h b/chain/wallet/handlers/DapRunCmdCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..f224cb40069c54af58b9a854eb51ec38ecbf7fb3 --- /dev/null +++ b/chain/wallet/handlers/DapRunCmdCommand.h @@ -0,0 +1,31 @@ +#ifndef DAPRUNCMDCOMMAND_H +#define DAPRUNCMDCOMMAND_H + +#include <QProcess> + +#include "DapAbstractCommand.h" + +class DapRunCmdCommand : public DapAbstractCommand +{ +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to cli nodes. + DapRunCmdCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Send a response to the client. + /// @details Performed on the service side. + /// @param arg1 Command. + /// @param arg2...arg10 Parameters. + /// @return Reply to client. + QVariant respondToClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPRUNCMDCOMMAND_H diff --git a/chain/wallet/handlers/DapSaveHistoryExecutedCmdCommand.cpp b/chain/wallet/handlers/DapSaveHistoryExecutedCmdCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5e1f882978457074766fbcdbe4211842eca5ca4 --- /dev/null +++ b/chain/wallet/handlers/DapSaveHistoryExecutedCmdCommand.cpp @@ -0,0 +1,42 @@ +#include "DapSaveHistoryExecutedCmdCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +/// @details The parent must be either DapRPCSocket or DapRPCLocalServer. +/// @param asCliPath The path to history file. +DapSaveHistoryExecutedCmdCommand::DapSaveHistoryExecutedCmdCommand(const QString &asServicename, QObject *parent, const QString &asCliPath) + : DapAbstractCommand(asServicename, parent, asCliPath) +{ + DapRpcLocalServer * server = dynamic_cast<DapRpcLocalServer *>(m_parent); + if(server) + { + QDir().mkpath(QFileInfo(m_sCliPath).path()); + m_File = new QFile(m_sCliPath, this); + } +} + +/// Process the notification from the client on the service side. +/// @details Performed on the service side. +/// @param arg1 Command. +/// @param arg2...arg10 Parameters. +void DapSaveHistoryExecutedCmdCommand::notifedFromClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10) +{ + Q_UNUSED(arg1) + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + + if (!m_File->open(QIODevice::Append | QIODevice::ReadWrite)) + return; + + m_File->write(arg1.toString().toUtf8() + '\n'); + m_File->close(); +} diff --git a/chain/wallet/handlers/DapSaveHistoryExecutedCmdCommand.h b/chain/wallet/handlers/DapSaveHistoryExecutedCmdCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..f498230982b92b7fb67c2fe9f98439cd74c494ad --- /dev/null +++ b/chain/wallet/handlers/DapSaveHistoryExecutedCmdCommand.h @@ -0,0 +1,34 @@ +#ifndef DAPSAVEHISTORYEXECUTEDCMDCOMMAND_H +#define DAPSAVEHISTORYEXECUTEDCMDCOMMAND_H + +#include <QFile> +#include <QDir> + +#include "DapAbstractCommand.h" + +class DapSaveHistoryExecutedCmdCommand : public DapAbstractCommand +{ + /// Command history file. + QFile * m_File{nullptr}; + +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + /// @details The parent must be either DapRPCSocket or DapRPCLocalServer. + /// @param asCliPath The path to history file. + DapSaveHistoryExecutedCmdCommand(const QString &asServicename, QObject *parent = nullptr, const QString &asCliPath = QString()); + +public slots: + /// Process the notification from the client on the service side. + /// @details Performed on the service side. + /// @param arg1 Command. + /// @param arg2...arg10 Parameters. + void notifedFromClient(const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), + const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), + const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), + const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), + const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPSAVEHISTORYEXECUTEDCMDCOMMAND_H diff --git a/chain/wallet/handlers/DapUpdateLogsCommand.cpp b/chain/wallet/handlers/DapUpdateLogsCommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f04a0a4310f36622daf42cfc28f8ffa1885de496 --- /dev/null +++ b/chain/wallet/handlers/DapUpdateLogsCommand.cpp @@ -0,0 +1,132 @@ +#include "DapUpdateLogsCommand.h" + +/// Overloaded constructor. +/// @param asServiceName Service name. +/// @param parent Parent. +DapUpdateLogsCommand::DapUpdateLogsCommand(const QString &asServiceName, QObject *parent, const QString &asLogFile) + : DapAbstractCommand(asServiceName, parent), m_csLogFile(asLogFile) +{ + qInfo() << "Initialization of DapUpdateLogsCommand..."; + DapRpcLocalServer * server = dynamic_cast<DapRpcLocalServer *>(m_parent); + + // Watcher is created only on the service side + if(server) + { + // Initialize the watcher for the log file of the node + m_watcherLogFile = new QFileSystemWatcher(this); + QFileInfo fileInfo(m_csLogFile); + m_watcherLogFile->addPath(m_csLogFile); + m_watcherLogFile->addPath(fileInfo.absolutePath()); + + if (!(m_watcherLogFile->addPath(m_csLogFile) || fileInfo.exists())) + { + qWarning() << "Node log file not found"; + } + + connect(m_watcherLogFile, &QFileSystemWatcher::fileChanged, this, [&] + { + if(m_isNoifyClient) + { + readLogFile(); + notifyToClient(m_bufLog); + } + if(!m_watcherLogFile->files().contains(m_csLogFile)) + { + m_watcherLogFile->addPath(m_csLogFile); + } + }); + // Signal-slot connection restoring control over the log file of the node + // if it is deleted during the operation of the service + connect(m_watcherLogFile, &QFileSystemWatcher::directoryChanged, this, [=] + { + qDebug() << "Log file directory changed"; + if(!m_watcherLogFile->files().contains(m_csLogFile)) + { + m_watcherLogFile->addPath(m_csLogFile); + } + }); + } +} + +/// Process the notification from the client on the service side. +/// @details Performed on the service side. +/// @param arg1...arg10 Parameters. +void DapUpdateLogsCommand::notifedFromClient(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg2) + Q_UNUSED(arg3) + Q_UNUSED(arg4) + Q_UNUSED(arg5) + Q_UNUSED(arg6) + Q_UNUSED(arg7) + Q_UNUSED(arg8) + Q_UNUSED(arg9) + Q_UNUSED(arg10) + + + + if(arg1.toString() == "start") + { + m_isNoifyClient = true; + m_bufferSize = arg2.toInt(); + readLogFile(); + notifyToClient(m_bufLog); + } + else if(arg1.toString() == "stop") + { + m_isNoifyClient = false; + } +} + +///The slot reads logs to the buffer. +void DapUpdateLogsCommand::readLogFile() +{ + QFile dapLogFile(m_csLogFile); + if (!dapLogFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qWarning() << "The node log file does not open"; + return; + } + QTextStream readFile(&dapLogFile); + m_bufLog.clear(); + while(!readFile.atEnd()) + { + m_bufLog.append(readFile.readLine()); + + if(m_bufLog.size() > m_bufferSize) + { + m_bufLog.removeFirst(); + } + } + + if(readFile.status()!= QTextStream::Ok) + { + qWarning() << "Error reading log file"; + } + dapLogFile.close(); +} + +/// Process the notification from the service on the client side. +/// @details Performed on the client side. +/// @param arg1...arg10 Parameters. +void DapUpdateLogsCommand::notifedFromService(const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, + const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, + const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, + const QVariant &arg10) +{ + Q_UNUSED(arg1); + Q_UNUSED(arg2); + Q_UNUSED(arg3); + Q_UNUSED(arg4); + Q_UNUSED(arg5); + Q_UNUSED(arg6); + Q_UNUSED(arg7); + Q_UNUSED(arg8); + Q_UNUSED(arg9); + Q_UNUSED(arg10); + + emit clientNotifed(arg1); +} diff --git a/chain/wallet/handlers/DapUpdateLogsCommand.h b/chain/wallet/handlers/DapUpdateLogsCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..132fb797b951c1e16363817f1222450576a920db --- /dev/null +++ b/chain/wallet/handlers/DapUpdateLogsCommand.h @@ -0,0 +1,58 @@ +#ifndef DAPUPDATELOGSCOMMAND_H +#define DAPUPDATELOGSCOMMAND_H + +#include <QFile> +#include <QFileInfo> +#include <QFileSystemWatcher> + +#include "DapAbstractCommand.h" + +#define DEFAULT_BUFFER_SIZE 20 + +class DapUpdateLogsCommand : public DapAbstractCommand +{ + ///The cursor position from which to start reading the file. + qint64 m_seekFile {0}; + ///The number of rows that are stored in memory. + int m_bufferSize {DEFAULT_BUFFER_SIZE}; + ///The container with the lines from the log. + QStringList m_bufLog; + + const QString m_csLogFile; + ///Monitors changes in the log file. + QFileSystemWatcher *m_watcherLogFile {nullptr}; + + bool m_isNoifyClient {false}; + +public: + /// Overloaded constructor. + /// @param asServiceName Service name. + /// @param parent Parent. + explicit DapUpdateLogsCommand(const QString &asServicename, QObject *parent, const QString &asLogFile = QString()); + +protected slots: + ///The slot reads logs to the buffer. + void readLogFile(); + +public slots: + /// Process the notification from the client on the service side. + /// @details Performed on the service side. + /// @param arg1...arg10 Parameters. + virtual void notifedFromClient(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()) override; + /// Process the notification from the service on the client side. + /// @details Performed on the client side. + /// @param arg1...arg10 Parameters. + Q_INVOKABLE virtual void notifedFromService(const QVariant &arg1 = QVariant(), + const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), + const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), + const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), + const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), + const QVariant &arg10 = QVariant()) override; +}; + +#endif // DAPUPDATELOGSCOMMAND_H diff --git a/chain/wallet/libdap-qt-chain-wallet.pri b/chain/wallet/libdap-qt-chain-wallet.pri new file mode 100644 index 0000000000000000000000000000000000000000..f1674f66df17f6fb9eef989de9b89eac16689b25 --- /dev/null +++ b/chain/wallet/libdap-qt-chain-wallet.pri @@ -0,0 +1,81 @@ +QT += core + +INCLUDEPATH += $$PWD $$PWD/../ + + +include (dapRPCProtocol/DapRPCProtocol.pri) + +win32{ + QMAKE_CXXFLAGS += -mno-ms-bitfields +} + +DISTFILES += + +HEADERS += \ + $$PWD/DapChainConvertor.h \ + $$PWD/DapHistoryType.h \ + $$PWD/DapLogMessage.h \ + $$PWD/DapNodeType.h \ + $$PWD/DapWallet.h \ + $$PWD/DapWalletHistoryEvent.h \ + $$PWD/DapWalletToken.h \ + $$PWD/handlers/DapAbstractCommand.h \ + $$PWD/handlers/DapActivateClientCommand.h \ + $$PWD/handlers/DapAddWalletCommand.h \ + $$PWD/handlers/DapCreateTransactionCommand.h \ + $$PWD/handlers/DapExportLogCommand.h \ + $$PWD/handlers/DapGetHistoryExecutedCmdCommand.h \ + $$PWD/handlers/DapGetListNetworksCommand.h \ + $$PWD/handlers/DapGetListWalletsCommand.h \ + $$PWD/handlers/DapGetWalletsInfoCommand.h \ + $$PWD/handlers/DapGetWalletAddressesCommand.h \ + $$PWD/handlers/DapGetWalletHistoryCommand.h \ + $$PWD/handlers/DapGetWalletInfoCommand.h \ + $$PWD/handlers/DapGetWalletTokenInfoCommand.h \ + $$PWD/handlers/DapMempoolProcessCommand.h \ + $$PWD/handlers/DapQuitApplicationCommand.h \ + $$PWD/handlers/DapRunCmdCommand.h \ + $$PWD/handlers/DapSaveHistoryExecutedCmdCommand.h \ + $$PWD/handlers/DapUpdateLogsCommand.h \ + $$PWD/models/DapWalletModel.h \ + $$PWD/serviceClient/DapServiceClient.h \ + $$PWD/serviceClient/DapServiceClientNativeAbstract.h \ + $$PWD/serviceClient/DapServiceClientNativeLinux.h \ + $$PWD/serviceClient/DapServiceClientNativeMacOS.h \ + $$PWD/serviceClient/DapServiceClientNativeWin.h + +SOURCES += \ + $$PWD/DapChainConvertor.cpp \ + $$PWD/DapHistoryType.cpp \ + $$PWD/DapLogMessage.cpp \ + $$PWD/DapWallet.cpp \ + $$PWD/DapWalletHistoryEvent.cpp \ + $$PWD/DapWalletToken.cpp \ + $$PWD/handlers/DapAbstractCommand.cpp \ + $$PWD/handlers/DapActivateClientCommand.cpp \ + $$PWD/handlers/DapAddWalletCommand.cpp \ + $$PWD/handlers/DapCreateTransactionCommand.cpp \ + $$PWD/handlers/DapExportLogCommand.cpp \ + $$PWD/handlers/DapGetHistoryExecutedCmdCommand.cpp \ + $$PWD/handlers/DapGetListNetworksCommand.cpp \ + $$PWD/handlers/DapGetListWalletsCommand.cpp \ + $$PWD/handlers/DapGetWalletsInfoCommand.cpp \ + $$PWD/handlers/DapGetWalletAddressesCommand.cpp \ + $$PWD/handlers/DapGetWalletHistoryCommand.cpp \ + $$PWD/handlers/DapGetWalletInfoCommand.cpp \ + $$PWD/handlers/DapGetWalletTokenInfoCommand.cpp \ + $$PWD/handlers/DapMempoolProcessCommand.cpp \ + $$PWD/handlers/DapQuitApplicationCommand.cpp \ + $$PWD/handlers/DapRunCmdCommand.cpp \ + $$PWD/handlers/DapSaveHistoryExecutedCmdCommand.cpp \ + $$PWD/handlers/DapUpdateLogsCommand.cpp \ + $$PWD/models/DapWalletModel.cpp \ + $$PWD/serviceClient/DapServiceClient.cpp \ + $$PWD/serviceClient/DapServiceClientNativeAbstract.cpp \ + $$PWD/serviceClient/DapServiceClientNativeLinux.cpp \ + $$PWD/serviceClient/DapServiceClientNativeMacOS.cpp \ + $$PWD/serviceClient/DapServiceClientNativeWin.cpp + + + + diff --git a/chain/wallet/models/DapWalletModel.cpp b/chain/wallet/models/DapWalletModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b794f8f0ff592c076a3103ca8012f573c9a1683e --- /dev/null +++ b/chain/wallet/models/DapWalletModel.cpp @@ -0,0 +1,129 @@ +#include "DapWalletModel.h" + +DapWalletModel::DapWalletModel(QObject *parent) + : QAbstractListModel(parent) +{ + +} + +DapWalletModel &DapWalletModel::getInstance() +{ + static DapWalletModel instance; + return instance; +} + +int DapWalletModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return m_aWallets.count(); +} + +QVariant DapWalletModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + switch (role) + { + case NameDisplayRole: return m_aWallets[index.row()].getName(); + case BalanceDisplayRole: return m_aWallets[index.row()].getBalance(); + case AddressDisplayRole: return m_aWallets[index.row()].getAddress(); + case IconDisplayRole: return m_aWallets[index.row()].getIcon(); + case NetworksDisplayRole: return m_aWallets[index.row()].getNetworks(); + case TokensDisplayRole: + return QVariant::fromValue<QList<QObject*>>(getTokens(index.row())); + case WalletsDisplayRole: return getWalletList(); + default: break; + } + + return QVariant(); +} + +QList<QObject*> DapWalletModel::getTokens(const int aIndex) const +{ + QList<QObject*> tokens; + auto cbegin = m_aWallets[aIndex].getTokens().cbegin(); + auto cend = m_aWallets[aIndex].getTokens().cend(); + for(; cbegin != cend; ++ cbegin) + tokens.append(*cbegin); + + return tokens; +} + +QStringList DapWalletModel::getWalletList() const +{ + QStringList walletList; + foreach (auto wallet, m_aWallets) + { + walletList.append(wallet.getName()); + } + return walletList; +} + +void DapWalletModel::appendWallet(const DapWallet &aWallet) +{ + m_aWallets.append(aWallet); + + emit walletListChanged(getWalletList()); + + int lastIndex = m_aWallets.count() - 1; + beginInsertRows(QModelIndex(), lastIndex, lastIndex); + endInsertRows(); +} + +void DapWalletModel::appendToken(const QString &asWalletAddress, DapWalletToken* aToken) +{ + auto wallet = std::find_if(m_aWallets.begin(), m_aWallets.end(), [=] (const DapWallet& aWallet) + { + return aWallet.getAddresses().values().contains(asWalletAddress); + }); + + return wallet->addToken(aToken); +} + +void DapWalletModel::removeWallet(const QString &asWalletAddress) +{ + int removeIndex = -1; + auto wallet = std::find_if(m_aWallets.cbegin(), m_aWallets.cend(), [=] (const DapWallet& aWallet) + { + return aWallet.getAddresses().values().contains(asWalletAddress); + }); + removeIndex = m_aWallets.indexOf(*wallet); + m_aWallets.removeAt(removeIndex); + + emit walletListChanged(getWalletList()); + + if(removeIndex == -1) + return; + beginRemoveRows(QModelIndex(), removeIndex, removeIndex); + endRemoveRows(); +} + +void DapWalletModel::removeWallet(const int aWalletIndex) +{ + if(aWalletIndex >= m_aWallets.count() || m_aWallets.count() < aWalletIndex) + return; + beginRemoveRows(QModelIndex(), aWalletIndex, aWalletIndex); + m_aWallets.removeAt(aWalletIndex); + + emit walletListChanged(getWalletList()); + + endRemoveRows(); +} + +QHash<int, QByteArray> DapWalletModel::roleNames() const +{ + static const QHash<int, QByteArray> roles + { + { NameDisplayRole, "name" }, + { BalanceDisplayRole, "balance" }, + { AddressDisplayRole, "address" }, + { IconDisplayRole, "iconPath" }, + { NetworksDisplayRole, "networks" }, + { TokensDisplayRole, "tokens" }, + { WalletsDisplayRole, "walletList" } + }; + + return roles; +} diff --git a/chain/wallet/models/DapWalletModel.h b/chain/wallet/models/DapWalletModel.h new file mode 100644 index 0000000000000000000000000000000000000000..5819271bb2aca1f2abd8fa7760be84f64248ae79 --- /dev/null +++ b/chain/wallet/models/DapWalletModel.h @@ -0,0 +1,57 @@ +#ifndef DAPWALLETMODEL_H +#define DAPWALLETMODEL_H + +#include <QObject> +#include <QAbstractListModel> +#include <algorithm> +#include <QList> + +#include "DapWallet.h" + +class DapWalletModel : public QAbstractListModel +{ + Q_OBJECT + + QList<DapWallet> m_aWallets; + + explicit DapWalletModel(QObject *parent = nullptr); + +public: + Q_PROPERTY(QStringList WalletList READ getWalletList NOTIFY walletListChanged) + + enum DapWalletRole + { + NameDisplayRole = Qt::UserRole, + AddressDisplayRole, + BalanceDisplayRole, + IconDisplayRole, + NetworksDisplayRole, + TokensDisplayRole, + WalletsDisplayRole + }; + Q_ENUM(DapWalletRole) + + static DapWalletModel& getInstance(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QHash<int, QByteArray> roleNames() const override; + + QList<QObject*> getTokens(const int aIndex) const; + + QStringList getWalletList() const; + +signals: + void walletListChanged(const QStringList& aWalletList); + +public slots: + + Q_INVOKABLE void appendWallet(const DapWallet& aWallet); + Q_INVOKABLE void appendToken(const QString& asWalletAddress, DapWalletToken* aToken); + Q_INVOKABLE void removeWallet(const QString& asWalletAddress); + Q_INVOKABLE void removeWallet(const int aWalletIndex); +}; + +#endif // DAPWALLETMODEL_H diff --git a/chain/wallet/serviceClient/DapServiceClient.cpp b/chain/wallet/serviceClient/DapServiceClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eaa9f8809d44df605dc444cca2b64b01c07e8974 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClient.cpp @@ -0,0 +1,150 @@ +#include "DapServiceClient.h" + +DapServiceClient::DapServiceClient(const QString& asServiceName, QObject *apParent) + : QObject(apParent), DapServiceClientNative(asServiceName), m_sServiceName(asServiceName) +{ + // Initialization of the service connection socket + m_pClientSocket = new DapUiSocket(this); + // Signal-slot connection broadcasting service connection error + connect(m_pClientSocket,static_cast<void(DapUiSocket::*)(DapUiSocketError)> (&DapUiSocket::error), + this, &DapServiceClient::handleSocketError); + // Signal-slot connection broadcasting signal of successful connection to the service + connect(m_pClientSocket,SIGNAL(connected()), this, SLOT(connectedToService())); + // Signal-slot connection transmitting a signal to disconnect from the service + connect(m_pClientSocket,SIGNAL(disconnected()), this, SLOT(disconnectFromService())); + // Signal-slot connection that reconnects to the service + connect(&m_reconnectTimer, SIGNAL(timeout()), this, SLOT(reconnectToService())); +} + +/// Get a socket pointer. +/// @return A pointer to a socket. +DapUiSocket *DapServiceClient::getClientSocket() const +{ + return m_pClientSocket; +} + +/// Establish a connection with the service when the latter is launched. +void DapServiceClient::onServiceStarted() +{ + qInfo() << "Service started."; + connectToService(); +} + +/// Handle event of successful connection to the service. +void DapServiceClient::connectedToService() +{ + qInfo() << "Connected to the service"; + m_launchAttemptCounter = 0; + m_isServiceConnected = true; + stopReconnectingToService(); + emit sigConnected(); +} + +/// Start the process of reconnecting to the service. +void DapServiceClient::startReconnectingToService() +{ + if(!m_reconnectTimer.isActive()) { + qInfo() << "Start trying to reconnect to service"; + m_reconnectTimer.start(RECONNECT_TIMEOUT_MS); + } +} + +/// Stop the process of reconnecting to the service. +void DapServiceClient::stopReconnectingToService() +{ + if(m_reconnectTimer.isActive()) + { + m_reconnectTimer.stop(); + qInfo() << "Reconnect timer stopped"; + } +} + +/// Handle socket error. +/// @param aSocketEror Socket error code. +void DapServiceClient::handleSocketError(DapUiSocketError aSocketEror) +{ + qDebug() << m_pClientSocket->errorString(); + startReconnectingToService(); + emit sigSocketError(aSocketEror); + emit sigSocketErrorString(m_pClientSocket->errorString()); +} + +/// Reconnect service. +void DapServiceClient::reconnectToService() +{ + ++m_launchAttemptCounter; + DapServiceError resultInit = DapServiceError::NO_ERRORS; + if(m_launchAttemptCounter == NUMBER_LAUNCH_ATTEMPTS) + { + qCritical() << "Server not running after `serviceStart` operation"; + QMessageBox::critical(Q_NULLPTR, DAP_BRAND, "Unable to start service", QMessageBox::Ok); + exit(-1); + } + else + { + resultInit = init(); + } + if(resultInit == DapServiceError::NO_ERRORS) + { + connectToService(); + } +} + +/// Initiate the service monitor. +DapServiceError DapServiceClient::init() +{ + DapServiceError result = DapServiceClientNative::init(); + + handleServiceError(result); + + return result; +} + +/// Handle service error. +/// @param aServiceEror Service error code. +void DapServiceClient::handleServiceError(DapServiceError aServiceEror) +{ + switch (aServiceEror) + { + case DapServiceError::NO_ERRORS: + break; + case DapServiceError::USER_COMMAND_ABORT: + QMessageBox::critical(Q_NULLPTR, DAP_BRAND, "User abort service comand", QMessageBox::Ok); + exit(-1); + case DapServiceError::UNABLE_START_SERVICE: + QMessageBox::critical(Q_NULLPTR, DAP_BRAND, "Start the service with administrator rights", QMessageBox::Ok); + qCritical() << "Start the service with administrator rights"; + break; + case DapServiceError::UNABLE_STOP_SERVICE: + qCritical() << "Can't stop service"; + break; + case DapServiceError::UNKNOWN_ERROR: + qCritical() << "Got unknown error"; + break; + case DapServiceError::SERVICE_NOT_FOUND: + qCritical() << "Service not found"; + break; + } + if(aServiceEror != DapServiceError::NO_ERRORS) + { + emit sigServiceError(aServiceEror); + } +} + +/// Establish a connection with the service. +void DapServiceClient::connectToService() +{ + if(m_pClientSocket->state() == QAbstractSocket::ConnectedState) + return; + + qInfo() << "with parametr: " << DAP_BRAND; + m_pClientSocket->connectToServer(DAP_BRAND); +} + +/// Handle service outage. +void DapServiceClient::disconnectFromService() +{ + m_isServiceConnected = true; + startReconnectingToService(); + emit sigDisconnected(); +} diff --git a/chain/wallet/serviceClient/DapServiceClient.h b/chain/wallet/serviceClient/DapServiceClient.h new file mode 100644 index 0000000000000000000000000000000000000000..f3acd4c556b103adfd1ab5538213d07944189cd7 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClient.h @@ -0,0 +1,93 @@ +#ifndef DAPSERVICECLIENT_H +#define DAPSERVICECLIENT_H + +#include <QObject> +#include <QTimer> +#include <QMessageBox> +#include <QLocalSocket> +#include <QLocalServer> + +#if defined(Q_OS_LINUX) +#include "DapServiceClientNativeLinux.h" +typedef class DapServiceClientNativeLinux DapServiceClientNative; +#elif defined(Q_OS_WIN) +#include "DapServiceClientNativeWin.h" +typedef class DapServiceClientNativeWin DapServiceClientNative; +#elif defined(Q_OS_MAC) +#include "DapServiceClientNativeMacOS.h" +typedef class DapServiceClientNativeMacOS DapServiceClientNative; +#endif + +typedef QLocalSocket DapUiSocket; +typedef QLocalServer DapUiServer; +typedef QLocalSocket::LocalSocketError DapUiSocketError; + +class DapServiceClient : public QObject, public DapServiceClientNative +{ + Q_OBJECT + Q_DISABLE_COPY(DapServiceClient) + + /// Reconnect interval. + const int RECONNECT_TIMEOUT_MS {5000}; + /// The number of attempts to restart the service. + const size_t NUMBER_LAUNCH_ATTEMPTS {3}; + /// The current number of attempts to restart the service. + size_t m_launchAttemptCounter {0}; + /// Reconnect timer. + QTimer m_reconnectTimer; + /// Service connection socket. + DapUiSocket *m_pClientSocket {nullptr}; + + bool m_isServiceConnected {false}; + + const QString& m_sServiceName; + +public: + explicit DapServiceClient(const QString& asServiceName, QObject * apParent = nullptr); + /// Get a socket pointer. + /// @return A pointer to a socket. + DapUiSocket *getClientSocket() const; + +signals: + /// The signal emitted in case of successful connection to the service. + void sigConnected(); + /// The signal emitted in case of successful disconnection from the service. + void sigDisconnected(); + /// The signal emitted in the event of an error when connecting to the service. + /// @param asErrorMessage Socket error message. + void sigSocketErrorString(const QString& asErrorMessage); + /// The signal emitted in the event of an error when connecting to the service. + /// @param aSocketEror Socket error code. + void sigSocketError(DapUiSocketError aSocketEror); + /// The signal is emitted in case of an error when trying to start the service. + /// @param aServiceEror Service error code. + void sigServiceError(DapServiceError aServiceEror); + +protected slots: + /// Establish a connection with the service when the latter is launched. + void onServiceStarted(); + /// Handle event of successful connection to the service. + void connectedToService(); + /// Start the process of reconnecting to the service. + void startReconnectingToService(); + /// Stop the process of reconnecting to the service. + void stopReconnectingToService(); + /// Handle socket error. + /// @param aSocketEror Socket error code. + void handleSocketError(DapUiSocketError aSocketEror); + /// Reconnect service. + void reconnectToService(); + /// Handle service error. + /// @param aServiceEror Service error code. + void handleServiceError(DapServiceError aServiceEror); + +public slots: + /// Initiate the service monitor. + virtual DapServiceError init() override; + /// Establish a connection with the service. + void connectToService(); + /// Handle service outage. + void disconnectFromService(); +}; + +#endif // DAPSERVICECLIENT_H diff --git a/chain/wallet/serviceClient/DapServiceClientNativeAbstract.cpp b/chain/wallet/serviceClient/DapServiceClientNativeAbstract.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cce5996f4601fc1ba83bba4b685b215e3d65f32 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeAbstract.cpp @@ -0,0 +1,54 @@ +#include "DapServiceClientNativeAbstract.h" + +DapServiceClientNativeAbstract::DapServiceClientNativeAbstract(const QString &asServiceName) + : m_sServiceName(asServiceName) +{ + m_isServiceRunning = false; +} + +DapServiceError DapServiceClientNativeAbstract::init() +{ + qInfo() << "DapServiceClientNativeAbstract::init()"; + DapServiceError result = DapServiceError::NO_ERRORS; + if(!isServiceRunning()) + { + qInfo() << "Install the service in the system"; + + result = serviceInstallAndRun(); + + if(result != DapServiceError::NO_ERRORS) + return result; + + if(isServiceRunning()) + { + onServiceStarted(); + } + else + { + qCritical() << "Service not started after " + "'serviceInstallAndRun' operation!"; + } + } + else + { + onServiceStarted(); + } + return result; +} + +void DapServiceClientNativeAbstract::onServiceInstalled() +{ + qInfo() << "DapServiceClientNativeAbstract::onServiceInstalled()"; + if(isServiceRunning()) + onServiceStarted(); +} + +void DapServiceClientNativeAbstract::onServiceStarted() +{ + +} + +void DapServiceClientNativeAbstract::onServiceStopped() +{ + +} diff --git a/chain/wallet/serviceClient/DapServiceClientNativeAbstract.h b/chain/wallet/serviceClient/DapServiceClientNativeAbstract.h new file mode 100644 index 0000000000000000000000000000000000000000..82f9f3092f4303cf7d45f7fc749dda27872fea92 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeAbstract.h @@ -0,0 +1,41 @@ +#ifndef DAPSERVICECLIENTNATIVEABSTRACT_H +#define DAPSERVICECLIENTNATIVEABSTRACT_H + +#include <QTimer> +#include <QDebug> + +enum class DapServiceError { + NO_ERRORS, + USER_COMMAND_ABORT, + UNABLE_START_SERVICE, + UNABLE_STOP_SERVICE, + SERVICE_NOT_FOUND, + UNKNOWN_ERROR +}; + +class DapServiceClientNativeAbstract +{ +public: + DapServiceClientNativeAbstract(const QString& asServiceName); + virtual ~DapServiceClientNativeAbstract() { } + + virtual bool isServiceRunning() = 0; + + virtual DapServiceError serviceInstallAndRun() = 0; + virtual DapServiceError serviceStart() = 0; + virtual DapServiceError serviceStop() = 0; + virtual DapServiceError serviceRestart() = 0; + +public slots: + virtual DapServiceError init(); +protected: + bool m_isServiceRunning; + const QString& m_sServiceName; + +protected slots: + virtual void onServiceInstalled(); + virtual void onServiceStarted(); + virtual void onServiceStopped(); +}; + +#endif // DAPSERVICECLIENTNATIVEABSTRACT_H diff --git a/chain/wallet/serviceClient/DapServiceClientNativeLinux.cpp b/chain/wallet/serviceClient/DapServiceClientNativeLinux.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ee040c8d2e0e09f934b8b7915a9be34b6a76dde --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeLinux.cpp @@ -0,0 +1,76 @@ +#include "DapServiceClientNativeLinux.h" + +#include <QtDebug> +#include <QMessageBox> + +DapServiceClientNativeLinux::DapServiceClientNativeLinux(const QString& asServiceName) + : DapServiceClientNativeAbstract(asServiceName) +{ + QString dapServiceNameToLower = QString(m_sServiceName).toLower(); + QString cmd = QString("ps -C %1 > /dev/null").arg(m_sServiceName); + m_checkIsServiceRunningCommand = strdup(cmd.toLatin1().data()); + + m_cmdTemplate = QString("service " + dapServiceNameToLower) + " %1"; + + qDebug() << "command for check is service running: " << m_checkIsServiceRunningCommand; +} + +DapServiceClientNativeLinux::~DapServiceClientNativeLinux() +{ + delete m_checkIsServiceRunningCommand; +} + +bool DapServiceClientNativeLinux::isServiceRunning() +{ + m_isServiceRunning =true;// (::system(m_checkIsServiceRunningCommand) == 0); + return m_isServiceRunning; +} + +DapServiceError DapServiceClientNativeLinux::serviceRestart() +{ + qDebug() << "Restart service name" << m_cmdTemplate.arg("restart").toLatin1().data(); + + int retCode = ::system(m_cmdTemplate.arg("restart").toLatin1().data()); + qDebug() << "Restart result code:" << retCode; + if(retCode != 0) { + return DapServiceError::USER_COMMAND_ABORT; + } + + return DapServiceError::NO_ERRORS; +} + +/** + * @brief SapNetworkClientNativeLinux::serviceStart + */ +DapServiceError DapServiceClientNativeLinux::serviceStart() +{ + // yes better use restart + int ret = ::system(m_cmdTemplate.arg("restart").toLatin1().data()); + qDebug() << "serviceStart Result: " << ret; + + if(ret != 0) { + return DapServiceError::USER_COMMAND_ABORT; + } + + return DapServiceError::NO_ERRORS; +} + +/** + * @brief SapServiceClientNativeLinux::serviceStop + */ +DapServiceError DapServiceClientNativeLinux::serviceStop() +{ + int ret = ::system(m_cmdTemplate.arg("stop").toLatin1().data()); + qDebug() << "serviceStop result:" << ret; + if(ret != 0) { + return DapServiceError::USER_COMMAND_ABORT; + } + return DapServiceError::NO_ERRORS; +} +/** + * @brief SapServiceClientNativeLinux::serviceInstallAndRun + */ +DapServiceError DapServiceClientNativeLinux::serviceInstallAndRun() +{ + return serviceStart(); +} diff --git a/chain/wallet/serviceClient/DapServiceClientNativeLinux.h b/chain/wallet/serviceClient/DapServiceClientNativeLinux.h new file mode 100644 index 0000000000000000000000000000000000000000..e8c57cd949afd39f7b1045e1a400bd26fa3d9b50 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeLinux.h @@ -0,0 +1,21 @@ +#ifndef DAPSERVICECLIENTNATIVELINUX_H +#define DAPSERVICECLIENTNATIVELINUX_H + +#include "DapServiceClientNativeAbstract.h" + +class DapServiceClientNativeLinux : public DapServiceClientNativeAbstract +{ + const char* m_checkIsServiceRunningCommand; + QString m_cmdTemplate; +public: + DapServiceClientNativeLinux(const QString& asServiceName); + ~DapServiceClientNativeLinux() override; + bool isServiceRunning() override; + DapServiceError serviceStart() override; + DapServiceError serviceRestart() override; + + DapServiceError serviceStop() override; + DapServiceError serviceInstallAndRun() override; +}; + +#endif // DAPSERVICECLIENTNATIVELINUX_H diff --git a/chain/wallet/serviceClient/DapServiceClientNativeMacOS.cpp b/chain/wallet/serviceClient/DapServiceClientNativeMacOS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3339b9e72fed94fc3ffe659cb58914b131f529d9 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeMacOS.cpp @@ -0,0 +1,76 @@ +#include "DapServiceClientNativeMacOS.h" + +#include <QtDebug> +#include <QMessageBox> + +DapServiceClientNativeMacOS::DapServiceClientNativeMacOS(const QString &asServiceName) + : DapServiceClientNativeAbstract(asServiceName) +{ + QString dapServiceNameToLower = QString(m_sServiceName).toLower(); + QString cmd = QString("ps -C %1 > /dev/null").arg(m_sServiceName); + m_checkIsServiceRunningCommand = strdup(cmd.toLatin1().data()); + + m_cmdTemplate = QString("service " + dapServiceNameToLower) + " %1"; + + qDebug() << "command for check is service running: " << m_checkIsServiceRunningCommand; +} + +DapServiceClientNativeMacOS::~DapServiceClientNativeMacOS() +{ + delete m_checkIsServiceRunningCommand; +} + +bool DapServiceClientNativeMacOS::isServiceRunning() +{ + m_isServiceRunning =true;// (::system(m_checkIsServiceRunningCommand) == 0); + return m_isServiceRunning; +} + +DapServiceError DapServiceClientNativeMacOS::serviceRestart() +{ + qDebug() << "Restart service name" << m_cmdTemplate.arg("restart").toLatin1().data(); + + int retCode = ::system(m_cmdTemplate.arg("restart").toLatin1().data()); + qDebug() << "Restart result code:" << retCode; + if(retCode != 0) { + return DapServiceError::USER_COMMAND_ABORT; + } + + return DapServiceError::NO_ERRORS; +} + +/** + * @brief SapNetworkClientNativeMacOS::serviceStart + */ +DapServiceError DapServiceClientNativeMacOS::serviceStart() +{ + // yes better use restart + int ret = ::system(m_cmdTemplate.arg("restart").toLatin1().data()); + qDebug() << "serviceStart Result: " << ret; + + if(ret != 0) { + return DapServiceError::USER_COMMAND_ABORT; + } + + return DapServiceError::NO_ERRORS; +} + +/** + * @brief SapServiceClientNativeMacOS::serviceStop + */ +DapServiceError DapServiceClientNativeMacOS::serviceStop() +{ + int ret = ::system(m_cmdTemplate.arg("stop").toLatin1().data()); + qDebug() << "serviceStop result:" << ret; + if(ret != 0) { + return DapServiceError::USER_COMMAND_ABORT; + } + return DapServiceError::NO_ERRORS; +} +/** + * @brief SapServiceClientNativeMacOS::serviceInstallAndRun + */ +DapServiceError DapServiceClientNativeMacOS::serviceInstallAndRun() +{ + return serviceStart(); +} diff --git a/chain/wallet/serviceClient/DapServiceClientNativeMacOS.h b/chain/wallet/serviceClient/DapServiceClientNativeMacOS.h new file mode 100644 index 0000000000000000000000000000000000000000..c04f37d5e9a6f9a44e472ea7c16f78e1794df37d --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeMacOS.h @@ -0,0 +1,21 @@ +#ifndef DAPSERVICECLIENTNATIVEMACOS_H +#define DAPSERVICECLIENTNATIVEMACOS_H + +#include "DapServiceClientNativeAbstract.h" + +class DapServiceClientNativeMacOS : public DapServiceClientNativeAbstract +{ + const char* m_checkIsServiceRunningCommand; + QString m_cmdTemplate; +public: + DapServiceClientNativeMacOS(const QString& asServiceName); + ~DapServiceClientNativeMacOS() override; + bool isServiceRunning() override; + DapServiceError serviceStart() override; + DapServiceError serviceRestart() override; + + DapServiceError serviceStop() override; + DapServiceError serviceInstallAndRun() override; +}; + +#endif // DAPSERVICECLIENTNATIVEMACOS_H diff --git a/chain/wallet/serviceClient/DapServiceClientNativeWin.cpp b/chain/wallet/serviceClient/DapServiceClientNativeWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a97fc9f3b762abb96111c34f48d85a012b70e5ff --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeWin.cpp @@ -0,0 +1,31 @@ +#include "DapServiceClientNativeWin.h" + +DapServiceClientNativeWin::DapServiceClientNativeWin(const QString& asServiceName) + : DapServiceClientNativeAbstract(asServiceName) +{ +} + +bool DapServiceClientNativeWin::isServiceRunning() +{ + return true; +} + +DapServiceError DapServiceClientNativeWin::serviceInstallAndRun() { + return DapServiceError::NO_ERRORS; +} + +DapServiceError DapServiceClientNativeWin::serviceStart() { + return DapServiceError::NO_ERRORS; +} + +DapServiceError DapServiceClientNativeWin::serviceRestart() { + return DapServiceError::NO_ERRORS; +} + +DapServiceError DapServiceClientNativeWin::serviceStop() { + return DapServiceError::NO_ERRORS; +} + +DapServiceClientNativeWin::~DapServiceClientNativeWin() { + +} diff --git a/chain/wallet/serviceClient/DapServiceClientNativeWin.h b/chain/wallet/serviceClient/DapServiceClientNativeWin.h new file mode 100644 index 0000000000000000000000000000000000000000..868698efbe6290f11bbbe732f03f32a7bf1ede16 --- /dev/null +++ b/chain/wallet/serviceClient/DapServiceClientNativeWin.h @@ -0,0 +1,19 @@ +#ifndef DAPSERVICECLIENTNATIVEWIN_H +#define DAPSERVICECLIENTNATIVEWIN_H + +#include "DapServiceClientNativeAbstract.h" + +class DapServiceClientNativeWin : public DapServiceClientNativeAbstract +{ +public: + DapServiceClientNativeWin(const QString& asServiceName); + ~DapServiceClientNativeWin() override; + bool isServiceRunning() override; + DapServiceError serviceStart() override; + DapServiceError serviceRestart() override; + + DapServiceError serviceStop() override; + DapServiceError serviceInstallAndRun() override; +}; + +#endif // DAPSERVICECLIENTNATIVEWIN_H diff --git a/stream/ch/chain/net/srv/vpn/DapStreamChChainNetSrvVpn.cpp b/stream/ch/chain/net/srv/vpn/DapStreamChChainNetSrvVpn.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91a9acaf80713b3c39c59b0c10371ba80158833a --- /dev/null +++ b/stream/ch/chain/net/srv/vpn/DapStreamChChainNetSrvVpn.cpp @@ -0,0 +1,407 @@ +/* +* Authors: +* Dmitriy Gerasimov <naeper@demlabs.net> +* Cellframe https://cellframe.net +* DeM Labs Inc. https://demlabs.net +* Copyright (c) 2017-2019 +* All rights reserved. + +This file is part of CellFrame SDK the open source project + +CellFrame SDK is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +CellFrame SDK is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with any CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <QtDebug> + +#include "DapStreamer.h" +#include "DapStreamChChainVpnPacket.h" +#include "DapStreamChChainNetSrvVpn.h" + +#if defined(Q_OS_UNIX) +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/ip.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/select.h> + +#elif defined(Q_OS_MACOS) +#elif defined (Q_OS_WIN) +#include <winsock2.h> +#endif + +#include <QProcess> +#include <QFile> + + +#include <fcntl.h> +#include <errno.h> +#include <string.h> + +using namespace Dap; +using namespace Dap::Stream; + +/** + * @brief ChChainNetSrvVpn::delForwardingAll + */ +void ChChainNetSrvVpn::delForwardingAll() +{ + for (auto s : m_socketsIn) + delete s; + m_socketsIn.clear(); + + for (auto s : m_servs) + delete s; + m_servs.clear(); +} + +/** + * @brief ChChainNetSrvVpn::delForwarding + * @param sockId + */ +void ChChainNetSrvVpn::delForwarding(int sockId) +{ + QTcpServer * serv = m_servs[sockId]; + if (serv) { + m_servs.remove(sockId); + delete serv; + } else qDebug() << "Not found socket by id: " << sockId; +} + +/** + * @brief ChChainNetSrvVpn::onFwClientReadyRead + */ +void ChChainNetSrvVpn::onFwClientReadyRead() +{ + qDebug() << "[onFwClientReadyRead]"; + QTcpSocket * sock = qobject_cast<QTcpSocket*>(QObject::sender()); + if (sock) { + QByteArray ba = sock->readAll(); + qDebug() << "From client's socket have read " << ba.length() << "bytes."; + Dap::Stream::Packet* pkt = (Dap::Stream::Packet*) calloc(1, ba.length() + sizeof(pkt->header)); + memcpy(pkt->data, ba.constData(), ba.length()); + pkt->header.op_data.data_size = ba.length(); + pkt->header.op_code = STREAM_SF_PACKET_OP_CODE_SEND; + pkt->header.socket_id = sock->socketDescriptor(); + packetOut(pkt); + } else{ + qCritical() << "Cant cast sender() object of type " + <<QObject::sender()->metaObject()->className()<< " to QTcpSocket"; + } +} + +/** + * @brief ChChainNetSrvVpn::onFwClientDisconnected + */ +void ChChainNetSrvVpn::onFwClientDisconnected() +{ + QTcpSocket *sock = qobject_cast<QTcpSocket*>(QObject::sender()); + if(sock) { + qDebug() << "Disconnected client " << sock->localAddress(); + m_socketsIn.remove(sock->socketDescriptor()); + + Dap::Stream::Packet* pkt = (Dap::Stream::Packet*) calloc(1,sizeof(pkt->header) + 1); + pkt->header.op_code = STREAM_SF_PACKET_OP_CODE_DISCONNECT; + pkt->header.socket_id = sock->socketDescriptor(); + pkt->header.raw.data_size = 2; ///TODO prev value is 0 + packetOut(pkt); + } else{ + qCritical() << "Cant cast sender() object of type " + <<QObject::sender()->metaObject()->className()<< " to QTcpSocket"; + } +} + +/** + * @brief ChChainNetSrvVpn::onFwServerConnected + */ +void ChChainNetSrvVpn::onFwServerConnected() +{ + qDebug() << "[onFwServerConnected()]"; + QTcpServer *serv = qobject_cast<QTcpServer*>(QObject::sender()); + QTcpSocket *sock; + QByteArray remoteAddrBA; + Dap::Stream::Packet *pkt; + + if(serv) { + if(!serv->hasPendingConnections()) + qDebug() << "No pendidng connections on the server"; + else do { + + sock = serv->nextPendingConnection(); + remoteAddrBA = (m_servsRemoteAddr[serv->socketDescriptor()]).toLatin1(); + m_socketsIn.insert(sock->socketDescriptor(),sock); + pkt = (Dap::Stream::Packet*) calloc(1, sizeof(pkt->header) + remoteAddrBA.length()); + + pkt->header.op_code = STREAM_SF_PACKET_OP_CODE_CONNECT; + pkt->header.socket_id = sock->socketDescriptor(); + pkt->header.op_connect.addr_size = remoteAddrBA.length(); + + memcpy(pkt->data, remoteAddrBA.constData(), pkt->header.op_connect.addr_size); + + pkt->header.op_connect.port = m_servsRemotePort[serv->socketDescriptor()]; + + qDebug() << "New connection enstablished to " + << m_servsRemoteAddr[serv->socketDescriptor()] + << ":" << pkt->header.op_connect.port + << " addr size" << pkt->header.op_connect.addr_size; + + connect(sock, &QTcpSocket::readyRead, this, &ChChainNetSrvVpn::onFwClientReadyRead); + connect(sock, &QTcpSocket::disconnected, this, &ChChainNetSrvVpn::onFwClientDisconnected); + + packetOut(pkt); + + } while( serv->hasPendingConnections() ); + } else + qDebug() << "Can't cast object to QTcpServer"; +} + +/** + * @brief ChChainNetSrvVpn::addForwarding + * @param remoteAddr + * @param remotePort + * @param localPort + * @return + */ +quint16 ChChainNetSrvVpn::addForwarding(const QString remoteAddr, quint16 remotePort, quint16 localPort) +{ + qDebug() << "addForwarding " << QString("127.0.0.1:%1 => %2:%3") + .arg(localPort) + .arg(remoteAddr) + .arg(remotePort); + QTcpServer *server = new QTcpServer; + if(server->listen(QHostAddress("127.0.0.1"), localPort)) { + qDebug() << "Sucessfully set up " << localPort << " to listening"; + m_servs.insert(server->socketDescriptor(), server); + m_servsRemoteAddr.insert(server->socketDescriptor(), remoteAddr); + m_servsRemotePort.insert(server->socketDescriptor(), remotePort); + connect(server, &QTcpServer::newConnection, this, &ChChainNetSrvVpn::onFwServerConnected); + connect(server, &QTcpServer::acceptError,[=]{ + qDebug() << "QTcpServer::acceptError() "<< server->errorString() ; + }); + return server->serverPort(); + } else { + qWarning() << "Can't open local port for listening"; + emit error(QString("Can't open local port %1").arg(localPort)); + delete server; + return 0; + } +} + +/** + * @brief ChChainNetSrvVpn::ChChainNetSrvVpn + */ +ChChainNetSrvVpn::ChChainNetSrvVpn(DapStreamer * a_streamer, DapSession * mainDapSession) + :DapChBase(nullptr, 'S'), m_streamer(a_streamer), m_mainDapSession(mainDapSession) +{ + tun = new DapTunNative(); + m_fdListener = nullptr; + connect(tun, &DapTunNative::created, this, &ChChainNetSrvVpn::tunCreated); + connect(tun, &DapTunNative::destroyed, this, &ChChainNetSrvVpn::tunDestroyed); + connect(tun, &DapTunNative::error , this, &ChChainNetSrvVpn::tunError); + connect(tun, &DapTunNative::packetOut, this, &ChChainNetSrvVpn::packetOut); + connect(tun, &DapTunNative::sendCmd, this, &ChChainNetSrvVpn::sendCmdAll); + connect(tun, &DapTunNative::bytesRead, this, &ChChainNetSrvVpn::bytesRead); + connect(tun, &DapTunNative::bytesWrite, this, &ChChainNetSrvVpn::bytesWrite); + connect(tun, &DapTunNative::nativeCreateRequest, this, &ChChainNetSrvVpn::sigTunNativeCreate); + connect(tun, &DapTunNative::nativeDestroyRequest, this, &ChChainNetSrvVpn::sigNativeDestroy); +} + +/** + * @brief ChChainNetSrvVpn::packetOut + * @param pkt + */ +void ChChainNetSrvVpn::packetOut(Dap::Stream::Packet *pkt) +{ + DapChannelPacketHdr* hdr= (DapChannelPacketHdr *) ::calloc(1, sizeof(DapChannelPacketHdr)); + hdr->id='S'; + hdr->type=0x00; + hdr->size=sizeof(pkt->header); + switch(pkt->header.op_code){ + case STREAM_SF_PACKET_OP_CODE_SEND: + case STREAM_SF_PACKET_OP_CODE_RECV: + case STREAM_SF_PACKET_OP_CODE_RAW_SEND: + case STREAM_SF_PACKET_OP_CODE_RAW_RECV: + case STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REPLY: + case STREAM_SF_PACKET_OP_CODE_RAW_L3: + case STREAM_SF_PACKET_OP_CODE_RAW_L2: + case STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REQUEST: + hdr->size+=pkt->header.op_data.data_size; + break; + default: + qWarning() << "Unknown packet code" << pkt->header.op_code; + } + emit pktChOut(hdr,pkt); +} + +/** + * @brief DapChSockForw::requestIP + */ +void ChChainNetSrvVpn::requestIP(quint32 a_usageId) +{ + emit netConfigRequested(); + Dap::Stream::Packet * pktOut = reinterpret_cast<Dap::Stream::Packet*>(::calloc(1 ,sizeof(pktOut->header))); + pktOut->header.op_code=STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REQUEST; + pktOut->header.usage_id = a_usageId; + qInfo() << "Request for IP with usage_id: " << pktOut->header.usage_id; + packetOut(pktOut); + emit ipRequested(); +} + +/** + * @brief DapChSockForw::netConfigClear + */ +void ChChainNetSrvVpn::netConfigClear() +{ + m_addr.clear(); + m_gw.clear(); + emit netConfigCleared(); +} + +/** + * @brief ChChainNetSrvVpn::tunCreate + * @param a_addr + * @param a_gw + */ +void ChChainNetSrvVpn::tunCreate(const QString &a_addr, const QString &a_gw) +{ + m_addr = a_addr; + m_gw = a_gw; + tun->create(a_addr, + a_gw, + m_mainDapSession->upstreamAddress(), + m_mainDapSession->upstreamPort(), + streamer()->upstreamSocket()); +} + +/** + * @brief ChChainNetSrvVpn::tunCreate + */ +void ChChainNetSrvVpn::tunCreate() +{ + tun->create(m_addr, + m_gw, + m_mainDapSession->upstreamAddress(), + m_mainDapSession->upstreamPort(), + streamer()->upstreamSocket()); +#ifdef ANDROID + if (m_fdListener == nullptr) { + m_fdListener = new QTcpServer(); + + connect(m_fdListener, &QTcpServer::newConnection, this, [&] { + qDebug() << "f0"; + auto pending = m_fdListener->nextPendingConnection(); + connect(pending, &QTcpSocket::readyRead, this, [=] { + if (pending) { + int val = pending->readAll().toInt(); + workerStart(val); + m_fdListener->close(); + } + }); + }); + } + m_fdListener->listen(QHostAddress::LocalHost, 22500); +#else + tun->workerStart(); +#endif +} + +void ChChainNetSrvVpn::tunDestroy() +{ + tun->destroy(); +} + +/** + * @brief ChChainNetSrvVpn::afterTunCreate + * @param a_tunSocket + */ +void ChChainNetSrvVpn::workerStart(int a_tunSocket) +{ + qDebug() << "set tun socket: " << a_tunSocket; + tun->setTunSocket(a_tunSocket); + tun->workerStart(); // start loop +} + +/** + * @brief ChChainNetSrvVpn::onPktIn + * @param pkt + */ +void ChChainNetSrvVpn::onPktIn(DapChannelPacket* pkt) +{ + // qDebug() << "onPktIn: id ="<<pkt->hdr()->id << " type = "<< pkt->hdr()->type<< " ch_data_size = "<<pkt->hdr()->size; + Dap::Stream::Packet * pktSF=(Dap::Stream::Packet *) pkt->data(); + //qDebug() << " onPktIn: SampSFPacket op_code ="<< pktSF->header.op_code; + switch(pktSF->header.op_code){ + case STREAM_SF_PACKET_OP_CODE_SEND: + case STREAM_SF_PACKET_OP_CODE_CONNECT:{ + qDebug() << "Backforward connection are not processed"; + } break; + case STREAM_SF_PACKET_OP_CODE_DISCONNECT:{ + + break; + QTcpSocket *sc=m_socketsIn[pktSF->header.socket_id]; + if (sc) { + m_socketsIn.remove(pktSF->header.socket_id); + sc->close(); + } else { + qDebug() <<" Unknown socket_id "<<pktSF->header.socket_id; + } + } break; + case STREAM_SF_PACKET_OP_CODE_RECV:{ + QTcpSocket *sc=m_socketsIn[pktSF->header.socket_id]; + if (sc) { + sc->write((const char*)pktSF->data, pktSF->header.op_data.data_size); + } else { + qDebug() <<" Unknown socket_id "<<pktSF->header.socket_id; + } + } break; + case STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REPLY:{ + quint32 l_addr,l_gw; + ::memcpy(&l_addr, pktSF->data,sizeof (l_addr)); + ::memcpy(&l_gw, pktSF->data+sizeof (l_addr),sizeof (l_addr)); + QString new_addr = QHostAddress( ntohl(l_addr) ).toString(); + QString new_gw = QHostAddress( ntohl ( l_gw )).toString(); + if (m_addr == new_addr && new_gw == m_gw) { + qDebug() << "Net config is the same, we don't touch Tun"; + emit netConfigReceivedSame(); + } else { + m_addr = new_addr; + m_gw = new_gw; + emit netConfigReceived(m_addr,m_gw); + } + } break; + case STREAM_SF_PACKET_OP_CODE_RAW_RECV:{ + pkt->unleashData(); // Uleash *data section from pkt object + tun->tunWriteData(pktSF); + }break; + /*case STREAM_SF_PACKET_OP_CODE_CONNECTED: + qDebug() << "[DapChSockForw] Get connected packet."; // Repsonse to the connect Packet + tcp_sock = m_socketsIn[sockForwPacket->header.socket_id]; + if(tcp_sock) + connect(tcp_sock, &QTcpSocket::readyRead, this, &DapChSockForw::onClientReadyRead); + else + qWarning() << ("[DapChSockForw] onPktIn() Not Find Socket by socket_id!"); + break;*/ + } + + delete pkt; +} + + + + + + + diff --git a/stream/ch/chain/net/srv/vpn/DapStreamChChainNetSrvVpn.h b/stream/ch/chain/net/srv/vpn/DapStreamChChainNetSrvVpn.h new file mode 100644 index 0000000000000000000000000000000000000000..f31ee99b062c27eac2f4b9df70a3b6dcd00b386a --- /dev/null +++ b/stream/ch/chain/net/srv/vpn/DapStreamChChainNetSrvVpn.h @@ -0,0 +1,149 @@ +/* +* Authors: +* Dmitriy Gerasimov <naeper@demlabs.net> +* Cellframe https://cellframe.net +* DeM Labs Inc. https://demlabs.net +* Copyright (c) 2017-2019 +* All rights reserved. + +This file is part of CellFrame SDK the open source project + +CellFrame SDK is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +CellFrame SDK is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with any CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once +#include "DapChBase.h" +#include "DapSession.h" + +//#include "DapSockForwPacket.h" +#include "DapStreamChChainNetSrv.h" +#include "DapStreamChChainVpnPacket.h" +#include "DapTunNative.h" +#include "DapStreamer.h" + +#include <QDebug> +#include <QTcpSocket> +#include <QTcpServer> + + + +#define STREAM_SF_PACKET_OP_CODE_CONNECTED 0x000000a9 +#define STREAM_SF_PACKET_OP_CODE_CONNECT 0x000000aa +#define STREAM_SF_PACKET_OP_CODE_DISCONNECT 0x000000ab +#define STREAM_SF_PACKET_OP_CODE_SEND 0x000000ac +#define STREAM_SF_PACKET_OP_CODE_RECV 0x000000ad +#define STREAM_SF_PACKET_OP_CODE_PROBLEM 0x000000ae + +#define STREAM_SF_PROBLEM_CODE_NO_FREE_ADDR 0x00000001 +#define STREAM_SF_PROBLEM_CODE_TUNNEL_DOWN 0x00000002 +#define STREAM_SF_PROBLEM_CODE_PACKET_LOST 0x00000003 + +#define STREAM_SF_PACKET_OP_CODE_RAW_L3 0x000000b0 +#define STREAM_SF_PACKET_OP_CODE_RAW_L2 0x000000b1 +#define STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REQUEST 0x000000b2 +#define STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REPLY 0x000000b3 +#define STREAM_SF_PACKET_OP_CODE_RAW_L3_DEST_REPLY 0x000000b4 + +#define STREAM_SF_PACKET_OP_CODE_RAW_SEND 0x000000bc +#define STREAM_SF_PACKET_OP_CODE_RAW_RECV 0x000000bd + +#define DAP_CHAIN_NET_SRV_VPN_ID + + +namespace Dap { + namespace Chain { + namespace NetSrv { + const Uid UID_VPN = 0x0000000000000001; + } + } + namespace Stream { + + class ChChainNetSrvVpn : public DapChBase + { + Q_OBJECT + public: + private: + // DATAS + DapStreamer * m_streamer; + DapSession * m_mainDapSession; + + QMap<int, QTcpSocket* > m_socketsIn; + QMap<int, QTcpServer* > m_servs; + QMap<int, QString > m_servsRemoteAddr; + QMap<int, quint16 > m_servsRemotePort; + + QMap<int, QTcpSocket* > m_socksIn; + QMap<int, QTcpSocket* > m_socksOut; + + DapTunNative * tun; + // METHODS + QString m_addr, m_gw; + QTcpServer *m_fdListener; + private slots: + void onFwServerConnected(); + void onFwClientReadyRead(); + void onFwClientDisconnected(); + + signals: + void bytesRead(int); + void bytesWrite(int); + + void fwdDisconnected(int sockServ, int sockClient); + void usrMsg(QString); + void sigPacketRead(); + void sigPacketWrite(); + + void sigTunNativeCreate(); + void sigNativeDestroy(); + + + public: + ChChainNetSrvVpn(DapStreamer * a_streamer, DapSession * mainDapSession); + + bool isTunCreated(){return tun->isCreated();} + + void tunCreate (const QString& a_addr, const QString& a_gw); + void workerStart(int a_tunSocket); + + quint16 addForwarding(const QString remoteAddr, quint16 remotePort, quint16 localPort); + void delForwarding(int sockId); + void delForwardingAll(); + + DapStreamer * streamer(){ return m_streamer; } + signals: + + void netConfigReceived(QString,QString); + void netConfigRequested(); + void netConfigReceivedSame(); + void netConfigCleared(); + void tunCreated(); + void tunDestroyed(); + void tunError(const QString&); + void tunWriteData(); + + void ipRequested(); + + void sendCmdAll(const QString&); + public slots: + void onPktIn(DapChannelPacket *pkt) override; + void packetOut(Dap::Stream::Packet *pkt); + + void requestIP(quint32); + void netConfigClear(); + + void tunCreate(); // create with all predefined before values + void tunDestroy(); + }; + + } +} diff --git a/stream/ch/chain/net/srv/vpn/README.md b/stream/ch/chain/net/srv/vpn/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a6013c932680fc7fdaf2c7b79a84ec940e082dd6 --- /dev/null +++ b/stream/ch/chain/net/srv/vpn/README.md @@ -0,0 +1,2 @@ +# libdap-qt-stream-ch-chain-net-srv-vpn + diff --git a/stream/ch/chain/net/srv/vpn/libdap-qt-stream-ch-chain-net-srv-vpn.pri b/stream/ch/chain/net/srv/vpn/libdap-qt-stream-ch-chain-net-srv-vpn.pri new file mode 100755 index 0000000000000000000000000000000000000000..2ea7adae64e13bf83293cda9d0eed39270601ef6 --- /dev/null +++ b/stream/ch/chain/net/srv/vpn/libdap-qt-stream-ch-chain-net-srv-vpn.pri @@ -0,0 +1,7 @@ +SOURCES += \ + $$PWD/DapStreamChChainNetSrvVpn.cpp + +HEADERS += \ + $$PWD/DapStreamChChainNetSrvVpn.h + +INCLUDEPATH += $$PWD diff --git a/ui/chain/wallet/DapHelper.cpp b/ui/chain/wallet/DapHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a462ebdfc744a3977f63e8efdd99ca48eb2f305 --- /dev/null +++ b/ui/chain/wallet/DapHelper.cpp @@ -0,0 +1,43 @@ +#include "DapHelper.h" + +DapHelper::DapHelper(QObject *parent) : QObject(parent) +{ + +} + +DapHelper &DapHelper::getInstance() +{ + static DapHelper instance; + return instance; +} + +/// Check for the existence of a running instance of the program. +/// @param systemSemaphore Semaphore for blocking shared resource. +/// @param memmoryApp Shared memory. +/// @param memmoryAppBagFix Shared memory for Linux system features. +/// @return If the application is running, it returns three, otherwise false. +bool DapHelper::checkExistenceRunningInstanceApp(QSystemSemaphore& systemSemaphore, QSharedMemory &memmoryApp, QSharedMemory &memmoryAppBagFix) +{ + systemSemaphore.acquire(); + + if(memmoryAppBagFix.attach()) + { + memmoryAppBagFix.detach(); + } + + bool isRunning {false}; + + if (memmoryApp.attach()) + { + isRunning = true; + } + else + { + memmoryApp.create(1); + isRunning = false; + } + + systemSemaphore.release(); + + return isRunning; +} diff --git a/ui/chain/wallet/DapHelper.h b/ui/chain/wallet/DapHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..14ed07aab99e8f88b7eecc6cbf3a31f770723fbe --- /dev/null +++ b/ui/chain/wallet/DapHelper.h @@ -0,0 +1,51 @@ +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * Demlabs Limited https://demlabs.net + * CellFrame https://cellframe.net + * Sources https://gitlab.demlabs.net/cellframe + * Copyright (c) 2017-2020 + * All rights reserved. + + This file is part of CellFrame SDK the open source project + + CellFrame SDK is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CellFrame SDK is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once +#include <QObject> +#include <QSystemSemaphore> +#include <QSharedMemory> + +class DapHelper : public QObject +{ + Q_OBJECT + + /// Standart constructor. + explicit DapHelper(QObject *parent = nullptr); + +public: + // Realization of a singleton + DapHelper(const DapHelper&) = delete; + DapHelper& operator= (const DapHelper &) = delete; + /// Get an instance of a class. + /// @return Instance of a class. + static DapHelper &getInstance(); + + /// Check for the existence of a running instance of the program. + /// @param systemSemaphore Semaphore for blocking shared resource. + /// @param memmoryApp Shared memory. + /// @param memmoryAppBagFix Shared memory for Linux system features. + /// @return If the application is running, it returns three, otherwise false. + bool checkExistenceRunningInstanceApp(QSystemSemaphore& systemSemaphore, QSharedMemory &memmoryApp, QSharedMemory &memmoryAppBagFix); +}; diff --git a/ui/chain/wallet/DapSettings.cpp b/ui/chain/wallet/DapSettings.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa56b454f53ecbe357e0ae3813ff490cb0968186 --- /dev/null +++ b/ui/chain/wallet/DapSettings.cpp @@ -0,0 +1,278 @@ +#include "DapSettings.h" + +#include <QJsonObject> +#include <QJsonArray> +#include <QIODevice> + +/// Standart constructor. +DapSettings::DapSettings(QObject *parent) : QObject(parent) +{ + Q_UNUSED(parent) + + init(); +} + +/// Overloaded constructor. +/// @param fileName Settings file name. +/// @param parent Parent. +DapSettings::DapSettings(const QString &asFileName, QObject *parent) +{ + Q_UNUSED(parent) + + init(); + + setFileName(asFileName); +} + +/// Initialize the components. +void DapSettings::init() +{ + connect(this, &DapSettings::fileNameChanged, this, [=] (const QString &asFileName) + { + m_file.setFileName(asFileName); + }); + + connect(this, &DapSettings::fileNeedClosed, [=] () { m_file.close(); }); +} + +/// Read settings file. +/// @return Virtual json file. If failed read return default json document +QJsonDocument DapSettings::readFile() +{ + if(!m_file.exists()) { + qWarning() << "File doesn't exist." << "Creating file with name " << m_fileName; + m_file.open(QIODevice::ReadOnly | QIODevice::Text); + emit fileNeedClosed(); + return QJsonDocument(); + } + + if(!m_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Failed to read file " << m_file.errorString(); + emit fileNeedClosed(); + return QJsonDocument(); + } + + const QByteArray data = m_file.readAll(); + if(data.isEmpty()) { + qWarning() << "Failed to read data. File " << m_fileName << " is empty"; + return QJsonDocument(); + } + + emit fileNeedClosed(); + + return QJsonDocument::fromJson(data); +} + +/// Write settings to file. +/// @param json Virtual json file. +/// @return Returns true if the recording was successful, false if the recording failed. +bool DapSettings::writeFile(const QJsonDocument &json) +{ + if(!m_file.open(QIODevice::WriteOnly)) { + qWarning() << "Couldn't open write file." << m_file.errorString(); + return false; + } + + const qint64 bytes = m_file.write(json.toJson()); + if(bytes <= 0) { + qWarning() << "Failed to write file with error: " << m_file.errorString(); + return false; + } + + qDebug() << "write bytes " << bytes << " to file " << m_fileName; + emit fileNeedClosed(); + + return true; +} + +/// Get an instance of a class. +/// @return Instance of a class. +DapSettings &DapSettings::getInstance() +{ + static DapSettings instance; + return instance; +} + +/// Get an instance of a class. +/// @return Instance of a class. +DapSettings &DapSettings::getInstance(const QString &asFileName) +{ + static DapSettings instance(asFileName); + return instance; +} + +/// Set property value in group by key property. +/// @details The search in the group is carried out according to the signs +/// defining the object: the name of the key property and its value. +/// To change the value of a property in an object, you must specify +/// the property parameter and its value. For example, setGroupPropertyValue +/// ("widgets", "name", "Services client", "visible", true); "name" +/// is the key property, "Services client" is the value of the key +/// property, "visible" is a modifiable property, true are the set value. +/// @param group Group name. +/// @param keyProperty Key property. +/// @param valueKeyProperty Key property value. +/// @param property Settable property. +/// @param valuePropery The value of the property being set. +bool DapSettings::setGroupPropertyValue(const QString &asGroup, const QString &asKeyProperty, + const QVariant &aValueKeyProperty, const QString &asProperty, + const QVariant &aValueProperty) +{ + if(asGroup.isEmpty() || asGroup.isNull()) + return false; + + auto list = getGroupValue(asGroup); + if(list.empty()) { + QVariantMap map { {asProperty, aValueProperty} }; + list.append(map); + } else { + for(auto &map : list) + if(map.find(asKeyProperty) != map.end() && map.value(asKeyProperty) == aValueKeyProperty) + map.insert(asProperty, aValueProperty); + } + + return setGroupValue(asGroup, list); +} + +/// Get property value from group by key property value. +/// @details The search in the group is carried out according to the signs +/// defining the object: the name of the key property and its value. +/// To change the value of a property in an object, you must specify +/// the property parameter and its value. For example, setGroupPropertyValue +/// ("widgets", "name", "Services client", "visible", true); "name" +/// is the key property, "Services client" is the value of the key +/// property, "visible" is a modifiable property, true are the set value. +/// See also setGroupPropertyValue. +/// @param group Group name. +/// @param keyProperty Key property. +/// @param valueKeyProperty Key property value. +/// @param property Settable property. +/// @param defaultValue The key value to be inserted in case the key is not found. +/// The default is non-valid value. +QVariant DapSettings::getGroupPropertyValue(const QString &asGroup, const QString &aKeyProperty, + const QString &aValueKeyProperty, const QString &asProperty) +{ + for(const QMap<QString, QVariant> &map : getGroupValue(asGroup)) + if(map.find(aKeyProperty) != map.end() && map.value(aKeyProperty) == aValueKeyProperty) + return map.value(asProperty); + return QVariant(); +} + +/// Get key value. +/// @details If the key does not exist, the function returns an invalid value. +/// @param key Key name. +QVariant DapSettings::getKeyValue(const QString &asKey) +{ + const QJsonValue value = readFile().object().value(asKey); + if(value.isNull() || value.isUndefined()) + return QVariant(); + + return value.toVariant(); +} + +/// Set key value. +/// @param key Key. +/// @param value Key value. +bool DapSettings::setKeyValue(const QString &asKey, const QVariant &aValue) +{ + if(asKey.isEmpty() || asKey.isNull()) + return false; + + if(aValue.isNull() || !aValue.isValid()) + return false; + + QJsonObject jsonObject = readFile().object(); + jsonObject.insert(asKey, aValue.toJsonValue()); + return writeFile(QJsonDocument(jsonObject)); +} + +/// Get a collection of values by name group. +/// @details If the group is not found, the function returns an empty list. +/// @param group Group name. +/// @return Group values collection. +QList<QVariantMap> DapSettings::getGroupValue(const QString &asGroup) +{ + if(asGroup.isEmpty() || asGroup.isNull()) { + qWarning() << "Failed get group value because group's name is undefined"; + return QList<QVariantMap>(); + } + + const QJsonValue jsonGroupValue = readFile().object().value(asGroup); + if(jsonGroupValue.isNull() || jsonGroupValue.isUndefined()) { + qWarning() << "Failed get group value because group " << asGroup << " doesn't exist"; + return QList<QVariantMap>(); + } + + if(!jsonGroupValue.isArray()) { + qWarning() << "Failed get group value because group " << asGroup << " isn't array of values"; + return QList<QVariantMap>(); + } + + QList<QVariantMap> collection; + const QJsonArray jsonGroupArray = jsonGroupValue.toArray(); + for(const QJsonValue &jsonValue : jsonGroupArray) + { + const QJsonObject jsonObject = jsonValue.toObject(); + if(!jsonValue.isObject()) { + qDebug() << jsonObject << " isn't object. Read next field..."; + continue; + } + + QVariantMap map; + for(const QString &key : jsonObject.keys()) + map.insert(key, jsonObject.value(key).toVariant()); + + collection.push_back(map); + } + + return collection; +} + +/// Set key values for group. +/// @param group Group name. +/// @param values Collection of group values. +bool DapSettings::setGroupValue(const QString &asGroup, const QList<QVariantMap> &aValues) +{ + if(asGroup.isEmpty() || asGroup.isNull()) + return false; + + QJsonArray groupValues; + for(const auto & map : aValues) + { + QJsonObject itemObject; + for(const auto &key : map.keys()) + itemObject.insert(key, map.value(key).toJsonValue()); + + groupValues.append(itemObject); + } + + return setKeyValue(asGroup, groupValues); +} + +/// Get the name of the settings file. +/// @return The name of the settings file. +const QString &DapSettings::getFileName() const +{ + return m_fileName; +} + +/// Set the name of the settings file. +/// @param fileName The name of the settings file. +/// @return Reference of changed object DapSettings +DapSettings &DapSettings::setFileName(const QString &asFileName) +{ + m_fileName = asFileName; + emit fileNameChanged(asFileName); + return *this; +} + +/// Method that implements the singleton pattern for the qml layer. +/// @param engine QML application. +/// @param scriptEngine The QJSEngine class provides an environment for evaluating JavaScript code. +QObject *DapSettings::singletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return &getInstance(); +} diff --git a/ui/chain/wallet/DapSettings.h b/ui/chain/wallet/DapSettings.h new file mode 100644 index 0000000000000000000000000000000000000000..dc52b3d9fdc5d351796fb38ba0ca97f2d385d15d --- /dev/null +++ b/ui/chain/wallet/DapSettings.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** This file is part of the libdap-qt-ui-chain-wallet application. +** +** The class provides an interface for managing application settings. +** Record format - Json. +** +** Implements a singleton pattern. +** +****************************************************************************/ + +#ifndef DAPSETTINGS_H +#define DAPSETTINGS_H + +#include <QObject> +#include <QFile> +#include <QQmlEngine> +#include <QJSEngine> +#include <QJsonDocument> +#include <QDebug> + +class DapSettings : public QObject +{ + Q_OBJECT +protected: + /// Standart constructor. + explicit DapSettings(QObject *parent = nullptr); + /// Overloaded constructor. + /// @param asFileName Settings file name. + /// @param parent Parent. + explicit DapSettings(const QString &asFileName, QObject *parent = nullptr); + + /// Settings file. + QFile m_file; + /// Settings file name. + QString m_fileName; + + /// Initialize the components. + virtual void init(); + +public: + /// Read settings file. + /// @return Virtual json file. If failed read return default json document + virtual QJsonDocument readFile(); + /// Write settings to file. + /// @param json Virtual json file. + /// @return Returns true if the recording was successful, false if the recording failed. + virtual bool writeFile(const QJsonDocument& json); + +public: + /// Removed as part of the implementation of the pattern sington. + DapSettings(const DapSettings&) = delete; + DapSettings& operator= (const DapSettings &) = delete; + + /// Get an instance of a class. + /// @return Instance of a class. + Q_INVOKABLE static DapSettings &getInstance(); + /// Get an instance of a class. + /// @param asFileName Settings file name + /// @return Instance of a class. + Q_INVOKABLE static DapSettings &getInstance(const QString &asFileName); + + ///******************************************** + /// Property + /// ******************************************* + + /// Settings file name. + Q_PROPERTY(QString FileName MEMBER m_fileName READ getFileName WRITE setFileName NOTIFY fileNameChanged) + + ///******************************************** + /// Interface + /// ******************************************* + + /// Set property value in group by key property. + /// @details The search in the group is carried out according to the signs + /// defining the object: the name of the key property and its value. + /// To change the value of a property in an object, you must specify + /// the property parameter and its value. For example, setGroupPropertyValue + /// ("widgets", "name", "Services client", "visible", true); "name" + /// is the key property, "Services client" is the value of the key + /// property, "visible" is a modifiable property, true are the set value. + /// @param group Group name. + /// @param keyProperty Key property. + /// @param valueKeyProperty Key property value. + /// @param property Settable property. + /// @param valuePropery The value of the property being set. + /// @return true if successfull set group value. False is group empty or null + Q_INVOKABLE bool setGroupPropertyValue(const QString &asGroup, const QString &asKeyProperty, + const QVariant &aValueKeyProperty, const QString &asProperty, + const QVariant &aValuePropery); + /// Get property value from group by key property value. + /// @details The search in the group is carried out according to the signs + /// defining the object: the name of the key property and its value. + /// To change the value of a property in an object, you must specify + /// the property parameter and its value. For example, setGroupPropertyValue + /// ("widgets", "name", "Services client", "visible", true); "name" + /// is the key property, "Services client" is the value of the key + /// property, "visible" is a modifiable property, true are the set value. + /// See also setGroupPropertyValue. + /// @param group Group name. + /// @param keyProperty Key property. + /// @param valueKeyProperty Key property value. + /// @param property Settable property. + /// The default is non-valid value. + Q_INVOKABLE QVariant getGroupPropertyValue(const QString &asGroup, const QString &asKeyProperty, + const QString &aValueKeyProperty, const QString &asProperty); + /// Get key value. + /// @details If the key does not exist, the function returns an invalid value. + /// @param key Key name. + Q_INVOKABLE QVariant getKeyValue(const QString &asKey); + /// Set key value. + /// @param key Key. + /// @param value Key value. + /// @return true if successfull set value. False is key empty or null + Q_INVOKABLE bool setKeyValue(const QString &asKey, const QVariant &aValue); + /// Get a collection of values by name group. + /// @details If the group is not found, the function returns an empty list. + /// @param group Group name. + /// @return Group values collection. + Q_INVOKABLE QList<QVariantMap> getGroupValue(const QString &asGroup); + /// Set key values for group. + /// @param group Group name. + /// @param values Collection of group values. + /// @return true if successfull set group value. False is group empty or null + Q_INVOKABLE bool setGroupValue(const QString &asGroup, const QList<QVariantMap> &aValues); + /// Get the name of the settings file. + /// @return The name of the settings file. + const QString &getFileName() const; + /// Set the name of the settings file. + /// @param fileName The name of the settings file. + /// @return Reference of changed object DapSettings + DapSettings &setFileName(const QString &asFileName); + +signals: + /// The signal is emitted when the FileName property changes. + /// @param asFileName The name of the settings file. + void fileNameChanged(const QString &asFileName); + /// The signal is emitted when file needs to close; + void fileNeedClosed(); + +public slots: + /// Method that implements the singleton pattern for the qml layer. + /// @param engine QML application. + /// @param scriptEngine The QJSEngine class provides an environment for evaluating JavaScript code. + static QObject *singletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine); +}; + +#endif // DAPSETTINGS_H diff --git a/ui/chain/wallet/DapSystemTrayIcon.cpp b/ui/chain/wallet/DapSystemTrayIcon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..484b76054f68c798d433f86dd828f30bdbbe4380 --- /dev/null +++ b/ui/chain/wallet/DapSystemTrayIcon.cpp @@ -0,0 +1,63 @@ +#include "DapSystemTrayIcon.h" + +DapSystemTrayIcon::DapSystemTrayIcon(QObject *parent) : QSystemTrayIcon(parent) +{ + installEventFilter(this); + + connect(this, SIGNAL(iconPosChaged(QRect)), this, SLOT(determinePosIcon(QRect))); + connect(&m_timer, SIGNAL(timeout()), SLOT(getMousePosition())); + connect(this, SIGNAL(mousePosChanged(QPoint)), this, SLOT(checkRange(QPoint))); +} + +void DapSystemTrayIcon::setToolTipWidget(QWidget *apToolTip) +{ + Q_ASSERT(apToolTip); + + m_pToolTipWidget = apToolTip; +} + +const QWidget *DapSystemTrayIcon::getToolTipWidget() const +{ + return m_pToolTipWidget; +} + +bool DapSystemTrayIcon::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QHelpEvent::ToolTip) + { + QSystemTrayIcon *icon = static_cast<QSystemTrayIcon *>(watched); + emit iconPosChaged(icon->geometry()); + return true; + } + else + { + return QObject::eventFilter(watched, event); + } +} + +void DapSystemTrayIcon::determinePosIcon(const QRect &aPos) +{ + m_rectIcon = aPos; + if(m_pToolTipWidget != nullptr) + { + m_timer.start(1000); + m_pToolTipWidget->move(QPoint(aPos.x(), aPos.y())); + m_pToolTipWidget->show(); + } +} + +void DapSystemTrayIcon::getMousePosition() +{ + QPoint mousePos = QCursor::pos(); + + emit mousePosChanged(mousePos); +} + +void DapSystemTrayIcon::checkRange(const QPoint &aPos) +{ + if(!m_rectIcon.contains(aPos)) + { + m_timer.stop(); + m_pToolTipWidget->hide(); + } +} diff --git a/ui/chain/wallet/DapSystemTrayIcon.h b/ui/chain/wallet/DapSystemTrayIcon.h new file mode 100644 index 0000000000000000000000000000000000000000..a8cb1fc81feb17d069cd233f4625432e8bfb7400 --- /dev/null +++ b/ui/chain/wallet/DapSystemTrayIcon.h @@ -0,0 +1,38 @@ +#ifndef DAPSYSTEMTRAYICON_H +#define DAPSYSTEMTRAYICON_H + +#include <QObject> +#include <QWidget> +#include <QHelpEvent> +#include <QSystemTrayIcon> +#include <QTimer> + +class DapSystemTrayIcon : public QSystemTrayIcon +{ + Q_OBJECT + + QTimer m_timer; + QRect m_rectIcon; + QWidget * m_pToolTipWidget {nullptr}; + +public: + explicit DapSystemTrayIcon(QObject *parent = nullptr); + + void setToolTipWidget(QWidget * apToolTip); + const QWidget * getToolTipWidget() const; + +signals: + void iconPosChaged(const QRect& aPos); + void mousePosChanged(const QPoint& aPos); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; + +private slots: + void determinePosIcon(const QRect& aPos); + void getMousePosition(); + void checkRange(const QPoint& aPos); + +}; + +#endif // DAPSYSTEMTRAYICON_H diff --git a/ui/chain/wallet/README.md b/ui/chain/wallet/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f9fe7c13414fc6d64785df4d6512884562999896 --- /dev/null +++ b/ui/chain/wallet/README.md @@ -0,0 +1,2 @@ +# libdap-qt-ui-chain-wallet + diff --git a/ui/chain/wallet/libdap-qt-ui-chain-wallet.pri b/ui/chain/wallet/libdap-qt-ui-chain-wallet.pri new file mode 100644 index 0000000000000000000000000000000000000000..15b343e3d4e34bd3a7ed94e7298917c4ceb205d7 --- /dev/null +++ b/ui/chain/wallet/libdap-qt-ui-chain-wallet.pri @@ -0,0 +1,25 @@ +QT += core qml + +INCLUDEPATH += $$PWD $$PWD/../ + +win32{ + QMAKE_CXXFLAGS += -mno-ms-bitfields +} + +DISTFILES += + +HEADERS += \ + $$PWD/DapHelper.h \ + $$PWD/DapSettings.h \ + $$PWD/DapSystemTrayIcon.h + +SOURCES += \ + $$PWD/DapHelper.cpp \ + $$PWD/DapSettings.cpp \ + $$PWD/DapSystemTrayIcon.cpp \ + +RESOURCES += \ + $$PWD/libdap-qt-ui-chain-wallet.qrc + + + diff --git a/ui/chain/wallet/libdap-qt-ui-chain-wallet.qrc b/ui/chain/wallet/libdap-qt-ui-chain-wallet.qrc new file mode 100644 index 0000000000000000000000000000000000000000..b2b9c41577e45739344bda0d1c3bce150c789335 --- /dev/null +++ b/ui/chain/wallet/libdap-qt-ui-chain-wallet.qrc @@ -0,0 +1,19 @@ +<RCC> + <qresource prefix="/"> + <file>resources/QML/DapFontRoboto.qml</file> + <file>resources/fonts/LICENSE.txt</file> + <file>resources/fonts/roboto_black_italic.ttf</file> + <file>resources/fonts/roboto_black.ttf</file> + <file>resources/fonts/roboto_bold_italic.ttf</file> + <file>resources/fonts/roboto_bold.ttf</file> + <file>resources/fonts/roboto_italic.ttf</file> + <file>resources/fonts/roboto_light_italic.ttf</file> + <file>resources/fonts/roboto_light.ttf</file> + <file>resources/fonts/roboto_medium_italic.ttf</file> + <file>resources/fonts/roboto_medium.ttf</file> + <file>resources/fonts/roboto_regular.ttf</file> + <file>resources/fonts/roboto_thin_italic.ttf</file> + <file>resources/fonts/roboto_thin.ttf</file> + <file>resources/JS/TimeFunctions.js</file> + </qresource> +</RCC> diff --git a/ui/chain/wallet/resources/JS/TimeFunctions.js b/ui/chain/wallet/resources/JS/TimeFunctions.js new file mode 100644 index 0000000000000000000000000000000000000000..6084d72e283b92184ab0a05e5f7b35ba9441ba70 --- /dev/null +++ b/ui/chain/wallet/resources/JS/TimeFunctions.js @@ -0,0 +1,60 @@ +//Splits a string from the log. +function parceStringFromLog(string) +{ + var split = string.split(/ \[|\] \[|\]|\[/); + return split; +} + + +//This function converts the string representation of time to the Date format +function parceTime(thisTime) +{ + var aDate = thisTime.split('-'); + var aDay = aDate[0].split('/'); + var aTime = aDate[1].split(':'); + return new Date(20+aDay[2], aDay[0] - 1, aDay[1], aTime[0], aTime[1], aTime[2]); +} + + +//Returns the time in the correct form +function getTime(thisTime) +{ + var tmpTime = new Date(thisTime) + var thisHour = tmpTime.getHours(); + var thisMinute = tmpTime.getMinutes(); + var thisSecond = tmpTime.getSeconds(); + if(thisMinute < 10) thisMinute = '0' + thisMinute; + if(thisSecond < 10) thisSecond = '0' + thisSecond; + return thisHour + ':' + thisMinute + ':' + thisSecond; +} + + +//Returns the time in the correct form for the header +function getDay(thisTime, privateDate) +{ + var monthArray = ["January", "February", "March", "April", "May", "June", "July", "August", "September", + "October", "November", "December"]; + var tmpDate = new Date(thisTime); + var thisMonth = tmpDate.getMonth(); + var thisDay = tmpDate.getDate(); + var thisYear = tmpDate.getFullYear(); + + if(thisYear === privateDate.todayYear) + { + if(thisMonth === privateDate.todayMonth) + { + switch(thisDay) + { + case(privateDate.todayDay): return"Today"; + case(privateDate.todayDay-1): return"Yesterday"; + default: return monthArray[thisMonth] + ', ' + thisDay; + } + } + else + return monthArray[thisMonth] + ', ' + thisDay; + } + else + return monthArray[thisMonth] + ', ' + thisDay + ', ' + thisYear; +} + + diff --git a/ui/chain/wallet/resources/QML/DapFontRoboto.qml b/ui/chain/wallet/resources/QML/DapFontRoboto.qml new file mode 100644 index 0000000000000000000000000000000000000000..2b8f74f18ddedfb9df6d1c758e3ef2757c75ffda --- /dev/null +++ b/ui/chain/wallet/resources/QML/DapFontRoboto.qml @@ -0,0 +1,237 @@ +import QtQuick 2.0 +import "qrc:/" + +Item +{ + ///@details dapMainFontTheme ID of item with all project fonts. + property alias dapMainFontTheme: dapFontsObjects + ///@details dapFactor Scaling factor. + property int dapFactor: 1 + + //Add Font Loader + DapFont + { + id: dapFonts + dapFontPath: "qrc:/resources/fonts/" + dapFontNames: ["roboto_black.ttf", + "roboto_light.ttf", + "roboto_medium.ttf", + "roboto_regular.ttf", + "roboto_thin.ttf"] + } + //Create fonts + QtObject + { + + id: dapFontsObjects + + ///@details dapFontRobotoBlack14 Font of Roboto font family (black, 14pt) + property font dapFontRobotoBlack14: Qt.font({ + family: dapFonts.dapProjectFonts[0].name, + bold: false, + italic: false, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoBlackCustom Font of Roboto font family (black, without parameters) + property font dapFontRobotoBlackCustom: Qt.font({ family: dapFonts.dapProjectFonts[0].name }) + + ///@details dapFontRobotoBlackItalic14 Font of Roboto font family (black-italic, 14pt) + property font dapFontRobotoBlackItalic14: Qt.font({ + family: dapFonts.dapProjectFonts[0].name, + bold: false, + italic: true, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoBlackItalicCustom Font of Roboto font family (black-italic, without parameters) + property font dapFontRobotoBlackItalicCustom: Qt.font({ + family: dapFonts.dapProjectFonts[0].name, + italic: true + }) + + ///@details dapFontRobotoBold14 Font of Roboto font family (bold, 14pt) + property font dapFontRobotoBold14: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: true, + italic: false, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoBoldCustom Font of Roboto font family (bold, without parameters) + property font dapFontRobotoBoldCustom: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: true + }) + + ///@detalis dapFontRobotoBoldItalic14 Font of Roboto font family (bold-italic, 14pt) + property font dapFontRobotoBoldItalic14: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: true, + italic: true, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoBoldItalicCustom Font of Roboto font family (bold-italic, without parameters) + property font dapFontRobotoBoldItalicCustom: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: true, + italic: true + }) + + ///@details dapFontRobotoLight14 Font of Roboto font family (light, 14pt) + property font dapFontRobotoLight14: Qt.font({ + family: dapFonts.dapProjectFonts[1].name, + bold: false, + italic: false, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoLightCustom Font of Roboto font family (light, without parameters) + property font dapFontRobotoLightCustom: Qt.font({ family: dapFonts.dapProjectFonts[1].name }) + + ///@details dapFontRobotoLightItalic14 Font of Roboto font family (light-italic, 14pt) + property font dapFontRobotoLightItalic14: Qt.font({ + family: dapFonts.dapProjectFonts[1].name, + bold: false, + italic: true, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoLightItalicCustom Font of Roboto font family (light-italic, without parameters) + property font dapFontRobotoLightItalicCustom: Qt.font({ + family: dapFonts.dapProjectFonts[1].name, + italic: true + }) + ///@details dapFontRobotoMedium14 Font of Roboto font family (medium, 14pt) + property font dapFontRobotoMedium14: Qt.font({ + family: dapFonts.dapProjectFonts[2].name, + bold: false, + italic: false, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoMediumCustom Font of Roboto font family (medium, without parameters) + property font dapFontRobotoMediumCustom: Qt.font({ family: dapFonts.dapProjectFonts[2].name }) + + ///@details dapFontRobotoMediumItalic14 Font of Roboto font family (medium-italic, 14pt) + property font dapFontRobotoMediumItalic14: Qt.font({ + family: dapFonts.dapProjectFonts[2].name, + bold: false, + italic: true, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoMediumItalicCustom Font of Roboto font family (medium-italic, without parameters) + property font dapFontRobotoMediumItalicCustom: Qt.font({ + family: dapFonts.dapProjectFonts[2].name, + italic: true + }) + + ///@details dapFontRobotoItalic14 Font of Roboto font family (italic, 14pt) + property font dapFontRobotoItalic14: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: true, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoItalicCustom Font of Roboto font family (italic, without parameters) + property font dapFontRobotoItalicCustom: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + italic: true + }) + + ///@details dapFontRobotoRegular14 Font of Roboto font family (regular, 14pt) + property font dapFontRobotoRegular14: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoRegular12 Font of Roboto font family (regular, 12pt) + property font dapFontRobotoRegular12: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 12 * dapFactor + }) + + ///@details dapFontRobotoRegular16 Font of Roboto font family (regular, 16pt) + property font dapFontRobotoRegular16: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 16 * dapFactor + }) + + ///@details dapFontRobotoRegular18 Font of Roboto font family (regular, 18pt) + property font dapFontRobotoRegular18: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 18 * dapFactor + }) + + ///@details dapFontRobotoRegular22 Font of Roboto font family (regular, 22pt) + property font dapFontRobotoRegular22: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 18 * dapFactor + }) + + ///@details dapFontRobotoRegular28 Font of Roboto font family (regular, 28pt) + property font dapFontRobotoRegular28: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 18 * dapFactor + }) + + ///@details dapFontRobotoRegularCustom Font of Roboto font family (regular, without parameters) + property font dapFontRobotoRegularCustom: Qt.font({ family: dapFonts.dapProjectFonts[3].name }) + + ///@details dapFontRobotoThin14 Font of Roboto font family (thin, 14pt) + property font dapFontRobotoThin14: Qt.font({ + family: dapFonts.dapProjectFonts[4].name, + bold: false, + italic: false, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoThinCustom Font of Roboto font family (thin, without parameters) + property font dapFontRobotoThinCustom: Qt.font({ family: dapFonts.dapProjectFonts[4].name }) + + ///@details dapFontRobotoThinItalic14 Font of Roboto font family (thin-italic, 14pt) + property font dapFontRobotoThinItalic14: Qt.font({ + family: dapFonts.dapProjectFonts[4].name, + bold: false, + italic: true, + pixelSize: 14 * dapFactor + }) + + ///@details dapFontRobotoThinItalicCustom Font of Roboto font family (thin-italic, without parameters) + property font dapFontRobotoThinItalicCustom: Qt.font({ + family: dapFonts.dapProjectFonts[4].name, + italic: true + }) + + ///@details dapFontRobotoRegular11 Font of Roboto font family (regular, 11pt) + property font dapFontRobotoRegular11: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 11 * dapFactor + }) + + ///@details dapFontRobotoRegular10 Font of Roboto font family (regular, 10pt) + property font dapFontRobotoRegular10: Qt.font({ + family: dapFonts.dapProjectFonts[3].name, + bold: false, + italic: false, + pixelSize: 10 * dapFactor + }) + } +} diff --git a/ui/chain/wallet/resources/fonts/LICENSE.txt b/ui/chain/wallet/resources/fonts/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7 --- /dev/null +++ b/ui/chain/wallet/resources/fonts/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ui/chain/wallet/resources/fonts/roboto_black.ttf b/ui/chain/wallet/resources/fonts/roboto_black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..51c71bbe2d565247a020319ff9b324e8c8e05353 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_black.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_black_italic.ttf b/ui/chain/wallet/resources/fonts/roboto_black_italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ca20ca399981d14c441b9ea2f3decc1c88e69da4 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_black_italic.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_bold.ttf b/ui/chain/wallet/resources/fonts/roboto_bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e612852d259930d0dcc632318ac0f15ae312422b Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_bold.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_bold_italic.ttf b/ui/chain/wallet/resources/fonts/roboto_bold_italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..677bc045e565c7b74c3ce0f8ad55df305bb28a29 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_bold_italic.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_italic.ttf b/ui/chain/wallet/resources/fonts/roboto_italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5fd05c3b645a8fdcdeffae18bffc19369514a76a Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_italic.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_light.ttf b/ui/chain/wallet/resources/fonts/roboto_light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f1fb5805f432036d390a353c43191f06b0ad6e0 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_light.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_light_italic.ttf b/ui/chain/wallet/resources/fonts/roboto_light_italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..eec0ae9be8f8f74279afe5253de5286c04fc2fad Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_light_italic.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_medium.ttf b/ui/chain/wallet/resources/fonts/roboto_medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..86d1c52ed5ee125fdfa6ed63a58f5c02f08dd246 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_medium.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_medium_italic.ttf b/ui/chain/wallet/resources/fonts/roboto_medium_italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..66aa174f058481c39bcd60bdb464a1b3f78e4dcc Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_medium_italic.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_regular.ttf b/ui/chain/wallet/resources/fonts/roboto_regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cb8ffcf1ad2c163bbf95ce6ff829b537d8bebd18 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_regular.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_thin.ttf b/ui/chain/wallet/resources/fonts/roboto_thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a85eb7c29505713608ec9fd8489944977914be21 Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_thin.ttf differ diff --git a/ui/chain/wallet/resources/fonts/roboto_thin_italic.ttf b/ui/chain/wallet/resources/fonts/roboto_thin_italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ac77951b80fc3ad37533dcae49c9e8085c42f1fb Binary files /dev/null and b/ui/chain/wallet/resources/fonts/roboto_thin_italic.ttf differ