mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-02-05 15:18:45 +00:00
23
sdv_executables/sdv_control/CMakeLists.txt
Normal file
23
sdv_executables/sdv_control/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
# Define project
|
||||
project (sdv_control VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# Add include directories
|
||||
include_directories(../export)
|
||||
|
||||
# Define the executable
|
||||
add_executable(sdv_control
|
||||
main.cpp
|
||||
"list_elements.cpp"
|
||||
"list_elements.h"
|
||||
"startup_shutdown.h"
|
||||
"startup_shutdown.cpp"
|
||||
"context.h"
|
||||
"print_table.h" "start_stop_service.cpp" "start_stop_service.h" "installation.h" "installation.cpp")
|
||||
|
||||
target_link_libraries(sdv_control ${CMAKE_DL_LIBS})
|
||||
|
||||
# Build dependencies
|
||||
add_dependencies(sdv_control core_services)
|
||||
|
||||
# Appending the executable to the service list
|
||||
set(SDV_Executable_List ${SDV_Executable_List} sdv_control PARENT_SCOPE)
|
||||
52
sdv_executables/sdv_control/context.h
Normal file
52
sdv_executables/sdv_control/context.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef CONTEXT_H
|
||||
#define CONTEXT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <support/string.h>
|
||||
#include <support/sequence.h>
|
||||
|
||||
/**
|
||||
* @brief SDV context
|
||||
*/
|
||||
struct SContext
|
||||
{
|
||||
bool bSilent = false; ///< Silence flag
|
||||
bool bVerbose = false; ///< Verbose flag
|
||||
bool bServerSilent = false; ///< Silence flag of server
|
||||
bool bServerVerbose = false; ///< Verbose flag of server
|
||||
uint32_t uiInstanceID = 1000; ///< Instance ID
|
||||
bool bListNoHdr = false; ///< Do not print a header with the listing table.
|
||||
bool bListShort = false; ///< Print only a shortened list with one column.
|
||||
sdv::sequence<sdv::u8string> seqCmdLine; ///< The commands provided on the command line.
|
||||
std::filesystem::path pathInstallDir; ///< Optional installation directory.
|
||||
};
|
||||
|
||||
#include <cctype> // std::tolower
|
||||
#include <algorithm> // std::equal
|
||||
|
||||
/**
|
||||
* @brief Compare whether two characters are identical when both are converted to lower case.
|
||||
* @remarks Cannot deal with Unicode letters comprising of more than one characters.
|
||||
* @param[in] cLeft First character
|
||||
* @param[in] cRight Second character
|
||||
* @return The case independent equality of the characters.
|
||||
*/
|
||||
inline bool ichar_equals(char cLeft, char cRight)
|
||||
{
|
||||
return std::tolower(static_cast<unsigned char>(cLeft)) ==
|
||||
std::tolower(static_cast<unsigned char>(cRight));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare for case-independent equality.
|
||||
* @param[in] rssLeft Reference to the left string.
|
||||
* @param[in] rssRight Reference to the right string.
|
||||
* @return The case-independent equality of the strings.
|
||||
*/
|
||||
inline bool iequals(const std::string& rssLeft, const std::string& rssRight)
|
||||
{
|
||||
return std::equal(rssLeft.begin(), rssLeft.end(), rssRight.begin(), rssRight.end(), ichar_equals);
|
||||
}
|
||||
|
||||
#endif // !defined CONTEXT_H
|
||||
124
sdv_executables/sdv_control/installation.cpp
Normal file
124
sdv_executables/sdv_control/installation.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "installation.h"
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include <interfaces/process.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
void InstallationHelp(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "INSTALL", "UPDATE" or "UNINSTALL".
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing install/update/uninstall command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "INSTALL"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control INSTALL <name> [files...] [options...]\n\n"
|
||||
"Make a new installation with a set of files. This command succeeds when the files contain at least one component "
|
||||
"module and another installation with the same name is not existing. Complex services are automatically added to the "
|
||||
"configuration.\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "UPDATE"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control UPDATE <name> [files...] [options...]\n\n"
|
||||
"Update an existing installation. This will not remove any configuration (unless a component is not available any "
|
||||
"more after, or a new component was added by the update.\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "UNINSTALL"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control UNINSTALL <name> [files...] [options...]\n\n"
|
||||
"Remove an existing installation. This will remove the configuration for the components as well. Dependent components "
|
||||
"become inactive and will be activated again when the component is installed again.\n\n");
|
||||
return;
|
||||
}
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid install/update/uninstall command..." << std::endl;
|
||||
}
|
||||
|
||||
int Install(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "INSTALL"
|
||||
if (rsContext.seqCmdLine.size() < 3)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Not enough parameters for installation command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "INSTALL"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command : " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Followed by the installation name
|
||||
//std::string ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
// Determine the service to start
|
||||
sdv::u8string ssClass, ssName;
|
||||
if (rsContext.seqCmdLine.size() == 3)
|
||||
{
|
||||
ssClass = rsContext.seqCmdLine[1];
|
||||
ssName = rsContext.seqCmdLine[2];
|
||||
} else
|
||||
ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPO_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object
|
||||
sdv::core::TObjectID tObjectID = pRepoControl->CreateObject(ssClass, ssName, {});
|
||||
if (!tObjectID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << START_OBJECT_ERROR_ERROR_MSG << " Object name: " << ssName << std::endl;
|
||||
return START_OBJECT_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
// All good...
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int Update(const SContext& /*rsContext*/)
|
||||
{
|
||||
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
|
||||
return NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int Uninstall(const SContext& /*rsContext*/)
|
||||
{
|
||||
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
|
||||
return NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
39
sdv_executables/sdv_control/installation.h
Normal file
39
sdv_executables/sdv_control/installation.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef INSTALLATION_H
|
||||
#define INSTALLATION_H
|
||||
|
||||
#include "context.h"
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
/**
|
||||
* @brief Help for installing, updating and uninstalling components.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void InstallationHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Install components.
|
||||
* @details The command line context.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int Install(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Update installation.
|
||||
* @details The command line context.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int Update(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Uninstall components.
|
||||
* @details The command line context.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int Uninstall(const SContext& rsContext);
|
||||
|
||||
#endif // !defined INSTALLATION_H
|
||||
416
sdv_executables/sdv_control/list_elements.cpp
Normal file
416
sdv_executables/sdv_control/list_elements.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
#include "list_elements.h"
|
||||
#include "print_table.h"
|
||||
#include <interfaces/config.h>
|
||||
#include <support/sdv_core.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include "../../global/exec_dir_helper.h"
|
||||
#include "../../global/flags.h"
|
||||
#include "../error_msg.h"
|
||||
|
||||
void ListHelp(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "LIST"
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing listing command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "LIST"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid command: " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Which list command help is requested
|
||||
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
|
||||
if (rsContext.seqCmdLine.size() >= 2)
|
||||
{
|
||||
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
|
||||
}
|
||||
|
||||
// Print help if requested
|
||||
if (!rsContext.bSilent)
|
||||
{
|
||||
switch (eListCommand)
|
||||
{
|
||||
case EListCommand::modules:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST MODULES [options...]\n\nShow a list of all loaded modules.\n");
|
||||
break;
|
||||
case EListCommand::classes:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CLASSES [options...]\n\nShow a list of available component classes.\n");
|
||||
break;
|
||||
case EListCommand::components:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST COMPONENTS [options...]\n\nShow a list of all loaded components.\n");
|
||||
break;
|
||||
case EListCommand::installations:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST INSTALLATIONS [options...]\n\nShow a list of all installations.\n");
|
||||
break;
|
||||
case EListCommand::connections:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CONNECTIONS [options...]\n\nShow a list of all connected applications.\n");
|
||||
break;
|
||||
default:
|
||||
CCommandLine::PrintHelpText(std::cout, R"code(Usage: sdv_control LIST <list_command> [options...]
|
||||
|
||||
Supported listing commands:
|
||||
LIST MODULES Show a list of loaded server modules.
|
||||
LIST CLASSES Show a list of available component classes.
|
||||
LIST COMPONENTS Show a list of instantiated server components
|
||||
LIST INSTALLATIONS Show a list of installations.
|
||||
LIST CONNECTIONS Show a list of current connections.
|
||||
|
||||
)code");
|
||||
break;
|
||||
}
|
||||
std::cout << "Options:\n";
|
||||
std::cout << " --no_header Do not print a header for the listing table.\n";
|
||||
std::cout << " --short Print only the most essential information as one column.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
int ListElements(const SContext& rsContext, std::ostream& rstream /*= std::cout*/)
|
||||
{
|
||||
// First argument should be "LIST"
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "LIST"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Which list command help is requested
|
||||
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
|
||||
if (rsContext.seqCmdLine.size() >= 2)
|
||||
{
|
||||
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
{
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command.." << std::endl << std::endl;
|
||||
ListHelp(rsContext);
|
||||
}
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << "." << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
int iRet = -100;
|
||||
switch (eListCommand)
|
||||
{
|
||||
case EListCommand::modules:
|
||||
iRet = ListModules(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::classes:
|
||||
iRet = ListClasses(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::components:
|
||||
iRet = ListComponents(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::installations:
|
||||
iRet = ListInstallations(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::connections:
|
||||
iRet = ListConnections(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
|
||||
int ListModules(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IModuleInfo* pModuleInfo = nullptr;
|
||||
if (pObjectAccess)
|
||||
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).
|
||||
GetInterface<sdv::core::IModuleInfo>();
|
||||
if (!pModuleInfo)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << MODULE_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return MODULE_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Relative path from exe
|
||||
auto fnPrintRelPath = [](const sdv::u8string& rssPath)
|
||||
{
|
||||
std::filesystem::path path = rssPath.c_str();
|
||||
if (path.is_relative()) return path.generic_u8string();
|
||||
return path.lexically_relative(GetExecDirectory()).generic_u8string();
|
||||
};
|
||||
|
||||
// Create the module list
|
||||
sdv::sequence<sdv::core::SModuleInfo> seqModules = pModuleInfo->GetModuleList();
|
||||
if (rsContext.bListShort)
|
||||
{
|
||||
std::vector<std::array<std::string, 1>> vecShortModuleList;
|
||||
vecShortModuleList.push_back({ "Path" });
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
vecShortModuleList.push_back({ fnPrintRelPath(rsModuleInfo.ssPath) });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecShortModuleList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::array<std::string, 5>> vecModuleList;
|
||||
vecModuleList.push_back({ "Module ID", "Filename", "Version", "Active", "Path" });
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
vecModuleList.push_back({
|
||||
std::to_string(static_cast<int64_t>(rsModuleInfo.tModuleID)),
|
||||
rsModuleInfo.ssFilename,
|
||||
std::to_string(rsModuleInfo.uiVersion / 100) + "." + std::to_string(rsModuleInfo.uiVersion % 100),
|
||||
(rsModuleInfo.bActive ? " +" : " -"),
|
||||
fnPrintRelPath(rsModuleInfo.ssPath) });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecModuleList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListClasses(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IModuleInfo* pModuleInfo = nullptr;
|
||||
if (pObjectAccess)
|
||||
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).
|
||||
GetInterface<sdv::core::IModuleInfo>();
|
||||
if (!pModuleInfo)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << MODULE_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return MODULE_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Class type
|
||||
auto fnPrintClassType = [](sdv::EObjectType eType)
|
||||
{
|
||||
switch (eType)
|
||||
{
|
||||
case sdv::EObjectType::SystemObject: return "SystemObject";
|
||||
case sdv::EObjectType::Device: return "Device";
|
||||
case sdv::EObjectType::BasicService: return "BasicService";
|
||||
case sdv::EObjectType::ComplexService: return "ComplexService";
|
||||
case sdv::EObjectType::Application: return "Application";
|
||||
case sdv::EObjectType::Proxy: return "Proxy";
|
||||
case sdv::EObjectType::Stub: return "Stub";
|
||||
case sdv::EObjectType::Utility: return "Utility";
|
||||
default: return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
// Class flags
|
||||
auto fnPrintClassFlags = [](uint32_t uiFlags)
|
||||
{
|
||||
hlpr::flags<sdv::EObjectFlags> flags(uiFlags);
|
||||
std::stringstream sstream;
|
||||
if (flags.check(sdv::EObjectFlags::singleton))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Singleton";
|
||||
}
|
||||
return std::string("{") + sstream.str() + std::string("}");
|
||||
};
|
||||
|
||||
// Dependencies
|
||||
auto fnPrintList = [](const sdv::sequence<sdv::u8string>& rseqList)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
for (const sdv::u8string& rss : rseqList)
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << rss;
|
||||
}
|
||||
return std::string("{") + sstream.str() + std::string("}");
|
||||
};
|
||||
|
||||
// Create the module list
|
||||
if (rsContext.bListShort)
|
||||
{
|
||||
std::vector<std::array<std::string, 2>> vecShortClassList;
|
||||
vecShortClassList.push_back({ "Class name", "Aliases"});
|
||||
sdv::sequence<sdv::core::SModuleInfo> seqModules = pModuleInfo->GetModuleList();
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
{
|
||||
sdv::sequence<sdv::SClassInfo> seqClasses = pModuleInfo->GetClassList(rsModuleInfo.tModuleID);
|
||||
for (const sdv::SClassInfo& rsClassInfo : seqClasses)
|
||||
vecShortClassList.push_back({ rsClassInfo.ssClassName, fnPrintList(rsClassInfo.seqClassAliases) });
|
||||
}
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecShortClassList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::array<std::string, 7>> vecClassList;
|
||||
vecClassList.push_back({ "Class name", "Aliases", "Default name", "Type", "Flags", "Module ID", "Dependencies" });
|
||||
sdv::sequence<sdv::core::SModuleInfo> seqModules = pModuleInfo->GetModuleList();
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
{
|
||||
sdv::sequence<sdv::SClassInfo> seqClasses = pModuleInfo->GetClassList(rsModuleInfo.tModuleID);
|
||||
for (const sdv::SClassInfo& rsClassInfo : seqClasses)
|
||||
vecClassList.push_back({
|
||||
rsClassInfo.ssClassName,
|
||||
fnPrintList(rsClassInfo.seqClassAliases),
|
||||
rsClassInfo.ssDefaultObjectName,
|
||||
fnPrintClassType(rsClassInfo.eType),
|
||||
fnPrintClassFlags(rsClassInfo.uiFlags),
|
||||
std::to_string(static_cast<int64_t>(rsModuleInfo.tModuleID)),
|
||||
fnPrintList(rsClassInfo.seqDependencies) });
|
||||
}
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecClassList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListComponents(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IRepositoryInfo* pRepoInfo = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (!pRepoInfo)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPOSITORY_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Class type
|
||||
auto fnPrintClassType = [](sdv::EObjectType eType)
|
||||
{
|
||||
switch (eType)
|
||||
{
|
||||
case sdv::EObjectType::SystemObject: return "SystemObject";
|
||||
case sdv::EObjectType::Device: return "Device";
|
||||
case sdv::EObjectType::BasicService: return "BasicService";
|
||||
case sdv::EObjectType::ComplexService: return "ComplexService";
|
||||
case sdv::EObjectType::Application: return "Application";
|
||||
case sdv::EObjectType::Proxy: return "Proxy";
|
||||
case sdv::EObjectType::Stub: return "Stub";
|
||||
case sdv::EObjectType::Utility: return "Utility";
|
||||
default: return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
// Object flags
|
||||
auto fnPrintObjectFlags = [](uint32_t uiFlags)
|
||||
{
|
||||
hlpr::flags<sdv::core::EObjectInfoFlags> flags(uiFlags);
|
||||
std::stringstream sstream;
|
||||
if (flags.check(sdv::core::EObjectInfoFlags::object_controlled))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Controlled";
|
||||
}
|
||||
if (flags.check(sdv::core::EObjectInfoFlags::object_foreign))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Foreign";
|
||||
}
|
||||
if (flags.check(sdv::core::EObjectInfoFlags::object_isolated))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Isolated";
|
||||
}
|
||||
return std::string("{") + sstream.str() + std::string("}");
|
||||
};
|
||||
|
||||
// Create the object list
|
||||
if (rsContext.bListShort)
|
||||
{
|
||||
std::vector<std::array<std::string, 6>> vecShortObjectList;
|
||||
vecShortObjectList.push_back({ "Object name" });
|
||||
sdv::sequence<sdv::core::SObjectInfo> seqObjects = pRepoInfo->GetObjectList();
|
||||
for (const sdv::core::SObjectInfo& rsObjectInfo : seqObjects)
|
||||
vecShortObjectList.push_back({ rsObjectInfo.ssObjectName });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecShortObjectList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::array<std::string, 6>> vecObjectList;
|
||||
vecObjectList.push_back({ "Object ID", "Class name", "Object name", "Type", "Flags", "Module ID" });
|
||||
sdv::sequence<sdv::core::SObjectInfo> seqObjects = pRepoInfo->GetObjectList();
|
||||
for (const sdv::core::SObjectInfo& rsObjectInfo : seqObjects)
|
||||
vecObjectList.push_back({
|
||||
std::to_string(static_cast<int64_t>(rsObjectInfo.tModuleID)),
|
||||
rsObjectInfo.sClassInfo.ssClassName,
|
||||
rsObjectInfo.ssObjectName,
|
||||
fnPrintClassType(rsObjectInfo.sClassInfo.eType),
|
||||
fnPrintObjectFlags(rsObjectInfo.uiFlags),
|
||||
std::to_string(static_cast<int64_t>(rsObjectInfo.tModuleID)) });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecObjectList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::installation::IAppInstall* pAppInstall = nullptr;
|
||||
if (pObjectAccess)
|
||||
pAppInstall = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ConfigService")).
|
||||
GetInterface<sdv::installation::IAppInstall>();
|
||||
if (!pAppInstall)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONFIG_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return CONFIG_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object list
|
||||
std::vector<std::array<std::string, 1>> vecInstallList;
|
||||
vecInstallList.push_back({"Installation"});
|
||||
sdv::sequence<sdv::u8string> seqInstallations = pAppInstall->GetInstallations();
|
||||
for (const sdv::u8string& rssInstallation : seqInstallations)
|
||||
vecInstallList.push_back({
|
||||
rssInstallation});
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecInstallList, rstream, rsContext.bListNoHdr);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListConnections(const SContext& /*rsContext*/, const sdv::TObjectPtr& /*rptrRepository*/, std::ostream& /*rstream = std::cout */ )
|
||||
{
|
||||
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
|
||||
return NOT_IMPLEMENTED;
|
||||
}
|
||||
69
sdv_executables/sdv_control/list_elements.h
Normal file
69
sdv_executables/sdv_control/list_elements.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef LIST_ELEMENTS_H
|
||||
#define LIST_ELEMENTS_H
|
||||
|
||||
#include "context.h"
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
/**
|
||||
* @brief Help for listing elements.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void ListHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief List elements in a table. Base function. The elements to list are to be parsed from the arguments. The context could
|
||||
* indicate additional flags.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListElements(const SContext& rsContext, std::ostream& rstream = std::cout);
|
||||
|
||||
/**
|
||||
* @brief List the loaded server modules.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListModules(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the available component classes.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListClasses(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the instantiated server components.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListComponents(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the installations.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the current connections.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListConnections(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
#endif // !defined LIST_ELEMENTS_H
|
||||
223
sdv_executables/sdv_control/main.cpp
Normal file
223
sdv_executables/sdv_control/main.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "../../global/process_watchdog.h"
|
||||
#include <support/sdv_core.h>
|
||||
#include "../../global/cmdlnparser/cmdlnparser.cpp"
|
||||
#include "../../global/exec_dir_helper.h"
|
||||
#include <support/mem_access.h>
|
||||
#include <support/sdv_core.h>
|
||||
#include <support/app_control.h>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include "context.h"
|
||||
#include "startup_shutdown.h"
|
||||
#include "list_elements.h"
|
||||
#include "start_stop_service.h"
|
||||
#include "installation.h"
|
||||
#include "../error_msg.h"
|
||||
|
||||
/**
|
||||
* @brief Add a slag to the string.
|
||||
* @param[in] rssString The string to add a flag to.
|
||||
* @param[in] rssFlag The flag text to add.
|
||||
*/
|
||||
void AddFlagString(std::string& rssString, const std::string& rssFlag)
|
||||
{
|
||||
if (!rssString.empty()) rssString += " | ";
|
||||
rssString += rssFlag;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain(int iArgc, const wchar_t* rgszArgv[])
|
||||
#else
|
||||
extern "C" int main(int iArgc, const char* rgszArgv[])
|
||||
#endif
|
||||
{
|
||||
// Workaround for GCC to make certain that POSIX thread library is loaded before the components are loaded.
|
||||
// REASON: If the first call to a thread is done in a dynamic library, the application is already classified as single
|
||||
// threaded and a termination is initiated.
|
||||
// See: https://stackoverflow.com/questions/51209268/using-stdthread-in-a-library-loaded-with-dlopen-leads-to-a-sigsev
|
||||
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
|
||||
CProcessWatchdog watchdog;
|
||||
|
||||
// If not set, set the runtime location to the EXE directory.
|
||||
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
|
||||
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
|
||||
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
|
||||
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
|
||||
|
||||
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
|
||||
SContext sContext;
|
||||
bool bError = false;
|
||||
bool bHelp = false;
|
||||
bool bVersion = false;
|
||||
std::string ssArgError;
|
||||
try
|
||||
{
|
||||
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help. Use <COMMAND> --help for specific help on the command.");
|
||||
rArgHelpDef.AddSubOptionName("help");
|
||||
auto& rArgSilentDef = cmdln.DefineOption("s", sContext.bSilent, "Do not show any information on std::cout. Not compatible with 'verbose'.");
|
||||
rArgSilentDef.AddSubOptionName("silent");
|
||||
auto& rArgVerboseDef = cmdln.DefineOption("v", sContext.bVerbose, "Provide verbose information. Not compatible with 'silent'.");
|
||||
rArgVerboseDef.AddSubOptionName("verbose");
|
||||
cmdln.DefineSubOption("version", bVersion, "Show version information.");
|
||||
cmdln.DefineSubOption("instance", sContext.uiInstanceID, "The instance ID of the SDV instance (default ID is 1000).");
|
||||
cmdln.DefineSubOption("server_silent", sContext.bServerSilent, "Only used with STARTUP command: Server is started using "
|
||||
"silent option. Not compatible with 'server_verbose'.");
|
||||
cmdln.DefineSubOption("server_verbose", sContext.bServerVerbose, "Only used with STARTUP command: Server is started using "
|
||||
"verbose option. Not compatible with 'server_silent'.");
|
||||
cmdln.DefineSubOption("install_dir", sContext.pathInstallDir, "Only used with STARTUP command: Installation directory "
|
||||
"(absolute or relative to the sdv_core executable).");
|
||||
cmdln.DefineSubOption("no_header", sContext.bListNoHdr, "Only used with LIST command: Do not print a header for the "
|
||||
"listing table.");
|
||||
cmdln.DefineSubOption("short", sContext.bListShort, "Only used with LIST command: Print only the most essential "
|
||||
"information as one column.");
|
||||
cmdln.DefineDefaultArgument(sContext.seqCmdLine, "COMMAND");
|
||||
|
||||
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
|
||||
} catch (const SArgumentParseException& rsExcept)
|
||||
{
|
||||
ssArgError = rsExcept.what();
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
if (!sContext.bSilent)
|
||||
{
|
||||
std::cout << "SDV Server Control Utility" << std::endl;
|
||||
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
|
||||
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
if (!ssArgError.empty() && !sContext.bSilent)
|
||||
std::cerr << "ERROR: " << ssArgError << std::endl;
|
||||
|
||||
if (!bHelp && !bVersion && sContext.seqCmdLine.empty())
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
std::cerr << "ERROR: Missing command!" << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
enum class ECommand { unknown, startup, shutdown, list, install, update, uninstall, start, stop } eCommand = ECommand::unknown;
|
||||
if (!sContext.seqCmdLine.empty())
|
||||
{
|
||||
if (iequals(sContext.seqCmdLine[0], "STARTUP")) eCommand = ECommand::startup;
|
||||
else if (iequals(sContext.seqCmdLine[0], "SHUTDOWN")) eCommand = ECommand::shutdown;
|
||||
else if (iequals(sContext.seqCmdLine[0], "LIST")) eCommand = ECommand::list;
|
||||
else if (iequals(sContext.seqCmdLine[0], "INSTALL")) eCommand = ECommand::install;
|
||||
else if (iequals(sContext.seqCmdLine[0], "UPDATE")) eCommand = ECommand::update;
|
||||
else if (iequals(sContext.seqCmdLine[0], "UNINSTALL")) eCommand = ECommand::uninstall;
|
||||
else if (iequals(sContext.seqCmdLine[0], "START")) eCommand = ECommand::start;
|
||||
else if (iequals(sContext.seqCmdLine[0], "STOP")) eCommand = ECommand::stop;
|
||||
else
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
std::cerr << "ERROR: Invalid command: " << sContext.seqCmdLine[0] << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bHelp)
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
{
|
||||
if (bError)
|
||||
std::cout << std::endl;
|
||||
switch (eCommand)
|
||||
{
|
||||
case ECommand::startup:
|
||||
case ECommand::shutdown:
|
||||
StartupShutdownHelp(sContext);
|
||||
break;
|
||||
case ECommand::start:
|
||||
case ECommand::stop:
|
||||
StartStopServiceHelp(sContext);
|
||||
break;
|
||||
case ECommand::list:
|
||||
ListHelp(sContext);
|
||||
break;
|
||||
case ECommand::install:
|
||||
case ECommand::update:
|
||||
case ECommand::uninstall:
|
||||
InstallationHelp(sContext);
|
||||
break;
|
||||
default:
|
||||
cmdln.PrintHelp(std::cout, R"code(Supported commands:
|
||||
STARTUP Start the core application server
|
||||
SHUTDOWN Stop the core application server
|
||||
LIST List module/classes/component/installation/connection information.
|
||||
INSTALL Install a new application or service.
|
||||
UPDATE Update an existing installation.
|
||||
UNINSTALL Uninstall an installed application or service.
|
||||
START Start a service (complex services only).
|
||||
STOP Stop a service (complex services only).
|
||||
)code");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bError ? CMDLN_ARG_ERR : NO_ERROR;
|
||||
}
|
||||
if (bError) return CMDLN_ARG_ERR;
|
||||
|
||||
if (bVersion)
|
||||
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build " <<
|
||||
SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
|
||||
|
||||
if (sContext.seqCmdLine.empty()) return NO_ERROR; // Done.
|
||||
|
||||
// Start the application control
|
||||
if (sContext.bVerbose)
|
||||
std::cout << "Starting local application control.." << std::endl;
|
||||
sdv::app::CAppControl appcontrol;
|
||||
std::string ssAppConfig = std::string(R"code(
|
||||
[Application]
|
||||
Mode = "Maintenance"
|
||||
Instance = )code") + std::to_string(sContext.uiInstanceID) + R"code(
|
||||
)code";
|
||||
if (!appcontrol.Startup(ssAppConfig))
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
std::cerr << "ERROR: " << APP_CONTROL_STARTUP_ERROR_MSG << std::endl;
|
||||
return APP_CONTROL_STARTUP_ERROR;
|
||||
}
|
||||
|
||||
int iRet = 0;
|
||||
switch (eCommand)
|
||||
{
|
||||
case ECommand::startup:
|
||||
iRet = StartupSDVServer(sContext);
|
||||
break;
|
||||
case ECommand::shutdown:
|
||||
iRet = ShutdownSDVServer(sContext);
|
||||
break;
|
||||
case ECommand::list:
|
||||
iRet = ListElements(sContext);
|
||||
break;
|
||||
case ECommand::start:
|
||||
iRet = StartService(sContext);
|
||||
break;
|
||||
case ECommand::stop:
|
||||
iRet = StopService(sContext);
|
||||
break;
|
||||
case ECommand::install:
|
||||
iRet = Install(sContext);
|
||||
break;
|
||||
case ECommand::update:
|
||||
iRet = Update(sContext);
|
||||
break;
|
||||
case ECommand::uninstall:
|
||||
iRet = Uninstall(sContext);
|
||||
break;
|
||||
default:
|
||||
std::cout << "Command missing :-(" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sContext.bVerbose) std::cout << "Shutting down local application control.." << std::endl;
|
||||
appcontrol.Shutdown();
|
||||
|
||||
return iRet;
|
||||
}
|
||||
83
sdv_executables/sdv_control/print_table.h
Normal file
83
sdv_executables/sdv_control/print_table.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef TABLE_H
|
||||
#define TABLE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* @brief Print a table of a vector of rows.
|
||||
* @tparam nSize The array size.
|
||||
* @details the first line is the header.
|
||||
* @param[in] rvecRows Reference to the vector of rows.
|
||||
* @param[in] rstream The output stream to use for printing.
|
||||
* @param[in] bNoHeader When set, skip the first row (the header row).
|
||||
*/
|
||||
template <size_t nSize>
|
||||
void PrintTable(const std::vector<std::array<std::string, nSize>>& rvecRows, std::ostream& rstream, bool bNoHeader = false)
|
||||
{
|
||||
// Calculate the maximum length of the column by going through each cell.
|
||||
bool bSkipFirst = bNoHeader;
|
||||
size_t rgnLength[nSize] = {};
|
||||
for (const auto& rrgssRow : rvecRows)
|
||||
{
|
||||
if (bSkipFirst)
|
||||
{
|
||||
bSkipFirst = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
|
||||
{
|
||||
if (rrgssRow[nIndex].size() > rgnLength[nIndex])
|
||||
rgnLength[nIndex] = rrgssRow[nIndex].size();
|
||||
}
|
||||
}
|
||||
|
||||
// Print a cell
|
||||
auto fnPrintCell = [&](size_t nIndex, const std::string& rssText)
|
||||
{
|
||||
// Print the text
|
||||
rstream << rssText;
|
||||
|
||||
// Check index
|
||||
if (nIndex == nSize - 1) // Last column; nl needed
|
||||
rstream << std::endl;
|
||||
else // Separator needed
|
||||
rstream << std::string(rgnLength[nIndex] - rssText.size() + 2, ' ');
|
||||
};
|
||||
|
||||
// Print each line
|
||||
bSkipFirst = bNoHeader;
|
||||
bool bInitialLine = !bNoHeader;
|
||||
for (const auto& rrgssRow : rvecRows)
|
||||
{
|
||||
if (bSkipFirst)
|
||||
{
|
||||
bSkipFirst = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start with a space if a header is present
|
||||
if (!bNoHeader)
|
||||
rstream << " ";
|
||||
|
||||
// Print the text
|
||||
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
|
||||
fnPrintCell(nIndex, rrgssRow[nIndex]);
|
||||
|
||||
// Need a vertical separator?
|
||||
if (bInitialLine)
|
||||
{
|
||||
size_t nSeparatorLength = 1;
|
||||
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
|
||||
nSeparatorLength += rgnLength[nIndex] + 2;
|
||||
nSeparatorLength--;
|
||||
rstream << std::string(nSeparatorLength, '-') << std::endl;
|
||||
bInitialLine = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined TABLE_H
|
||||
176
sdv_executables/sdv_control/start_stop_service.cpp
Normal file
176
sdv_executables/sdv_control/start_stop_service.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "start_stop_service.h"
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include <interfaces/process.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
void StartStopServiceHelp(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "START" or "STOP".
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing start/stop command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "START"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control START <name> [options...]\n"
|
||||
" sdv_control START <class> <name> [options...]\n\n"
|
||||
"Start a complex service with the supplied object name as is defined in the configuration (first usage) or the "
|
||||
"supplied class name and with object name assignment and add to the configuration (second usage).\n"
|
||||
"Only complex services can be started. If the service depends on not running other services, these are started as "
|
||||
"well.\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "STOP"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control STOP <name> [options...]\n"
|
||||
" sdv_control STOP <ID> [options...]\n"
|
||||
" sdv_control STOP <class> [options...]\n"
|
||||
" sdv_control STOP <module> [options...]\n\n"
|
||||
"Stop the complex service(s) with the supplied object name (first usage), with supplied object ID (second usage), with "
|
||||
"supplied class name (third usage) or contained in the module with the supplied module name (fourth usage).\n"
|
||||
"Only complex services can be stopped. Dependent services are stopped as well. If one of object to be stopped is not a "
|
||||
"complex service, the command fails.\n\n");
|
||||
return;
|
||||
}
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid start/stop command..." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
int StartService(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "START"
|
||||
if (rsContext.seqCmdLine.size() < 2)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Not enough parameters for START command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (rsContext.seqCmdLine.size() > 3)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Too many parameters for START command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "START"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Determine the service to start
|
||||
sdv::u8string ssClass, ssName;
|
||||
if (rsContext.seqCmdLine.size() == 3)
|
||||
{
|
||||
ssClass = rsContext.seqCmdLine[1];
|
||||
ssName = rsContext.seqCmdLine[2];
|
||||
} else
|
||||
ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPOSITORY_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object
|
||||
sdv::core::TObjectID tObjectID = pRepoControl->CreateObject(ssClass, ssName, {});
|
||||
if (!tObjectID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << START_OBJECT_ERROR_MSG << " Object name: " << ssName << std::endl;
|
||||
return START_OBJECT_ERROR;
|
||||
}
|
||||
|
||||
// All good...
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int StopService(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "STOP"
|
||||
if (rsContext.seqCmdLine.size() < 2)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Not enough parameters for STOP command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (rsContext.seqCmdLine.size() > 3)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Too many parameters for STOP command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "STOP"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command : " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Determine the service to start
|
||||
sdv::u8string ssClass, ssName;
|
||||
if (rsContext.seqCmdLine.size() == 3)
|
||||
{
|
||||
ssClass = rsContext.seqCmdLine[1];
|
||||
ssName = rsContext.seqCmdLine[2];
|
||||
} else
|
||||
ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPOSITORY_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object
|
||||
sdv::core::TObjectID tObjectID = pRepoControl->DestroyObject(ssName);
|
||||
if (!tObjectID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << STOP_OBJECT_ERROR_MSG << " Object name: " << ssName << std::endl;
|
||||
return STOP_OBJECT_ERROR;
|
||||
}
|
||||
|
||||
// All good...
|
||||
return NO_ERROR;
|
||||
}
|
||||
30
sdv_executables/sdv_control/start_stop_service.h
Normal file
30
sdv_executables/sdv_control/start_stop_service.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef START_STOP_SERVICE_H
|
||||
#define START_STOP_SERVICE_H
|
||||
|
||||
#include "context.h"
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
/**
|
||||
* @brief Help for start or stop a complex service.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void StartStopServiceHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Start the service.
|
||||
* @details The command line context includes the service to start or stop.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int StartService(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Stop the complex service.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int StopService(const SContext& rsContext);
|
||||
|
||||
#endif // !defined START_STOP_SERVICE_H
|
||||
206
sdv_executables/sdv_control/startup_shutdown.cpp
Normal file
206
sdv_executables/sdv_control/startup_shutdown.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "startup_shutdown.h"
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include <interfaces/process.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
sdv::process::TProcessID g_tServerProcessID = 0;
|
||||
|
||||
/**
|
||||
* @brief Process lifetime monitor struct
|
||||
*/
|
||||
struct SProcessLifetimeCallback : sdv::IInterfaceAccess, sdv::process::IProcessLifetimeCallback
|
||||
{
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::process::IProcessLifetimeCallback)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Called when the process was terminated.
|
||||
* @remarks The process return value is not always valid. The validity depends on the support of the underlying system.
|
||||
* @param[in] tProcessID The process ID of the process being terminated.
|
||||
* @param[in] iRetValueParam Process return value or 0 when not supported.
|
||||
*/
|
||||
virtual void ProcessTerminated([[maybe_unused]] /*in*/ sdv::process::TProcessID tProcessID, /*in*/ int64_t iRetValueParam) override
|
||||
{
|
||||
iRetValue = iRetValueParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the process return value or 0 when no value was set.
|
||||
* @return The process return value.
|
||||
*/
|
||||
int64_t GetRetValue() const
|
||||
{
|
||||
return iRetValue;
|
||||
}
|
||||
|
||||
int64_t iRetValue = 0; ///< Process return value to be updated by the process monitor.
|
||||
};
|
||||
|
||||
void StartupShutdownHelp(const SContext& rsContext)
|
||||
{
|
||||
// First and only argument should be "STARTUP" or "SHUTDOWN".
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing startup/shutdown command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (rsContext.seqCmdLine.size() > 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: too many commands following startup/shutdown command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "STARTUP"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control STARTUP [options...]\n\n"
|
||||
"Start the SDV server with the supplied instance ID. If no instance ID is supplied, use the default instance "
|
||||
"ID #1000.\n\n"
|
||||
"Options:\n"
|
||||
" --server_silent Server is started using silent option. Not compatible with 'server_verbose'.\n"
|
||||
" --server_verbose Server is started using verbose option. Not compatible with 'server_silent'.\n"
|
||||
" --install_dir Installation directory (absolute or relative to the sdv_core executable).\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "SHUTDOWN"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control SHUTDOWN [options...]\n\nStop the SDV server with the supplied "
|
||||
"instance ID. If no instance ID is supplied, use the default instance ID #1000.\n\n");
|
||||
return;
|
||||
}
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid startup/shutdown command..." << std::endl;
|
||||
}
|
||||
|
||||
int StartupSDVServer(const SContext& rsContext)
|
||||
{
|
||||
if (rsContext.seqCmdLine.size() != 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid arguments following STARTUP command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Starting the SDV Server..." << std::endl;
|
||||
|
||||
// Get the process control service
|
||||
sdv::process::IProcessControl* pProcessControl = sdv::core::GetObject<sdv::process::IProcessControl>("ProcessControlService");
|
||||
sdv::process::IProcessLifetime* pProcessLifetime = sdv::core::GetObject<sdv::process::IProcessLifetime>("ProcessControlService");
|
||||
if (!pProcessControl || !pProcessLifetime)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << PROCESS_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return PROCESS_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
sdv::sequence<sdv::u8string> seqArgTemp;
|
||||
if (rsContext.bVerbose)
|
||||
std::cout << "Instance ID: " << rsContext.uiInstanceID << std::endl;
|
||||
seqArgTemp.push_back("-server");
|
||||
seqArgTemp.push_back("--instance" + std::to_string(rsContext.uiInstanceID));
|
||||
seqArgTemp.push_back("--no_banner");
|
||||
if (rsContext.bServerSilent) seqArgTemp.push_back("--silent");
|
||||
if (rsContext.bServerVerbose) seqArgTemp.push_back("--verbose");
|
||||
if (!rsContext.pathInstallDir.empty())
|
||||
seqArgTemp.push_back("--install_dir\"" + rsContext.pathInstallDir.generic_u8string() + "\"");
|
||||
g_tServerProcessID = pProcessControl->Execute("sdv_core", seqArgTemp, sdv::process::EProcessRights::parent_rights);
|
||||
if (!g_tServerProcessID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << STARTUP_CORE_ERROR_MSG << std::endl;
|
||||
return STARTUP_CORE_ERROR;
|
||||
}
|
||||
|
||||
// Register the process monitor...
|
||||
SProcessLifetimeCallback sProcessLifetimeCallback;
|
||||
uint32_t uiCookie = pProcessLifetime->RegisterMonitor(g_tServerProcessID, &sProcessLifetimeCallback);
|
||||
if (!uiCookie)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REGISTER_PROCESS_MONITOR_ERROR_MSG << std::endl;
|
||||
return REGISTER_PROCESS_MONITOR_ERROR;
|
||||
}
|
||||
|
||||
if (rsContext.bVerbose)
|
||||
std::cout << "Process ID: " << g_tServerProcessID << std::endl;
|
||||
|
||||
// Wait for 3 seconds to see if the process terminates... (which should not occur).
|
||||
bool bTerminated = pProcessLifetime->WaitForTerminate(g_tServerProcessID, 3000);
|
||||
pProcessLifetime->UnregisterMonitor(uiCookie);
|
||||
if (bTerminated)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CORE_NOT_STARTED_MSG << " Instance: #" << rsContext.uiInstanceID << " Exit code: " <<
|
||||
sProcessLifetimeCallback.iRetValue << std::endl;
|
||||
return CORE_NOT_STARTED;
|
||||
}
|
||||
|
||||
// Try to connect
|
||||
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " SDV Server instance #:" << rsContext.uiInstanceID <<
|
||||
std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "SDV Server #" << rsContext.uiInstanceID << " has successfully started..." << std::endl;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ShutdownSDVServer(const SContext& rsContext)
|
||||
{
|
||||
if (rsContext.seqCmdLine.size() != 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid arguments following SHUTDOWN command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Connecting to the SDV #" << rsContext.uiInstanceID << " server..." << std::endl;
|
||||
|
||||
// Try to connect
|
||||
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Requesting shutdown..." << std::endl;
|
||||
sdv::core::IObjectAccess* pObjAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::app::IAppShutdownRequest* pShutdownRequest = nullptr;
|
||||
if (pObjAccess)
|
||||
pShutdownRequest = sdv::TInterfaceAccessPtr(pObjAccess->GetObject("AppControlService")).
|
||||
GetInterface<sdv::app::IAppShutdownRequest>();
|
||||
if (pShutdownRequest)
|
||||
pShutdownRequest->RequestShutdown();
|
||||
ptrRepository.Clear();
|
||||
if (!pShutdownRequest)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << APP_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return APP_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Shutdown initiated..." << std::endl;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
sdv::process::TProcessID GetServerProcessID()
|
||||
{
|
||||
return g_tServerProcessID;
|
||||
}
|
||||
39
sdv_executables/sdv_control/startup_shutdown.h
Normal file
39
sdv_executables/sdv_control/startup_shutdown.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef STARTUP_SHUTDOWN_H
|
||||
#define STARTUP_SHUTDOWN_H
|
||||
|
||||
#include "context.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <interfaces/process.h>
|
||||
|
||||
/**
|
||||
* @brief Help for startup or shutdown the server.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void StartupShutdownHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Startup the SDV server.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int StartupSDVServer(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Shutdown the SDV Server.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ShutdownSDVServer(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Get the server process ID after a startup of the server.
|
||||
* @remarks The process ID is set when server execution is initiated. The presence of the process ID doesn't guarantee a successful
|
||||
* running of the server.
|
||||
* @return The process ID if the process execution was initiated. Or zero when the execution failed.
|
||||
*/
|
||||
sdv::process::TProcessID GetServerProcessID();
|
||||
|
||||
#endif // !defined STARTUP_SHUTDOWN_H
|
||||
Reference in New Issue
Block a user