From 632f62265b722de6f519cb4abdf2847c60a1e68b Mon Sep 17 00:00:00 2001
From: Dmitry Puzyrkov <dmitry.puzyrkov@demlabs.net>
Date: Mon, 8 Jul 2024 13:05:12 +0000
Subject: [PATCH] Feature conftool servicectl

---
 conftool/CMakeLists.txt                |   6 +-
 conftool/commands/abstractcommand.cpp  |   4 +-
 conftool/commands/conditioncommand.cpp |   1 -
 conftool/commands/servicecommand.cpp   |  87 +++++++++++++
 conftool/commands/servicecommand.h     |  11 ++
 conftool/commands/storagecommand.cpp   |   1 +
 conftool/main.cpp                      | 164 ++++++++++++++-----------
 conftool/service/service.h             |  25 ++++
 conftool/service/service_linux.cpp     |  54 ++++++++
 conftool/service/service_macos.cpp     |  44 +++++++
 conftool/service/service_win.cpp       |  81 ++++++++++++
 dist/share/default.setup               |  12 +-
 os/debian/postinst                     |   7 +-
 os/macos/PKGINSTALL/postinstall        |   6 +-
 os/windows/cellframe-node.nsis         |   7 +-
 15 files changed, 430 insertions(+), 80 deletions(-)
 create mode 100644 conftool/commands/servicecommand.cpp
 create mode 100644 conftool/commands/servicecommand.h
 create mode 100644 conftool/service/service.h
 create mode 100644 conftool/service/service_linux.cpp
 create mode 100644 conftool/service/service_macos.cpp
 create mode 100644 conftool/service/service_win.cpp

diff --git a/conftool/CMakeLists.txt b/conftool/CMakeLists.txt
index 8c53fdd2d..c7079a567 100644
--- a/conftool/CMakeLists.txt
+++ b/conftool/CMakeLists.txt
@@ -31,8 +31,12 @@ add_executable(${PROJECT_NAME} ./main.cpp
                                 ./commands/conditioncommand.cpp
                                 ./commands/storagecommand.cpp
                                 ./commands/configcommand.cpp
+                                ./commands/servicecommand.cpp
                                 ./commands/fromtemplatecommand.cpp
-                                ./config/cellframeconfigfile.cpp)
+                                ./config/cellframeconfigfile.cpp
+                                ./service/service_win.cpp
+                                ./service/service_linux.cpp
+                                ./service/service_macos.cpp)
 
 target_link_libraries(cellframe-node-config
   PRIVATE ftxui::screen
diff --git a/conftool/commands/abstractcommand.cpp b/conftool/commands/abstractcommand.cpp
index 9cd8bc7b5..fe79b8315 100644
--- a/conftool/commands/abstractcommand.cpp
+++ b/conftool/commands/abstractcommand.cpp
@@ -57,4 +57,6 @@ bool CAbstractScriptCommand::is_condition_open(){
 }
 bool CAbstractScriptCommand::is_condition_close(){
     return false;
-}
\ No newline at end of file
+}
+
+std::map<std::string, std::string> variable_storage;
\ No newline at end of file
diff --git a/conftool/commands/conditioncommand.cpp b/conftool/commands/conditioncommand.cpp
index 2f62ae742..d02ea1f33 100644
--- a/conftool/commands/conditioncommand.cpp
+++ b/conftool/commands/conditioncommand.cpp
@@ -91,4 +91,3 @@ bool CConditionCloseCommand::execute(bool non_intercative, int flags)
 {   
     return true;
 }
