From 0ac4d37163ab6426522cacad531d68bd96bd9140 Mon Sep 17 00:00:00 2001
From: "andrey.daragan" <daragan.andrey@demlabs.net>
Date: Wed, 5 Feb 2020 15:56:18 +0000
Subject: [PATCH] features-3087

---
 .../DapServiceController.cpp                  |  7 +++
 CellFrameDashboardGUI/DapServiceController.h  |  9 ++++
 .../desktop/Console/DapConsoleRightPanel.qml  | 28 ++++-------
 .../desktop/Console/DapConsoleScreen.qml      | 25 +++-------
 .../screen/desktop/Console/DapConsoleTab.qml  | 23 ++++++++-
 .../desktop/Console/DapConsoleTabForm.ui.qml  |  5 ++
 .../CellFrameDashboardService.pro             |  4 +-
 .../DapServiceController.cpp                  |  6 +++
 .../DapServiceController.h                    |  3 ++
 .../Handlers/DapAbstractCommand.cpp           |  7 +--
 .../Handlers/DapAbstractCommand.h             |  5 +-
 .../Handlers/DapCreateTransactionCommand.cpp  |  2 +-
 .../Handlers/DapCreateTransactionCommand.h    |  3 --
 .../DapGetHistoryExecutedCmdCommand.cpp       | 48 +++++++++++++++++++
 .../DapGetHistoryExecutedCmdCommand.h         | 35 ++++++++++++++
 .../Handlers/DapGetListNetworksCommand.cpp    |  2 +-
 .../Handlers/DapGetListNetworksCommand.h      |  3 --
 .../Handlers/DapGetListWalletsCommand.cpp     |  2 +-
 .../Handlers/DapGetListWalletsCommand.h       |  3 --
 .../Handlers/DapGetWalletHistoryCommand.cpp   |  2 +-
 .../Handlers/DapGetWalletHistoryCommand.h     |  3 --
 .../Handlers/DapMempoolProcessCommand.cpp     |  2 +-
 .../Handlers/DapMempoolProcessCommand.h       |  3 --
 .../Handlers/DapRunCmdCommand.cpp             | 42 ++++++++++++++++
 .../Handlers/DapRunCmdCommand.h               | 31 ++++++++++++
 .../DapSaveHistoryExecutedCmdCommand.cpp      | 42 ++++++++++++++++
 .../DapSaveHistoryExecutedCmdCommand.h        | 34 +++++++++++++
 .../Handlers/DapUpdateLogsCommand.cpp         |  2 +-
 .../libCellFrameDashboardCommon.pri           |  6 +++
 29 files changed, 321 insertions(+), 66 deletions(-)
 create mode 100644 libCellFrameDashboardCommon/Handlers/DapGetHistoryExecutedCmdCommand.cpp
 create mode 100644 libCellFrameDashboardCommon/Handlers/DapGetHistoryExecutedCmdCommand.h
 create mode 100644 libCellFrameDashboardCommon/Handlers/DapRunCmdCommand.cpp
 create mode 100644 libCellFrameDashboardCommon/Handlers/DapRunCmdCommand.h
 create mode 100644 libCellFrameDashboardCommon/Handlers/DapSaveHistoryExecutedCmdCommand.cpp
 create mode 100644 libCellFrameDashboardCommon/Handlers/DapSaveHistoryExecutedCmdCommand.h

diff --git a/CellFrameDashboardGUI/DapServiceController.cpp b/CellFrameDashboardGUI/DapServiceController.cpp
index baeed08..79c47f2 100644
--- a/CellFrameDashboardGUI/DapServiceController.cpp
+++ b/CellFrameDashboardGUI/DapServiceController.cpp
@@ -128,6 +128,13 @@ void DapServiceController::registerCommand()
     m_transceivers.append(qMakePair(dynamic_cast<DapAbstractCommand*>(m_DAPRpcSocket->addService(new DapMempoolProcessCommand("DapMempoolProcessCommand",m_DAPRpcSocket))), QString("mempoolProcessed")));
 
     m_transceivers.append(qMakePair(dynamic_cast<DapAbstractCommand*>(m_DAPRpcSocket->addService(new DapGetWalletHistoryCommand("DapGetWalletHistoryCommand",m_DAPRpcSocket))), QString("historyReceived")));
