mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-10-02 08:27:41 +00:00
Moved files out of gsmartcontrol directory after import from SVN.
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2018 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
/// \ingroup applib
|
||||
/// \weakgroup applib
|
||||
/// @{
|
||||
|
||||
#include <glib.h> // g_usleep()
|
||||
#include <glibmm/i18n.h>
|
||||
|
||||
#include "cmdex_sync.h"
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/// "Execution finished" signal
|
||||
sigc::signal<void, const CmdexSyncCommandInfo&> s_cmdex_sync_signal_execute_finish;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
cmdex_signal_execute_finish_type& cmdex_sync_signal_execute_finish()
|
||||
{
|
||||
return s_cmdex_sync_signal_execute_finish;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CmdexSync::CmdexSync(std::string command_name, std::string command_args)
|
||||
: CmdexSync()
|
||||
{
|
||||
this->set_command(std::move(command_name), std::move(command_args));
|
||||
}
|
||||
|
||||
|
||||
|
||||
CmdexSync::CmdexSync()
|
||||
{
|
||||
/// Translators: {command} will be replaced by command name.
|
||||
running_msg_ = _("Running {command}...");
|
||||
set_error_header(std::string(_("An error occurred while executing command:")) + "\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::set_command(std::string command_name, std::string command_args)
|
||||
{
|
||||
cmdex_.set_command(command_name, command_args);
|
||||
// keep a copy locally to avoid locking on get() every time
|
||||
command_name_ = std::move(command_name);
|
||||
command_args_ = std::move(command_args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string CmdexSync::get_command_name() const
|
||||
{
|
||||
return command_name_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string CmdexSync::get_command_args() const
|
||||
{
|
||||
return command_args_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CmdexSync::execute()
|
||||
{
|
||||
set_error_msg(""); // clear old error if present
|
||||
|
||||
bool slot_connected = !(signal_execute_tick.slots().begin() == signal_execute_tick.slots().end());
|
||||
|
||||
if (slot_connected && !signal_execute_tick.emit(TickStatus::starting))
|
||||
return false;
|
||||
|
||||
if (!cmdex_.execute()) { // try to execute
|
||||
debug_out_error("app", DBG_FUNC_MSG << "cmdex_.execute() failed.\n");
|
||||
import_error(); // get error from cmdex and display warnings if needed
|
||||
|
||||
// emit this for execution loggers
|
||||
cmdex_sync_signal_execute_finish().emit(CmdexSyncCommandInfo(get_command_name(),
|
||||
get_command_args(), get_stdout_str(), get_stderr_str(), get_error_msg()));
|
||||
|
||||
if (slot_connected)
|
||||
signal_execute_tick.emit(TickStatus::failed);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool stop_requested = false; // stop requested from tick function
|
||||
bool signals_sent = false; // stop signals sent
|
||||
|
||||
while(!cmdex_.stopped_cleanup_needed()) {
|
||||
|
||||
if (!stop_requested) { // running and no stop requested yet
|
||||
// call the tick function with "running" periodically.
|
||||
// if it returns false, try to stop.
|
||||
if (slot_connected && !signal_execute_tick.emit(TickStatus::running)) {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "execute_tick slot returned false, trying to stop the program.\n");
|
||||
stop_requested = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (stop_requested && !signals_sent) { // stop request received
|
||||
// send the stop request to the command
|
||||
if (!cmdex_.try_stop()) { // try sigterm. this returns false if it can't be done (no permissions, zombie)
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "cmdex_.try_stop() returned false.\n");
|
||||
}
|
||||
|
||||
// set sigkill timeout to 3 sec (in case sigterm fails); won't do anything if already exited.
|
||||
cmdex_.set_stop_timeouts(std::chrono::milliseconds(0), forced_kill_timeout_msec_);
|
||||
// import_error(); // don't need errors here - they will be available later anyway.
|
||||
|
||||
signals_sent = true;
|
||||
}
|
||||
|
||||
|
||||
// alert the tick function
|
||||
if (stop_requested && slot_connected) {
|
||||
signal_execute_tick.emit(TickStatus::stopping); // ignore returned value here
|
||||
}
|
||||
|
||||
|
||||
// Without this, no event sources will be processed and the program will
|
||||
// hang waiting for the child to exit (the watch handler won't be called).
|
||||
// Note: If you have an idle callback, g_main_context_pending() will
|
||||
// always return true (until the idle callback returns false and unregisters itself).
|
||||
while(g_main_context_pending(nullptr)) {
|
||||
g_main_context_iteration(nullptr, false);
|
||||
}
|
||||
|
||||
g_usleep(50*1000); // 50 msec. avoids 100% CPU usage.
|
||||
}
|
||||
|
||||
// command exited, do a cleanup.
|
||||
cmdex_.stopped_cleanup();
|
||||
import_error(); // get error from cmdex and display warnings if needed
|
||||
|
||||
// emit this for execution loggers
|
||||
cmdex_sync_signal_execute_finish().emit(CmdexSyncCommandInfo(get_command_name(),
|
||||
get_command_args(), get_stdout_str(), get_stderr_str(), get_error_msg()));
|
||||
|
||||
if (slot_connected)
|
||||
signal_execute_tick.emit(TickStatus::stopped); // last call
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::set_forced_kill_timeout(std::chrono::milliseconds timeout_msec)
|
||||
{
|
||||
forced_kill_timeout_msec_ = timeout_msec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string CmdexSync::get_error_msg(bool with_header) const
|
||||
{
|
||||
if (with_header)
|
||||
return error_header_ + error_msg_;
|
||||
return error_msg_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::set_running_msg(const std::string& msg)
|
||||
{
|
||||
running_msg_ = msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::set_error_header(const std::string& msg)
|
||||
{
|
||||
error_header_ = msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string CmdexSync::get_error_header()
|
||||
{
|
||||
return error_header_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::import_error()
|
||||
{
|
||||
Cmdex::error_list_t errors = cmdex_.get_errors(); // these are not clones
|
||||
hz::ErrorBase* e = nullptr;
|
||||
if (!errors.empty())
|
||||
e = errors.back()->clone();
|
||||
cmdex_.clear_errors(); // and clear them
|
||||
|
||||
if (e) { // if error is present, alert the user
|
||||
on_error_warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::on_error_warn(hz::ErrorBase* e)
|
||||
{
|
||||
if (e) {
|
||||
set_error_msg(e->get_message()); // this message will be displayed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CmdexSync::set_error_msg(const std::string& error_msg)
|
||||
{
|
||||
error_msg_ = error_msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string CmdexSync::get_running_msg() const
|
||||
{
|
||||
return running_msg_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Cmdex& CmdexSync::get_command_executor()
|
||||
{
|
||||
return cmdex_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
Reference in New Issue
Block a user