-std::map<std::string, std::string> variable_storage;
\ No newline at end of file
diff --git a/conftool/commands/servicecommand.cpp b/conftool/commands/servicecommand.cpp
new file mode 100644
index 000000000..c94bad005
--- /dev/null
+++ b/conftool/commands/servicecommand.cpp
@@ -0,0 +1,87 @@
+#include "servicecommand.h"
+#include <stdexcept>
+#include <filesystem>
+
+#include "../build_config.h"
+#include "../config/cellframeconfigfile.h"
+#include "../service/service.h"
+
+namespace fs = std::filesystem;
+
+CAbstractScriptCommand::Registrar<CServiceCommand> service_registrar("service");
+
+
+CServiceCommand::CServiceCommand(std::vector <std::string> cmd_tokens): CAbstractScriptCommand(cmd_tokens)
+{   
+    //zero token is always a command (network)
+    
+    if (cmd_tokens.size() < 2)
+        throw std::invalid_argument("service command require action argument");
+    
+    this->action = cmd_tokens[1];
+}
+
+bool CServiceCommand::execute(bool non_intercative, int flags)
+{ 
+    if (this->action == "enable"){
+        if (CServiceControl::enable()) {
+            std::cout << "enabled" <<std::endl;
+        }
+        else{
+            std::cout << "error" <<std::endl;
+        }
+    }
+    
+    if (this->action == "disable")
+    {
+       if (CServiceControl::disable()) {
+            std::cout << "disabled" <<std::endl;
+        }
+        else{
+            std::cout << "error" <<std::endl;
+        }
+    }
+
+    if (this->action == "status")
+    {
+        std::cout << (CServiceControl::serviceStatus() == ENABLED?"enabled":"disabled")<<std::endl;
+    }
+
+    if (this->action == "start")
+    {
+        if (CServiceControl::start())
+        {
+            std::cout << "started" << std::endl;
+        }
+        else
+        {
+            std::cout << "error" << std::endl;
+        }
+    }
+    
+    if (this->action == "stop")
+    {
+        if (CServiceControl::stop())
+        {
+            std::cout << "stoped" << std::endl;
+        }
+        else
+        {
+            std::cout << "error" << std::endl;
+        }
+    }
+
+    if (this->action == "restart")
+    {
+        if (CServiceControl::restart())
+        {
+            std::cout << "restarted" << std::endl;
+        }
+        else
+        {
+            std::cout << "error" << std::endl;
+        }
+    }
+   
+    return true;
+}
diff --git a/conftool/commands/servicecommand.h b/conftool/commands/servicecommand.h
new file mode 100644
index 000000000..a0b2f47a2
--- /dev/null
+++ b/conftool/commands/servicecommand.h
@@ -0,0 +1,11 @@
+#include "abstractcommand.h"
+
+class CServiceCommand : public CAbstractScriptCommand {
+    public:
+        CServiceCommand(std::vector <std::string> cmd_tokens);
+        static std::unique_ptr<CAbstractScriptCommand> create(std::vector <std::string> cmd_tokens) { return std::make_unique<CServiceCommand>(cmd_tokens); }
+        bool execute(bool non_interactive, int flags);
+    
+    private:
+        std::string action;
+};
diff --git a/conftool/commands/storagecommand.cpp b/conftool/commands/storagecommand.cpp
index e16c68bbb..b02a9f3c4 100644
--- a/conftool/commands/storagecommand.cpp
+++ b/conftool/commands/storagecommand.cpp
@@ -31,3 +31,4 @@ bool CVariableCommand::execute(bool non_intercative, int flags)
     }
     return true;
 }
+
diff --git a/conftool/main.cpp b/conftool/main.cpp
index 14df00e18..aa17d93d7 100644
--- a/conftool/main.cpp
+++ b/conftool/main.cpp
@@ -54,8 +54,101 @@ std::string getHostName(void)
     return res;
 }
 