+    // Run cli command
+    m_transceivers.append(qMakePair(dynamic_cast<DapAbstractCommand*>(m_DAPRpcSocket->addService(new DapRunCmdCommand("DapRunCmdCommand",m_DAPRpcSocket))), QString("cmdRunned")));
+    // Get history of commands executed by cli handler
+    m_transceivers.append(qMakePair(dynamic_cast<DapAbstractCommand*>(m_DAPRpcSocket->addService(new DapGetHistoryExecutedCmdCommand("DapGetHistoryExecutedCmdCommand",m_DAPRpcSocket))), QString("historyExecutedCmdReceived")));
+    // Save cmd command in file
+    m_transceivers.append(qMakePair(dynamic_cast<DapAbstractCommand*>(m_DAPRpcSocket->addService(new DapSaveHistoryExecutedCmdCommand("DapSaveHistoryExecutedCmdCommand",m_DAPRpcSocket))), QString()));
+
 
     connect(this, &DapServiceController::walletsListReceived, [=] (const QVariant& walletList)
     {
diff --git a/CellFrameDashboardGUI/DapServiceController.h b/CellFrameDashboardGUI/DapServiceController.h
index 7310396..78c135d 100644
--- a/CellFrameDashboardGUI/DapServiceController.h
+++ b/CellFrameDashboardGUI/DapServiceController.h
@@ -25,6 +25,9 @@
 #include "Handlers/DapCreateTransactionCommand.h"
 #include "Handlers/DapMempoolProcessCommand.h"
 #include "Handlers/DapGetWalletHistoryCommand.h"
+#include "Handlers/DapRunCmdCommand.h"
+#include "Handlers/DapGetHistoryExecutedCmdCommand.h"
+#include "Handlers/DapSaveHistoryExecutedCmdCommand.h"
 
 class DapServiceController : public QObject
 {
@@ -145,6 +148,12 @@ signals:
     void historyReceived(const QVariant& walletHistory);
 
     void walletHistoryReceived(const QList<QObject*>& walletHistory);
+    /// The signal is emitted when the command is executed by the cli node command handler.
+    /// @param asAnswer The response of the cli node command handler.
+    void cmdRunned(const QVariant& asAnswer);
+    /// The signal is emitted when receiving a history of commands executed by the cli handler.
+    /// @param aHistory History of commands executed by cli handler.
+    void historyExecutedCmdReceived(const QVariant& aHistory);
     
 private slots:
     /// Register command.
diff --git a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleRightPanel.qml b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleRightPanel.qml
index fdd8fd5..45975e5 100644
--- a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleRightPanel.qml
+++ b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleRightPanel.qml
@@ -2,6 +2,7 @@ import QtQuick 2.4
 
 DapConsoleRightPanelForm
 {
+    property alias dapModelHistoryConsole: modelHistoryConsole
     ///@detalis commandQuery Command for history.
     property string commandQuery
     ///@detalis historyQuery Text of command from the command history.
@@ -9,27 +10,14 @@ DapConsoleRightPanelForm
     ///@detalis historySize Num of history command at right panel.
     property int historySize: 10
 
-    dapRightPanelWidth: visible ? 300 * pt : 0 * pt
-
     ListModel
     {
         id: modelHistoryConsole
-        ListElement
-        {
-            query: "help1"
-        }
-        ListElement
-        {
-            query: "wallet list1"
-        }
-        ListElement
-        {
-            query: "help2"
-        }
-        ListElement
-        {
-            query: "wallet list2"
-        }
+    }
+
+    Component.onCompleted:
+    {
+        dapServiceController.requestToService("DapGetHistoryExecutedCmdCommand", historySize);
     }
 
     //Returns true if item 'someElement' is already exist at list 'someModel'.
@@ -53,13 +41,17 @@ DapConsoleRightPanelForm
         if(!findElement(modelHistoryConsole, {query: commandQuery}))
         {
             if(commandQuery !== "")
+            {
                 modelHistoryConsole.insert(0, {query: commandQuery});
+            }
         }
         else
             modelHistoryConsole.insert(0, {query: commandQuery});
 
         //History is limited by historySize and realized as FIFO
         if(historySize < modelHistoryConsole.count)
+        {
             modelHistoryConsole.remove(modelHistoryConsole.count-1);
+        }
     }
 }
diff --git a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleScreen.qml b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleScreen.qml
index 79fc3e6..c62d0bc 100644
--- a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleScreen.qml
+++ b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleScreen.qml
@@ -4,6 +4,7 @@ import QtQuick.Layouts 1.0
 
 DapConsoleScreenForm
 {
+    property alias dapModelConsoleCommand: modelConsoleCommand
     ///@detalis sendCommand Text of command from the inputCommand
     property string sendCommand
     ///@detalis historyCommand Text of command from the command history
@@ -11,6 +12,8 @@ DapConsoleScreenForm
     ///@detalis receivedAnswer Answer for the sended command
     property string receivedAnswer
 
+    signal runCommand(string command)
+
 
     Component.onCompleted:
     {
@@ -41,23 +44,6 @@ DapConsoleScreenForm
     ListModel
     {
         id: modelConsoleCommand
-        ListElement
-        {
-            query: "Command"
-            response: "This answer"
-        }
-        ListElement
-        {
-            query: "Command"
-            response: "This answer may be very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very long"
-        }
-        ListElement
-        {
-            query: "One little query"
-            response: "One little response"
-        }
-
-
     }
 
     Component
@@ -89,9 +75,10 @@ DapConsoleScreenForm
         if(sendedCommand != "")
         {
             sendCommand = sendedCommand;
-            modelConsoleCommand.append({query: sendedCommand, response: receivedAnswer});
             consoleHistoryIndex = modelConsoleCommand.count;
+            runCommand(sendCommand)
             sendedCommand = "";
+            currentCommand = sendedCommand;
         }
     }
 
@@ -99,7 +86,7 @@ DapConsoleScreenForm
     onHistoryCommandChanged:
     {
         sendCommand = historyCommand;
-        modelConsoleCommand.append({query: sendCommand, response: receivedAnswer});
+        runCommand(sendCommand)
         consoleHistoryIndex = modelConsoleCommand.count;
     }
 
diff --git a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTab.qml b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTab.qml
index aa7a4b5..3d67527 100644
--- a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTab.qml
+++ b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTab.qml
@@ -3,6 +3,25 @@ import "qrc:/"
 
 DapConsoleTabForm
 {
-    //The console interface need in command handler
-    // Handler answer must be set to rAnswer
+    dapConsoleScreen.onRunCommand:
+    {
+        dapServiceController.requestToService("DapRunCmdCommand", command);
+        dapServiceController.notifyService("DapSaveHistoryExecutedCmdCommand", command);
+    }
+
+    Connections
+    {
+        target: dapServiceController
+        onCmdRunned:
+        {
+            dapConsoleScreen.dapModelConsoleCommand.append({query: asAnswer[0], response: asAnswer[1]});
+        }
+        onHistoryExecutedCmdReceived:
+        {
+            for(var x=0; x < aHistory.length; ++x)
+            {
+                dapScreen.sendCommand = aHistory[x]
+            }
+        }
+    }
 }
diff --git a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTabForm.ui.qml b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTabForm.ui.qml
index c27d9ef..f797c0e 100644
--- a/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTabForm.ui.qml
+++ b/CellFrameDashboardGUI/screen/desktop/Console/DapConsoleTabForm.ui.qml
@@ -6,6 +6,8 @@ DapAbstractTab
 {
     id: consoleTab
 
+    property alias dapConsoleScreen: consoleScreen
+    property alias dapConsoleRigthPanel: consoleRigthPanel
     ///@detalis rAnswer Answer for the sended command
     property string rAnswer
 
@@ -14,6 +16,7 @@ DapAbstractTab
     dapScreen:
         DapConsoleScreen
         {
+            id: consoleScreen
             //Set receivedAnswer of dapScreen to the external variable rAnswer for the displaying it in console
             receivedAnswer: rAnswer
             //Assign historyCommand of dapScreen with dapRightPanel.historyQuery for ability to use right history panel to send command to the console
@@ -23,6 +26,8 @@ DapAbstractTab
     dapRightPanel:
         DapConsoleRightPanel
         {
+            id: consoleRigthPanel
+            anchors.fill: parent
             //Assign commandQuery of dapRightPanel with dapScreen.sendCommand for set it to right history panelfrome console
             commandQuery: dapScreen.sendCommand
         }
diff --git a/CellFrameDashboardService/CellFrameDashboardService.pro b/CellFrameDashboardService/CellFrameDashboardService.pro
index b5d91d9..1130cdf 100755
--- a/CellFrameDashboardService/CellFrameDashboardService.pro
+++ b/CellFrameDashboardService/CellFrameDashboardService.pro
@@ -20,14 +20,14 @@ win32 {
     VERSION = $${VER_MAJ}.$${VER_MIN}.$$VER_PAT
     DEFINES += CLI_PATH=\\\"./cellframe-node-cli.exe\\\"
     DEFINES += LOG_FILE=\\\"./opt/cellframe-node/var/log/cellframe-node.log\\\"
-    DEFINES += CMD_LOG=\\\"./opt/cellframe-dashboard/data/cellframe-cmd_log.txt\\\"
+    DEFINES += CMD_HISTORY=\\\"./opt/cellframe-dashboard/data/cmd_history.txt\\\"
     DEFINES += HAVE_STRNDUP
 }
 else {
     VERSION = $$VER_MAJ\.$$VER_MIN\-$$VER_PAT
     DEFINES += CLI_PATH=\\\"/opt/cellframe-node/bin/cellframe-node-cli\\\"
     DEFINES += LOG_FILE=\\\"/opt/cellframe-node/var/log/cellframe-node.log\\\"
-    DEFINES += CMD_LOG=\\\"/opt/cellframe-dashboard/data/cellframe-cmd_log.txt\\\"
+    DEFINES += CMD_HISTORY=\\\"/opt/cellframe-dashboard/data/cmd_history.txt\\\"
 }
 
 # The following define makes your compiler emit warnings if you use
diff --git a/CellFrameDashboardService/DapServiceController.cpp b/CellFrameDashboardService/DapServiceController.cpp
index 07f3872..2f13e5e 100755
--- a/CellFrameDashboardService/DapServiceController.cpp
+++ b/CellFrameDashboardService/DapServiceController.cpp
@@ -68,6 +68,12 @@ void DapServiceController::registerCommand()
     m_pServer->addService(new DapMempoolProcessCommand("DapMempoolProcessCommand", m_pServer, CLI_PATH));
 
     m_pServer->addService(new DapGetWalletHistoryCommand("DapGetWalletHistoryCommand", m_pServer, CLI_PATH));
+    // Run cli command
+    m_pServer->addService(new DapRunCmdCommand("DapRunCmdCommand", m_pServer, CLI_PATH));
+    // Get history of commands executed by cli handler
+    m_pServer->addService(new DapGetHistoryExecutedCmdCommand("DapGetHistoryExecutedCmdCommand", m_pServer, CMD_HISTORY));
+    // Save cmd command in file
+    m_pServer->addService(new DapSaveHistoryExecutedCmdCommand("DapSaveHistoryExecutedCmdCommand", m_pServer, CMD_HISTORY));
 }
 
 /// Initialize system tray.
diff --git a/CellFrameDashboardService/DapServiceController.h b/CellFrameDashboardService/DapServiceController.h
index 941b567..e7ca31b 100755
--- a/CellFrameDashboardService/DapServiceController.h
+++ b/CellFrameDashboardService/DapServiceController.h
@@ -36,6 +36,9 @@ typedef class DapRpcLocalServer DapUiService;
 #include "Handlers/DapCreateTransactionCommand.h"
 #include "Handlers/DapMempoolProcessCommand.h"
 #include "Handlers/DapGetWalletHistoryCommand.h"
+#include "Handlers/DapRunCmdCommand.h"
+#include "Handlers/DapGetHistoryExecutedCmdCommand.h"
+#include "Handlers/DapSaveHistoryExecutedCmdCommand.h"
 #include "DapSystemTrayIcon.h"
 #include "DapToolTipWidget.h"
 
diff --git a/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.cpp
index ad31079..fa1ab22 100644
--- a/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.cpp
@@ -4,8 +4,9 @@
 /// @param asServiceName Service name.
 /// @param parent Parent.
 /// @details The parent must be either DapRPCSocket or DapRPCLocalServer.
-DapAbstractCommand::DapAbstractCommand(const QString &asServiceName, QObject *parent)
-    : DapCommand(asServiceName, parent), m_parent(parent)
+/// @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)
 {
 
 }
@@ -146,7 +147,7 @@ void DapAbstractCommand::notifyToService(const QVariant &arg1, const QVariant &a
 
     Q_ASSERT(socket);
 
-    DapRpcMessage notify = DapRpcMessage::createNotification(QString("%1.%2").arg(this->getName()).arg("respondToClient"), QJsonArray::fromVariantList(params));
+    DapRpcMessage notify = DapRpcMessage::createNotification(QString("%1.%2").arg(this->getName()).arg("notifedFromClient"), QJsonArray::fromVariantList(params));
     socket->notify(notify);
 }
 
diff --git a/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.h b/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.h
index d0a46e9..f2fe31f 100644
--- a/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.h
+++ b/libCellFrameDashboardCommon/Handlers/DapAbstractCommand.h
@@ -24,11 +24,14 @@ class DapAbstractCommand : public DapCommand
 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.
-    explicit DapAbstractCommand(const QString &asServiceName, QObject *parent = nullptr);
+    /// @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.
diff --git a/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.cpp
index 9468e57..ba563b0 100644
--- a/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.cpp
@@ -6,7 +6,7 @@
 /// @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), m_sCliPath(asCliPath)
+    : DapAbstractCommand(asServicename, parent, asCliPath)
 {
 
 }
diff --git a/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.h b/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.h
index 0982b42..de3ec67 100644
--- a/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.h
+++ b/libCellFrameDashboardCommon/Handlers/DapCreateTransactionCommand.h
@@ -7,9 +7,6 @@
 
 class DapCreateTransactionCommand : public DapAbstractCommand
 {
-    /// The path to cli nodes.
-    QString m_sCliPath;
-
 public:
     /// Overloaded constructor.
     /// @param asServiceName Service name.
diff --git a/libCellFrameDashboardCommon/Handlers/DapGetHistoryExecutedCmdCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapGetHistoryExecutedCmdCommand.cpp
new file mode 100644
index 0000000..9c10cb2
--- /dev/null
+++ b/libCellFrameDashboardCommon/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/libCellFrameDashboardCommon/Handlers/DapGetHistoryExecutedCmdCommand.h b/libCellFrameDashboardCommon/Handlers/DapGetHistoryExecutedCmdCommand.h
new file mode 100644
index 0000000..df760d1
--- /dev/null
+++ b/libCellFrameDashboardCommon/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/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.cpp
index 1a7e5b0..79adcec 100644
--- a/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.cpp
@@ -6,7 +6,7 @@
 /// @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), m_sCliPath(asCliPath)
+    : DapAbstractCommand(asServicename, parent, asCliPath)
 {
 
 }
diff --git a/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.h b/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.h
index fb16b49..ecfac60 100644
--- a/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.h
+++ b/libCellFrameDashboardCommon/Handlers/DapGetListNetworksCommand.h
@@ -7,9 +7,6 @@
 
 class DapGetListNetworksCommand : public DapAbstractCommand
 {
-    /// The path to cli nodes.
-    QString m_sCliPath;
-
 public:
     /// Overloaded constructor.
     /// @param asServiceName Service name.
diff --git a/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.cpp
index 089ff09..e6d3964 100644
--- a/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.cpp
@@ -6,7 +6,7 @@
 /// @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), m_sCliPath(asCliPath)
+    : DapAbstractCommand(asServicename, parent, asCliPath)
 {
 
 }
diff --git a/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.h b/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.h
index 202f38e..6d7c228 100644
--- a/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.h
+++ b/libCellFrameDashboardCommon/Handlers/DapGetListWalletsCommand.h
@@ -14,9 +14,6 @@
 
 class DapGetListWalletsCommand : public DapAbstractCommand
 {
-    /// The path to cli nodes.
-    QString m_sCliPath;
-
 public:
     /// Overloaded constructor.
     /// @param asServiceName Service name.
diff --git a/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.cpp
index aada237..8571bd6 100644
--- a/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.cpp
@@ -6,7 +6,7 @@
 /// @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), m_sCliPath(asCliPath)
+    : DapAbstractCommand(asServicename, parent, asCliPath)
 {
 
 }
diff --git a/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.h b/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.h
index ba6c4d2..cbd1b29 100644
--- a/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.h
+++ b/libCellFrameDashboardCommon/Handlers/DapGetWalletHistoryCommand.h
@@ -12,9 +12,6 @@
 
 class DapGetWalletHistoryCommand : public DapAbstractCommand
 {
-    /// The path to cli nodes.
-    QString m_sCliPath;
-
 public:
     /// Overloaded constructor.
     /// @param asServiceName Service name.
diff --git a/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.cpp
index 97e1672..5f08999 100644
--- a/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.cpp
@@ -6,7 +6,7 @@
 /// @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), m_sCliPath(asCliPath)
+    : DapAbstractCommand(asServicename, parent, asCliPath)
 {
 
 }
diff --git a/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.h b/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.h
index a82bad1..3947203 100644
--- a/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.h
+++ b/libCellFrameDashboardCommon/Handlers/DapMempoolProcessCommand.h
@@ -7,9 +7,6 @@
 
 class DapMempoolProcessCommand : public DapAbstractCommand
 {
-    /// The path to cli nodes.
-    QString m_sCliPath;
-
 public:
     /// Overloaded constructor.
     /// @param asServiceName Service name.
diff --git a/libCellFrameDashboardCommon/Handlers/DapRunCmdCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapRunCmdCommand.cpp
new file mode 100644
index 0000000..0960e47
--- /dev/null
+++ b/libCellFrameDashboardCommon/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/libCellFrameDashboardCommon/Handlers/DapRunCmdCommand.h b/libCellFrameDashboardCommon/Handlers/DapRunCmdCommand.h
new file mode 100644
index 0000000..f224cb4
--- /dev/null
+++ b/libCellFrameDashboardCommon/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/libCellFrameDashboardCommon/Handlers/DapSaveHistoryExecutedCmdCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapSaveHistoryExecutedCmdCommand.cpp
new file mode 100644
index 0000000..b5e1f88
--- /dev/null
+++ b/libCellFrameDashboardCommon/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/libCellFrameDashboardCommon/Handlers/DapSaveHistoryExecutedCmdCommand.h b/libCellFrameDashboardCommon/Handlers/DapSaveHistoryExecutedCmdCommand.h
new file mode 100644
index 0000000..f498230
--- /dev/null
+++ b/libCellFrameDashboardCommon/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/libCellFrameDashboardCommon/Handlers/DapUpdateLogsCommand.cpp b/libCellFrameDashboardCommon/Handlers/DapUpdateLogsCommand.cpp
index bbd3e08..57abec0 100644
--- a/libCellFrameDashboardCommon/Handlers/DapUpdateLogsCommand.cpp
+++ b/libCellFrameDashboardCommon/Handlers/DapUpdateLogsCommand.cpp
@@ -20,7 +20,7 @@ DapUpdateLogsCommand::DapUpdateLogsCommand(const QString &asServiceName, QObject
 
         connect(m_watcherDapLogFile, &QFileSystemWatcher::fileChanged, this, [&]
         {
-            notifyToClient();
+//            notifyToClient();
         });
     }
 }
diff --git a/libCellFrameDashboardCommon/libCellFrameDashboardCommon.pri b/libCellFrameDashboardCommon/libCellFrameDashboardCommon.pri
index 027bdfa..862e081 100755
--- a/libCellFrameDashboardCommon/libCellFrameDashboardCommon.pri
+++ b/libCellFrameDashboardCommon/libCellFrameDashboardCommon.pri
@@ -24,6 +24,7 @@ SOURCES +=\
     $$PWD/DapWalletHistoryEvent.cpp \
     $$PWD/Handlers/DapAbstractCommand.cpp \
     $$PWD/Handlers/DapActivateClientCommand.cpp \
+    $$PWD/Handlers/DapGetHistoryExecutedCmdCommand.cpp \
     $$PWD/Handlers/DapGetListNetworksCommand.cpp \
     $$PWD/Handlers/DapGetListWalletsCommand.cpp \
     $$PWD/Handlers/DapExportLogCommand.cpp \
@@ -34,6 +35,8 @@ SOURCES +=\
     $$PWD/Handlers/DapMempoolProcessCommand.cpp \
     $$PWD/Handlers/DapQuitApplicationCommand.cpp \
     $$PWD/Handlers/DapAddWalletCommand.cpp \
+    $$PWD/Handlers/DapRunCmdCommand.cpp \
+    $$PWD/Handlers/DapSaveHistoryExecutedCmdCommand.cpp \
     $$PWD/Handlers/DapUpdateLogsCommand.cpp \
     $$PWD/Models/DapWalletModel.cpp
 
@@ -50,6 +53,7 @@ HEADERS +=\
     $$PWD/DapWalletHistoryEvent.h\
     $$PWD/Handlers/DapAbstractCommand.h \
     $$PWD/Handlers/DapActivateClientCommand.h \
+    $$PWD/Handlers/DapGetHistoryExecutedCmdCommand.h \
     $$PWD/Handlers/DapGetListNetworksCommand.h \
     $$PWD/Handlers/DapGetListWalletsCommand.h \
     $$PWD/Handlers/DapExportLogCommand.h \
@@ -60,5 +64,7 @@ HEADERS +=\
     $$PWD/Handlers/DapMempoolProcessCommand.h \
     $$PWD/Handlers/DapQuitApplicationCommand.h \
     $$PWD/Handlers/DapAddWalletCommand.h \
+    $$PWD/Handlers/DapRunCmdCommand.h \
+    $$PWD/Handlers/DapSaveHistoryExecutedCmdCommand.h \
     $$PWD/Handlers/DapUpdateLogsCommand.h \
     $$PWD/Models/DapWalletModel.h
-- 
GitLab