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