+#ifdef WIN32
+
+LONG GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue)
+{
+    nValue = nDefaultValue;
+    DWORD dwBufferSize(sizeof(DWORD));
+    DWORD nResult(0);
+    LONG nError = ::RegQueryValueExW(hKey,
+        strValueName.c_str(),
+        0,
+        NULL,
+        reinterpret_cast<LPBYTE>(&nResult),
+        &dwBufferSize);
+    if (ERROR_SUCCESS == nError)
+    {
+        nValue = nResult;
+    }
+    return nError;
+}
+
+
+LONG GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue)
+{
+    DWORD nDefValue((bDefaultValue) ? 1 : 0);
+    DWORD nResult(nDefValue);
+    LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult, nDefValue);
+    if (ERROR_SUCCESS == nError)
+    {
+        bValue = (nResult != 0) ? true : false;
+    }
+    return nError;
+}
+
+
+LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue)
+{
+    strValue = strDefaultValue;
+    WCHAR szBuffer[512];
+    DWORD dwBufferSize = sizeof(szBuffer);
+    ULONG nError;
+    nError = RegQueryValueExW(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
+    if (ERROR_SUCCESS == nError)
+    {
+        strValue = szBuffer;
+    }
+    return nError;
+}
+
+#endif
+
 namespace fs = std::filesystem;
 
+std::string getNodeConfigPath(){
+    #ifdef __linux__ 
+        return "/opt/cellframe-node/";
+    #endif
+    
+    #ifdef __APPLE__ 
+        return  "/Applications/CellframeNode.app/Contents/Resources/";
+    #endif
+
+    #ifdef WIN32 
+        HKEY hKey;
+        LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hKey);
+        bool bExistsAndSuccess (lRes == ERROR_SUCCESS);
+        bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND);
+        std::wstring path;
+        GetStringRegKey(hKey, L"Common Documents", path, L"");
+        std::string stdpath(path.begin(),path.end());
+        return (std::filesystem::path{stdpath}/"cellframe-node/").string();
+    #endif
+}
+
+std::string getNodeBinaryPath(){
+    #ifdef __linux__ 
+        return "/opt/cellframe-node/bin/";
+    #endif
+    
+    #ifdef __APPLE__ 
+        return  "/Applications/CellframeNode.app/Contents/MacOS/";
+    #endif
+
+    #ifdef WIN32 
+        //HKLM "Software\${APP_NAME}" "Path"
+        HKEY hKey;
+        LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\cellframe-node\\", 0, KEY_READ, &hKey);
+        bool bExistsAndSuccess (lRes == ERROR_SUCCESS);
+        bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND);
+        std::wstring path;
+        GetStringRegKey(hKey, L"Path", path, L"");
+        std::string stdpath(path.begin(),path.end());
+        return (std::filesystem::path{stdpath}).string();
+    #endif
+}
+
 bool cmdOptionExists(char** begin, char** end, const std::string& option)
 {
     return std::find(begin, end, option) != end;
@@ -155,80 +248,13 @@ bool run_commands(std::vector <std::unique_ptr<CAbstractScriptCommand>> &command
     return true;
 }
 
-#ifdef WIN32
-
-LONG GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue)
-{
-    nValue = nDefaultValue;
-    DWORD dwBufferSize(sizeof(DWORD));
-    DWORD nResult(0);
-    LONG nError = ::RegQueryValueExW(hKey,
-        strValueName.c_str(),
-        0,
-        NULL,
-        reinterpret_cast<LPBYTE>(&nResult),
-        &dwBufferSize);
-    if (ERROR_SUCCESS == nError)
-    {
-        nValue = nResult;
-    }
-    return nError;
-}
-
-
-LONG GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue)
-{
-    DWORD nDefValue((bDefaultValue) ? 1 : 0);
-    DWORD nResult(nDefValue);
-    LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult, nDefValue);
-    if (ERROR_SUCCESS == nError)
-    {
-        bValue = (nResult != 0) ? true : false;
-    }
-    return nError;
-}
-
-
-LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue)
-{
-    strValue = strDefaultValue;
-    WCHAR szBuffer[512];
-    DWORD dwBufferSize = sizeof(szBuffer);
-    ULONG nError;
-    nError = RegQueryValueExW(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
-    if (ERROR_SUCCESS == nError)
-    {
-        strValue = szBuffer;
-    }
-    return nError;
-}
-
-#endif
 
 void populate_variables()
 {
     variable_storage["HOST_OS"] = HOST_OS;
     variable_storage["HOSTNAME"] = getHostName();
-
-    #ifdef __linux__ 
-        variable_storage["CONFIGS_PATH"] = "/opt/cellframe-node/";
-    #endif
-
-    #ifdef WIN32 
-        HKEY hKey;
-        LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hKey);
-        bool bExistsAndSuccess (lRes == ERROR_SUCCESS);
-        bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND);
-        std::wstring path;
-        GetStringRegKey(hKey, L"Common Documents", path, L"");
-        std::string stdpath(path.begin(),path.end());
-        variable_storage["CONFIGS_PATH"] = (std::filesystem::path{stdpath}/"cellframe-node/").string();
-    #endif
-
-    #ifdef __APPLE__ 
-        variable_storage["CONFIGS_PATH"] = "/Applications/CellframeNode.app/Contents/Resources/";
-    #endif
-
+    variable_storage["CONFIGS_PATH"] = getNodeConfigPath();
+    variable_storage["NODE_BINARY_PATH"] = getNodeBinaryPath();
 }
 
 int init_configs(int argc, char *argv[], int flags)
