Files
openvehicle-api/sdv_executables/sdv_control/startup_shutdown.cpp
tompzf 6ed4b1534e Precommit (#1)
* first commit

* cleanup
2025-11-04 13:28:06 +01:00

207 lines
7.9 KiB
C++

#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;
}