From 8615e8f33fb53a31d6226098a53808139d169210 Mon Sep 17 00:00:00 2001
From: "littletux89@gmail.com" <littletux89@gmail.com>
Date: Wed, 5 Feb 2020 18:37:26 +0300
Subject: [PATCH] [+] Added functionality.

---
 .../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 baeed08f0..79c47f2b6 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 73103963d..78c135d4f 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 fdd8fd57c..45975e533 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 79fc3e611..c62d0bc1d 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 aa7a4b51a..3d6752788 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 c27d9ef11..f797c0e29 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 b5d91d91c..1130cdf80 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 07f38726c..2f13e5ea2 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 941b56759..e7ca31b2e 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 ad310790a..fa1ab2217 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 d0a46e906..f2fe31f3c 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 9468e5733..ba563b0eb 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 0982b4245..de3ec6744 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 000000000..9c10cb29d
--- /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 000000000..df760d199
--- /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 1a7e5b027..79adcecf8 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 fb16b4985..ecfac60c6 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 089ff09bc..e6d396425 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 202f38eff..6d7c22827 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 aada237ca..8571bd6fa 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 ba6c4d246..cbd1b2983 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 97e16726a..5f08999f4 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 a82bad16d..3947203cc 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 000000000..0960e4702
--- /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 000000000..f224cb400
--- /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 000000000..b5e1f8829
--- /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 000000000..f49823098
--- /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 bbd3e0885..57abec009 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 027bdfa29..862e081c9 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