diff --git a/conftool/service/service.h b/conftool/service/service.h
new file mode 100644
index 000000000..ecc7fba61
--- /dev/null
+++ b/conftool/service/service.h
@@ -0,0 +1,25 @@
+#include <algorithm>
+#include <map>
+#include <string>
+#include <iostream>
+#include <cstdint>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <stdexcept>
+
+enum EServiceStatus{
+    ENABLED,
+    DISABLED,
+};
+
+struct CServiceControl
+{
+    static bool enable();
+    static bool disable();
+    static EServiceStatus serviceStatus();
+    static bool start();
+    static bool stop();
+    static bool restart();    
+};
\ No newline at end of file
diff --git a/conftool/service/service_linux.cpp b/conftool/service/service_linux.cpp
new file mode 100644
index 000000000..53107e64b
--- /dev/null
+++ b/conftool/service/service_linux.cpp
@@ -0,0 +1,54 @@
+ #ifdef __linux__ 
+
+#include "service.h"
+#include "../commands/abstractcommand.h"
+
+bool CServiceControl::enable(){
+    std::string cmd = "systemctl enable " + (std::filesystem::path{variable_storage["CONFIGS_PATH"]}/"share"/"cellframe-node.service").string();
+    int res = std::system(cmd.c_str());
+    
+    return res == 0 ? true : false;
+}
+
+bool CServiceControl::disable()
+{
+    std::string cmd = "systemctl disable cellframe-node.service";
+    int res = std::system(cmd.c_str());    
+    return res == 0 ? true : false;
+}
+
+EServiceStatus CServiceControl::serviceStatus()
+{
+    std::string cmd = "systemctl is-enabled cellframe-node.service";
+    int res = std::system(cmd.c_str());
+    switch (res)
+    {
+    case 0:
+        return ENABLED;
+    default:
+        return DISABLED;
+    }
+}
+
+bool CServiceControl::start()
+{
+    std::string cmd = "systemctl start cellframe-node.service";
+    int res = std::system(cmd.c_str());    
+    return res == 0 ? true : false;
+}
+
+bool CServiceControl::stop()
+{
+    std::string cmd = "systemctl stop cellframe-node.service";
+    int res = std::system(cmd.c_str());    
+    return res == 0 ? true : false;
+}
+
+bool CServiceControl::restart()
+{
+    std::string cmd = "systemctl restart cellframe-node.service";
+    int res = std::system(cmd.c_str());    
+    return res == 0 ? true : false;
+}    
+
+ #endif
\ No newline at end of file
diff --git a/conftool/service/service_macos.cpp b/conftool/service/service_macos.cpp
new file mode 100644
index 000000000..ed1f0c55c
--- /dev/null
+++ b/conftool/service/service_macos.cpp
@@ -0,0 +1,44 @@
+#ifdef __APPLE__
+
+#include "service.h"
+#include "../commands/abstractcommand.h"
+
+bool CServiceControl::enable()
+{
+    //starts too
+    int res = std::system("launchctl load -w /Library/LaunchDaemons/com.demlabs.cellframe-node.plist");
+    return res == 0 ? true : false;
+}
+
+bool CServiceControl::disable()
+{
+    //stops too
+    int res = std::system("launchctl unload -w /Library/LaunchDaemons/com.demlabs.cellframe-node.plist");
+    return res == 0 ? true : false;
+}
+
+EServiceStatus CServiceControl::serviceStatus()
+{
+    std::string cmd = std::string();
+    int res = std::system("launchctl list com.demlabs.cellframe-node");
+    return res == 0 ? ENABLED : DISABLED;
+}
+
+bool CServiceControl::start()
+{
+    return enable();
+}
+
+bool CServiceControl::stop()
+{
+    return disable();
+}
+
+bool CServiceControl::restart()
+{
+    stop();
+    start();
+    return true;
+}    
+
+#endif
\ No newline at end of file
diff --git a/conftool/service/service_win.cpp b/conftool/service/service_win.cpp
new file mode 100644
index 000000000..2a6606c7c
--- /dev/null
+++ b/conftool/service/service_win.cpp
@@ -0,0 +1,81 @@
+ #ifdef WIN32 
+
+#include "service.h"
+#include "../commands/abstractcommand.h"
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+
+
+int runShellAdmin(std::string app, std::string cmd)
+{
+    // Launch itself as admin
+    SHELLEXECUTEINFO sei = { sizeof(sei) };
+    sei.lpVerb = "runas";
+    sei.lpFile = app.c_str();
+    sei.lpParameters = cmd.c_str();
+    sei.hwnd = NULL;
+    sei.nShow = SW_HIDE;
+
+    if (!ShellExecuteEx(&sei))
+    {
+        DWORD dwError = GetLastError();
+        if (dwError == ERROR_CANCELLED)
+        {
+            std::cout << "End user did not allow elevation" << std::endl;
+            return -1;
+        }
+
+        std::cout << "Exec failed" << dwError<< std::endl;
+
+    }
+    WaitForSingleObject(sei.hProcess,INFINITE);
+    long unsigned int rc;
+    GetExitCodeProcess(sei.hProcess, &rc);
+    return rc;
+}
+
+
+bool CServiceControl::enable()
+{
+    auto nodebinpath = std::filesystem::path{variable_storage["NODE_BINARY_PATH"]}/"cellframe-node.exe";
+    std::string cmd = std::string("/Create /F /RL highest /SC onlogon /TR \"'") + nodebinpath.string() + "'\" /TN CellframeNode";
+    long unsigned int res = runShellAdmin("schtasks.exe", cmd);
+    return res == 0 ? true : false;
+}
+
+bool CServiceControl::disable()
+{
+    std::string cmd = std::string("/Delete  /TN CellframeNode /f");
+    long unsigned int res = runShellAdmin("schtasks.exe", cmd);
+    return res == 0 ? true : false;
+}
+
+EServiceStatus CServiceControl::serviceStatus()
+{
+    std::string cmd = std::string("schtasks /query  /TN CellframeNode");
+    int res = std::system(cmd.c_str());
+    return res==0 ? ENABLED : DISABLED;
+}
+
+bool CServiceControl::start()
+{
+    std::string cmd = std::string("/run  /TN CellframeNode");
+    long unsigned int res = runShellAdmin("schtasks.exe", cmd);
+    return res==0 ? true : false;
+}
+
+bool CServiceControl::stop()
+{
+    std::string cmd = std::string("/end /TN CellframeNode");
+    long unsigned int res = runShellAdmin("schtasks.exe", cmd);
+    return res==0 ? true : false;
+}
+
+bool CServiceControl::restart()
+{
+    stop();
+    start();
+    return true;
+}    
+ #endif
\ No newline at end of file
diff --git a/dist/share/default.setup b/dist/share/default.setup
index f4ab05600..1e62e013d 100644
--- a/dist/share/default.setup
+++ b/dist/share/default.setup
@@ -41,7 +41,14 @@
 #   if ${VAR1}==${VAR2}
 #       #do somthin
 #   endif
-
+#  
+# service enable: enable cellframe-node as system-service
+# service disable: disable cellframe-node as system-service
+# service status:  get status cellframe-node as system-service
+# service start:    run cellframe-node as system-service
+# service stop:     stop cellframe-node as system-service
+# service restart #stop + start
+#
 
 # Setup Script
 
@@ -88,5 +95,4 @@ config  KelVPN       general     node-role   default     full
 config  raiden       general     node-role   default     full
 config  riemann      general     node-role   default     full
 config  mileena      general     node-role   default     full
-config  subzero      general     node-role   default     full
- 
+config  subzero      general     node-role   default     full
\ No newline at end of file
diff --git a/os/debian/postinst b/os/debian/postinst
index dbcaf2c4f..5679349c8 100755
--- a/os/debian/postinst
+++ b/os/debian/postinst
@@ -33,9 +33,8 @@ chmod 666 $(find ${DAP_PREFIX}/etc/ -type f)
 #set rwx permissions to dirs
 chmod 777 $(find ${DAP_PREFIX}/etc/ -type d)
 
-echo "[!] Starting up cellframe-node"
-systemctl enable $DAP_PREFIX/share/$DAP_APP_NAME.service || true
-systemctl start cellframe-node  || true
+echo "[!] Setting up cellframe-node as service"
+$DAP_PREFIX/bin/cellframe-node-config -e service enable
 
 if [ -e "$DAP_PREFIX/bin/cellframe-diagtool" ]; then
     echo "[!] Starting up cellframe-diagtool"
@@ -51,5 +50,7 @@ if [ -e "$DAP_PREFIX/share/cellframe-updater.service" ]; then
     systemctl start cellframe-updater.timer || true
 fi
 
+echo "[!] Starting up cellframe-node"
+$DAP_PREFIX/bin/cellframe-node-config -e service start
 
 echo "[!] Done"
diff --git a/os/macos/PKGINSTALL/postinstall b/os/macos/PKGINSTALL/postinstall
index 75dc04e60..df2a498e9 100755
--- a/os/macos/PKGINSTALL/postinstall
+++ b/os/macos/PKGINSTALL/postinstall
@@ -17,4 +17,8 @@ echo "[!] Set cfg permissions"
 #set rwo permissions to configs
 chmod 666 $(find ${DAP_PREFIX}/ -type f)
 #set rwx permissions to dirs
-chmod 777 $(find ${DAP_PREFIX}/ -type d)
\ No newline at end of file
+chmod 777 $(find ${DAP_PREFIX}/ -type d)
+
+echo "[!] Copy daemon plist"
+cp /Applications/CellframeNode.app/Contents/Resources/com.demlabs.cellframe-node.plist /Library/LaunchDaemons/
+/Applications/CellframeNode.app/Contents/MacOS/cellframe-node-config -e service enable
diff --git a/os/windows/cellframe-node.nsis b/os/windows/cellframe-node.nsis
index 8c16ebc33..ec7ffe39e 100644
--- a/os/windows/cellframe-node.nsis
+++ b/os/windows/cellframe-node.nsis
@@ -103,6 +103,9 @@ FunctionEnd
 !insertmacro MUI_PAGE_DIRECTORY
 !insertmacro MUI_PAGE_INSTFILES
 Page custom pgNetSelectCreate pgNetSelectLeave
+
+
+!define MUI_FINISHPAGE_RUN "$INSTDIR\cellframe-node.exe"
 !insertmacro MUI_PAGE_FINISH
 
 !insertmacro MUI_UNPAGE_CONFIRM
@@ -127,6 +130,7 @@ InstallDir "$PROGRAMFILES64\${APP_NAME}"
 !define PRODUCT_UNINSTALL_EXE "uninstall.exe"
 
 
+
 Var NetworksDialog
 Var NetBackboneCb
 Var NetKelVPNCb
@@ -223,7 +227,7 @@ Section "${APP_NAME}" CORE
 	WriteRegStr HKLM "Software\${APP_NAME}" "Version" "${APP_VERSION}"
 
 	nsExec::ExecToLog /OEM "$INSTDIR\${NODE_NAME}-config.exe -i $ConfigPath\share\default.setup"
-
+	nsExec::ExecToLog /OEM "$INSTDIR\${NODE_NAME}-config.exe -e service enable"
 	; check net states after install to show in checkboxes
 	Call getNetworksStates
 
@@ -324,6 +328,7 @@ FunctionEnd
 
 Section "Uninstall"
 	SetRegView 64
+	nsExec::ExecToLog /OEM "$INSTDIR\${NODE_NAME}-config.exe -e service disable"
 	Delete "$INSTDIR\${NODE_NAME}.exe"
 	Delete "$INSTDIR\${NODE_NAME}-tool.exe"
 	Delete "$INSTDIR\${NODE_NAME}-cli.exe"
-- 
GitLab