diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/GpgContext.cpp | 184 | ||||
-rw-r--r-- | src/core/GpgCoreInit.cpp | 62 | ||||
-rw-r--r-- | src/core/function/gpg/GpgAdvancedOperator.cpp | 197 | ||||
-rw-r--r-- | src/core/function/gpg/GpgCommandExecutor.cpp | 198 | ||||
-rw-r--r-- | src/core/function/gpg/GpgCommandExecutor.h | 35 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyOpera.cpp | 79 | ||||
-rw-r--r-- | src/core/module/ModuleManager.cpp | 6 | ||||
-rw-r--r-- | src/core/thread/Task.cpp | 51 | ||||
-rw-r--r-- | src/core/thread/Task.h | 65 | ||||
-rw-r--r-- | src/core/thread/TaskRunner.cpp | 42 | ||||
-rw-r--r-- | src/core/thread/TaskRunner.h | 9 | ||||
-rw-r--r-- | src/ui/GpgFrontendApplication.cpp | 5 |
12 files changed, 442 insertions, 491 deletions
diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp index 059a5179..5a681fa7 100644 --- a/src/core/GpgContext.cpp +++ b/src/core/GpgContext.cpp @@ -36,6 +36,7 @@ #include <mutex> #include <shared_mutex> #include <string> +#include <vector> #include "core/GpgConstants.h" #include "core/common/CoreCommonUtil.h" @@ -351,93 +352,98 @@ const GpgInfo &GpgContext::GetInfo(bool refresh) { SPDLOG_DEBUG("start to load extra info"); // get all components - GpgCommandExecutor::GetInstance().Execute( - info_.GpgConfPath, {"--list-components"}, - [this](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf components exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} ,process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &components_info = info_.ComponentsInfo; - components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion, - _("Embedded In"), "/"}; - - auto gpgconf_binary_checksum = - check_binary_chacksum(info_.GpgConfPath); - components_info["gpgconf"] = {"GPG Configure", "/", info_.GpgConfPath, - gpgconf_binary_checksum.has_value() - ? gpgconf_binary_checksum.value() - : "/"}; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - if (info_split_list.size() != 3) continue; - - auto component_name = info_split_list[0]; - auto component_desc = info_split_list[1]; - auto component_path = info_split_list[2]; - - boost::algorithm::trim(component_name); - boost::algorithm::trim(component_desc); - boost::algorithm::trim(component_path); + GpgCommandExecutor::GetInstance().ExecuteSync( + {info_.GpgConfPath, + {"--list-components"}, + [this](int exit_code, const std::string &p_out, + const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf components exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {} ,process stdout: " + "{}", + p_err, p_out); + return; + } + + auto &components_info = info_.ComponentsInfo; + components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion, + _("Embedded In"), "/"}; + + auto gpgconf_binary_checksum = + check_binary_chacksum(info_.GpgConfPath); + components_info["gpgconf"] = {"GPG Configure", "/", + info_.GpgConfPath, + gpgconf_binary_checksum.has_value() + ? gpgconf_binary_checksum.value() + : "/"}; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + if (info_split_list.size() != 3) continue; + + auto component_name = info_split_list[0]; + auto component_desc = info_split_list[1]; + auto component_path = info_split_list[2]; + + boost::algorithm::trim(component_name); + boost::algorithm::trim(component_desc); + boost::algorithm::trim(component_path); #ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(component_path, "%3a", ":"); + // replace some special substrings on windows platform + boost::replace_all(component_path, "%3a", ":"); #endif - auto binary_checksum = check_binary_chacksum(component_path); - - SPDLOG_DEBUG( - "gnupg component name: {} desc: {} checksum: {} path: {} ", - component_name, component_desc, - binary_checksum.has_value() ? binary_checksum.value() : "/", - component_path); - - std::string version = "/"; - - if (component_name == "gpg") { - version = info_.GnupgVersion; - } - if (component_name == "gpg-agent") { - info_.GpgAgentPath = component_path; - } - if (component_name == "dirmngr") { - info_.DirmngrPath = component_path; - } - if (component_name == "keyboxd") { - info_.KeyboxdPath = component_path; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - // add component info to list - components_info[component_name] = { - component_desc, version, component_path, - binary_checksum.has_value() ? binary_checksum.value() : "/"}; - } - } - }); + auto binary_checksum = check_binary_chacksum(component_path); + + SPDLOG_DEBUG( + "gnupg component name: {} desc: {} checksum: {} path: {} ", + component_name, component_desc, + binary_checksum.has_value() ? binary_checksum.value() : "/", + component_path); + + std::string version = "/"; + + if (component_name == "gpg") { + version = info_.GnupgVersion; + } + if (component_name == "gpg-agent") { + info_.GpgAgentPath = component_path; + } + if (component_name == "dirmngr") { + info_.DirmngrPath = component_path; + } + if (component_name == "keyboxd") { + info_.KeyboxdPath = component_path; + } + + { + // try lock + std::unique_lock lock(info_.Lock); + // add component info to list + components_info[component_name] = { + component_desc, version, component_path, + binary_checksum.has_value() ? binary_checksum.value() : "/"}; + } + } + }}); SPDLOG_DEBUG("start to get dirs info"); - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--list-dirs"}, + GpgCommandExecutor::ExecuteContexts exec_contexts; + + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + info_.GpgConfPath, + {"--list-dirs"}, [this](int exit_code, const std::string &p_out, const std::string &p_err) { SPDLOG_DEBUG( @@ -486,7 +492,7 @@ const GpgInfo &GpgContext::GetInfo(bool refresh) { configurations_info[configuration_name] = {configuration_value}; } } - }); + }}); SPDLOG_DEBUG("start to get components info"); @@ -495,8 +501,9 @@ const GpgInfo &GpgContext::GetInfo(bool refresh) { if (component.first == "gpgme" || component.first == "gpgconf") continue; - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--check-options", component.first}, + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + info_.GpgConfPath, + {"--check-options", component.first}, [this, component](int exit_code, const std::string &p_out, const std::string &p_err) { SPDLOG_DEBUG( @@ -542,7 +549,7 @@ const GpgInfo &GpgContext::GetInfo(bool refresh) { boost::algorithm::trim(options_info[configuration_name][4]); } } - }); + }}); } SPDLOG_DEBUG("start to get avaliable component options info"); @@ -552,8 +559,9 @@ const GpgInfo &GpgContext::GetInfo(bool refresh) { if (component.first == "gpgme" || component.first == "gpgconf") continue; - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--list-options", component.first}, + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + info_.GpgConfPath, + {"--list-options", component.first}, [this, component](int exit_code, const std::string &p_out, const std::string &p_err) { SPDLOG_DEBUG( @@ -614,8 +622,10 @@ const GpgInfo &GpgContext::GetInfo(bool refresh) { available_options_info[configuration_name][8]); } } - }); + }}); } + + GpgCommandExecutor::GetInstance().ExecuteConcurrentlySync(exec_contexts); extend_info_loaded_ = true; } diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 0441b7d8..62344287 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -206,36 +206,38 @@ void init_gpgfrontend_core() { // async init no-ascii channel Thread::TaskRunnerGetter::GetInstance() .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) - ->PostTask(new Thread::Task([=](Thread::DataObjectPtr data_obj) -> int { - // init non-ascii channel - auto& ctx = GpgFrontend::GpgContext::CreateInstance( - GPGFRONTEND_NON_ASCII_CHANNEL, - [=]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; - args.ascii = false; - - // set key database path - if (use_custom_key_database_path && - !custom_key_database_path.empty()) { - args.db_path = custom_key_database_path; - } - - if (use_custom_gnupg_install_path) { - args.custom_gpgconf = true; - args.custom_gpgconf_path = - custom_gnupg_install_fs_path.u8string(); - } - - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); - - if (!ctx.good()) SPDLOG_ERROR("no-ascii channel init error"); - return ctx.good() ? 0 : -1; - })); + ->PostTask(new Thread::Task( + [=](Thread::DataObjectPtr data_obj) -> int { + // init non-ascii channel + auto& ctx = GpgFrontend::GpgContext::CreateInstance( + GPGFRONTEND_NON_ASCII_CHANNEL, + [=]() -> std::unique_ptr<ChannelObject> { + GpgFrontend::GpgContextInitArgs args; + args.ascii = false; + + // set key database path + if (use_custom_key_database_path && + !custom_key_database_path.empty()) { + args.db_path = custom_key_database_path; + } + + if (use_custom_gnupg_install_path) { + args.custom_gpgconf = true; + args.custom_gpgconf_path = + custom_gnupg_install_fs_path.u8string(); + } + + args.offline_mode = forbid_all_gnupg_connection; + args.auto_import_missing_key = auto_import_missing_key; + args.use_pinentry = use_pinentry_as_password_input_dialog; + + return std::unique_ptr<ChannelObject>(new GpgContext(args)); + }); + + if (!ctx.good()) SPDLOG_ERROR("no-ascii channel init error"); + return ctx.good() ? 0 : -1; + }, + "default_channel_ctx_init")); // try to restart all components GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 14202942..c338e69a 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.cpp +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -40,50 +40,53 @@ GpgFrontend::GpgAdvancedOperator::GpgAdvancedOperator(int channel) bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--reload", "gpg-agent"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - SPDLOG_DEBUG("gpgconf reload exit code: {}", exit_code); - success = true; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().GpgConfPath, + {"--reload", "gpg-agent"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + SPDLOG_DEBUG("gpgconf reload exit code: {}", exit_code); + success = true; + } + }}); return success; } bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--reload"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().GpgConfPath, + {"--reload"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + } else { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }}); return success; } bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--verbose", "--kill", "all"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - return; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().GpgConfPath, + {"--verbose", "--kill", "all"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + return; + } else { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }}); if (!success) return false; @@ -98,87 +101,89 @@ bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--apply-defaults"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().GpgConfPath, + {"--apply-defaults"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + } else { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }}); return success; } bool GpgFrontend::GpgAdvancedOperator::StartGpgAgent() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgAgentPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start gpg-agent successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("gpg-agent already started"); - } else { - SPDLOG_ERROR( - "gpg-agent execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().GpgAgentPath, + {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + SPDLOG_INFO("start gpg-agent successfully"); + } else if (exit_code == 2) { + success = true; + SPDLOG_INFO("gpg-agent already started"); + } else { + SPDLOG_ERROR( + "gpg-agent execute error, process stderr: {}, process stdout: " + "{}", + p_err, p_out); + return; + } + }}); return success; } bool GpgFrontend::GpgAdvancedOperator::StartDirmngr() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().DirmngrPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start dirmngr successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("dirmngr already started"); - } else { - SPDLOG_ERROR( - "dirmngr execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().DirmngrPath, + {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + SPDLOG_INFO("start dirmngr successfully"); + } else if (exit_code == 2) { + success = true; + SPDLOG_INFO("dirmngr already started"); + } else { + SPDLOG_ERROR( + "dirmngr execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }}); return success; } bool GpgFrontend::GpgAdvancedOperator::StartKeyBoxd() { bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().KeyboxdPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start keyboxd successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("keyboxd already started"); - } else { - SPDLOG_ERROR( - "keyboxd execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().KeyboxdPath, + {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + SPDLOG_INFO("start keyboxd successfully"); + } else if (exit_code == 2) { + success = true; + SPDLOG_INFO("keyboxd already started"); + } else { + SPDLOG_ERROR( + "keyboxd execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }}); return success; } diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index 2fee2be6..2e453388 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -34,134 +34,86 @@ #include "core/thread/TaskRunnerGetter.h" #include "thread/DataObject.h" -GpgFrontend::GpgCommandExecutor::GpgCommandExecutor(int channel) - : SingletonFunctionObject<GpgCommandExecutor>(channel) {} - -void GpgFrontend::GpgCommandExecutor::Execute( - std::string cmd, std::vector<std::string> arguments, - GpgCommandExecutorCallback callback, - GpgCommandExecutorInteractor interact_func) { - SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); - - Thread::Task::TaskCallback result_callback = - [](int rtn, Thread::DataObjectPtr data_object) { - SPDLOG_DEBUG("data object use count: {}", data_object->GetObjectSize()); - if (!data_object->Check<int, std::string, std::string, - GpgCommandExecutorCallback>()) - throw std::runtime_error("invalid data object size"); - - auto exit_code = Thread::ExtractParams<int>(data_object, 0); - auto process_stdout = - Thread::ExtractParams<std::string>(data_object, 1); - auto process_stderr = - Thread::ExtractParams<std::string>(data_object, 2); - auto callback = - Thread::ExtractParams<GpgCommandExecutorCallback>(data_object, 3); - - // call callback - callback(exit_code, process_stdout, process_stderr); - }; - - Thread::Task::TaskRunnable runner = - [](Thread::DataObjectPtr data_object) -> int { - SPDLOG_DEBUG("process runner called, data object size: {}", - data_object->GetObjectSize()); - - if (!data_object->Check<std::string, std::vector<std::string>, - GpgCommandExecutorInteractor, - GpgCommandExecutorCallback>()) - throw std::runtime_error("invalid data object size"); +namespace GpgFrontend { - // get arguments - auto cmd = Thread::ExtractParams<std::string>(data_object, 0); - SPDLOG_DEBUG("get cmd: {}", cmd); - auto arguments = - Thread::ExtractParams<std::vector<std::string>>(data_object, 1); - auto interact_func = - Thread::ExtractParams<GpgCommandExecutorInteractor>(data_object, 2); - auto callback = - Thread::ExtractParams<GpgCommandExecutorCallback>(data_object, 3); - - auto *cmd_process = new QProcess(); - cmd_process->setProcessChannelMode(QProcess::MergedChannels); - - QObject::connect(cmd_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("process started"); }); - QObject::connect( - cmd_process, &QProcess::readyReadStandardOutput, - [interact_func, cmd_process]() { interact_func(cmd_process); }); - QObject::connect(cmd_process, &QProcess::errorOccurred, - [=](QProcess::ProcessError error) { - SPDLOG_ERROR("error in executing command: {} error: {}", - cmd, error); - }); - QObject::connect( - cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), - [=](int, QProcess::ExitStatus status) { - if (status == QProcess::NormalExit) - SPDLOG_DEBUG( - "proceess finished, succeed in executing command: {}, exit " - "status: {}", - cmd, status); - else - SPDLOG_ERROR( - "proceess finished, error in executing command: {}, exit " - "status: {}", - cmd, status); - }); +GpgCommandExecutor::GpgCommandExecutor(int channel) + : SingletonFunctionObject<GpgCommandExecutor>(channel) {} - cmd_process->setProgram(QString::fromStdString(cmd)); +void GpgCommandExecutor::ExecuteSync(ExecuteContext context) { + Thread::Task *task = build_task(context); + QEventLoop looper; + QObject::connect(task, &Thread::Task::SignalTaskEnd, &looper, + &QEventLoop::quit); - QStringList q_arguments; - for (const auto &argument : arguments) - q_arguments.append(QString::fromStdString(argument)); - cmd_process->setArguments(q_arguments); + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(task); - SPDLOG_DEBUG("process execute ready, cmd: {} {}", cmd, - q_arguments.join(" ").toStdString()); + // block until task finished + // this is to keep reference vaild until task finished + looper.exec(); +} - cmd_process->start(); - cmd_process->waitForFinished(); +void GpgCommandExecutor::ExecuteConcurrentlyAsync(ExecuteContexts contexts) { + for (auto &context : contexts) { + auto &cmd = context.cmd; + auto &arguments = context.arguments; + auto &interact_func = context.interact_func; + auto &callback = context.callback; + + SPDLOG_INFO("gpg concurrently called cmd {}", cmd); + + Thread::Task *task = build_task(context); + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(task); + } +} - std::string process_stdout = - cmd_process->readAllStandardOutput().toStdString(), - process_stderr = - cmd_process->readAllStandardError().toStdString(); - int exit_code = cmd_process->exitCode(); +void GpgCommandExecutor::ExecuteConcurrentlySync( + const ExecuteContexts contexts) { + QEventLoop looper; + int remainingTasks = contexts.size(); - cmd_process->close(); - cmd_process->deleteLater(); + for (auto &context : contexts) { + auto &cmd = context.cmd; + auto &arguments = context.arguments; + auto &interact_func = context.interact_func; + auto &callback = context.callback; - data_object->Swap({exit_code, process_stdout, process_stderr, callback}); - return 0; - }; + SPDLOG_INFO("gpg concurrently called cmd {}", cmd); - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("Execute/{}", cmd), - Thread::TransferParams(cmd, arguments, interact_func, callback), - std::move(result_callback)); + Thread::Task *task = build_task(context); - QEventLoop looper; - QObject::connect(process_task, &Thread::Task::SignalTaskEnd, &looper, - &QEventLoop::quit); + QObject::connect(task, &Thread::Task::SignalTaskEnd, [&]() { + --remainingTasks; + if (remainingTasks <= 0) { + looper.quit(); + } + }); - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostConcurrentTask(task); + } - // block until task finished - // this is to keep reference vaild until task finished looper.exec(); } -void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( - std::string cmd, std::vector<std::string> arguments, - GpgCommandExecutorCallback callback, - GpgCommandExecutorInteractor interact_func) { - SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); +Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { + auto &cmd = context.cmd; + auto &arguments = context.arguments; + auto &interact_function = context.interact_func; + auto &callback = context.callback; + + SPDLOG_DEBUG("building task: called cmd {} arguments size: {}", cmd, + arguments.size()); Thread::Task::TaskCallback result_callback = [](int rtn, Thread::DataObjectPtr data_object) { + SPDLOG_DEBUG("data object use count: {}", data_object->GetObjectSize()); if (!data_object->Check<int, std::string, std::string, GpgCommandExecutorCallback>()) throw std::runtime_error("invalid data object size"); @@ -179,7 +131,7 @@ void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( }; Thread::Task::TaskRunnable runner = - [](GpgFrontend::Thread::DataObjectPtr data_object) -> int { + [](Thread::DataObjectPtr data_object) -> int { SPDLOG_DEBUG("process runner called, data object size: {}", data_object->GetObjectSize()); @@ -190,10 +142,11 @@ void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( // get arguments auto cmd = Thread::ExtractParams<std::string>(data_object, 0); + SPDLOG_DEBUG("get cmd: {}", cmd); auto arguments = Thread::ExtractParams<std::vector<std::string>>(data_object, 1); auto interact_func = - Thread::ExtractParams<std::function<void(QProcess *)>>(data_object, 2); + Thread::ExtractParams<GpgCommandExecutorInteractor>(data_object, 2); auto callback = Thread::ExtractParams<GpgCommandExecutorCallback>(data_object, 3); @@ -226,14 +179,13 @@ void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( }); cmd_process->setProgram(QString::fromStdString(cmd)); - cmd_process->setProcessChannelMode(QProcess::SeparateChannels); QStringList q_arguments; for (const auto &argument : arguments) q_arguments.append(QString::fromStdString(argument)); cmd_process->setArguments(q_arguments); - SPDLOG_DEBUG("process start ready, cmd: {} {}", cmd, + SPDLOG_DEBUG("process execute ready, cmd: {} {}", cmd, q_arguments.join(" ").toStdString()); cmd_process->start(); @@ -252,16 +204,10 @@ void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( return 0; }; - // data transfer into task - auto data_object = - Thread::TransferParams(cmd, arguments, interact_func, callback); - - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("ExecuteConcurrently/{}", cmd), - data_object, std::move(result_callback), false); - process_task->HoldOnLifeCycle(true); - - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); + return new Thread::Task( + std::move(runner), fmt::format("Execute/{}", cmd), + Thread::TransferParams(cmd, arguments, interact_function, callback), + std::move(result_callback)); } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h index 1bad6d40..98167269 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -29,6 +29,7 @@ #ifndef GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H #define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H +#include <initializer_list> #ifndef WINDOWS #include <boost/process.hpp> #endif @@ -50,6 +51,25 @@ using GpgCommandExecutorInteractor = std::function<void(QProcess *)>; class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> { public: + struct ExecuteContext { + const std::string cmd; + const std::vector<std::string> arguments; + const GpgCommandExecutorCallback callback; + const GpgCommandExecutorInteractor interact_func; + + ExecuteContext( + std::string cmd, std::vector<std::string> arguments, + GpgCommandExecutorCallback callback = [](int, std::string, + std::string) {}, + GpgCommandExecutorInteractor interact_func = [](QProcess *) {}) + : cmd(cmd), + arguments(arguments), + callback(callback), + interact_func(interact_func) {} + }; + + using ExecuteContexts = std::vector<ExecuteContext>; + /** * @brief Construct a new Gpg Command Executor object * @@ -64,20 +84,17 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor * @param arguments Command parameters * @param interact_func Command answering function */ - void Execute( - std::string cmd, std::vector<std::string> arguments, - GpgCommandExecutorCallback callback = [](int, std::string, - std::string) {}, - GpgCommandExecutorInteractor interact_func = [](QProcess *) {}); + void ExecuteSync(ExecuteContext); - void ExecuteConcurrently( - std::string cmd, std::vector<std::string> arguments, - GpgCommandExecutorCallback callback, - GpgCommandExecutorInteractor interact_func = [](QProcess *) {}); + void ExecuteConcurrentlyAsync(ExecuteContexts); + + void ExecuteConcurrentlySync(ExecuteContexts); private: GpgContext &ctx_ = GpgContext::GetInstance( SingletonFunctionObject::GetChannel()); ///< Corresponding context + + Thread::Task *build_task(const ExecuteContext &); }; } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index cc87fd4b..bdce3831 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -105,45 +105,46 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( const GpgKey& key, const std::string& output_file_path) { // get all components - GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().AppPath, - {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", - output_file_path, "--gen-revoke", key.GetFingerprint().c_str()}, - [=](int exit_code, const std::string& p_out, const std::string& p_err) { - if (exit_code != 0) { - SPDLOG_ERROR( - "gnupg gen revoke execute error, process stderr: {}, process " - "stdout: {}", - p_err, p_out); - } else { - SPDLOG_DEBUG( - "gnupg gen revoke exit_code: {}, process stdout size: {}", - exit_code, p_out.size()); - } - }, - [](QProcess* proc) -> void { - // Code From Gpg4Win - while (proc->canReadLine()) { - const QString line = QString::fromUtf8(proc->readLine()).trimmed(); - SPDLOG_DEBUG("line: {}", line.toStdString()); - if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE " - "ask_revocation_reason.code")) { - proc->write("0\n"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE " - "ask_revocation_reason.text")) { - proc->write("\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { - // We asked before - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_BOOL " - "ask_revocation_reason.okay")) { - proc->write("y\n"); - } - } - }); + GpgCommandExecutor::GetInstance().ExecuteSync( + {ctx_.GetInfo().AppPath, + {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", + output_file_path, "--gen-revoke", key.GetFingerprint().c_str()}, + [=](int exit_code, const std::string& p_out, const std::string& p_err) { + if (exit_code != 0) { + SPDLOG_ERROR( + "gnupg gen revoke execute error, process stderr: {}, process " + "stdout: {}", + p_err, p_out); + } else { + SPDLOG_DEBUG( + "gnupg gen revoke exit_code: {}, process stdout size: {}", + exit_code, p_out.size()); + } + }, + [](QProcess* proc) -> void { + // Code From Gpg4Win + while (proc->canReadLine()) { + const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + SPDLOG_DEBUG("line: {}", line.toStdString()); + if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.code")) { + proc->write("0\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.text")) { + proc->write("\n"); + } else if (line == + QLatin1String( + "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { + // We asked before + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_BOOL " + "ask_revocation_reason.okay")) { + proc->write("y\n"); + } + } + }}); } /** diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp index b9e73721..f578e67c 100644 --- a/src/core/module/ModuleManager.cpp +++ b/src/core/module/ModuleManager.cpp @@ -51,7 +51,7 @@ class ModuleManager::Impl { gpc_->RegisterModule(module); return 0; }), - __func__, nullptr, true)); + __func__, nullptr)); } void TriggerEvent(EventRefrernce event) { @@ -60,7 +60,7 @@ class ModuleManager::Impl { gpc_->TriggerEvent(event); return 0; }), - __func__, nullptr, true)); + __func__, nullptr)); } void ActiveModule(ModuleIdentifier identifier) { @@ -69,7 +69,7 @@ class ModuleManager::Impl { gpc_->ActiveModule(identifier); return 0; }), - __func__, nullptr, true)); + __func__, nullptr)); } std::optional<TaskRunnerPtr> GetTaskRunner(ModuleIdentifier module_id) { diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp index bda64564..6e545d81 100644 --- a/src/core/thread/Task.cpp +++ b/src/core/thread/Task.cpp @@ -28,6 +28,8 @@ #include "core/thread/Task.h" +#include <qobjectdefs.h> + #include <boost/stacktrace.hpp> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> @@ -49,7 +51,7 @@ class Task::Impl : public QObject { } Impl(Task *parent, TaskRunnable runnable, std::string name, - DataObjectPtr data_object, bool sequency) + DataObjectPtr data_object) : QObject(parent), parent_(parent), uuid_(generate_uuid()), @@ -57,15 +59,14 @@ class Task::Impl : public QObject { runnable_(std::move(runnable)), callback_(std::move([](int, const DataObjectPtr &) {})), callback_thread_(QThread::currentThread()), - data_object_(data_object), - sequency_(sequency) { + data_object_(data_object) { SPDLOG_TRACE("task {} created with runnable, callback_thread_: {}", GetFullID(), static_cast<void *>(callback_thread_)); init(); } Impl(Task *parent, TaskRunnable runnable, std::string name, - DataObjectPtr data_object, TaskCallback callback, bool sequency) + DataObjectPtr data_object, TaskCallback callback) : QObject(parent), parent_(parent), uuid_(generate_uuid()), @@ -73,8 +74,7 @@ class Task::Impl : public QObject { runnable_(std::move(runnable)), callback_(std::move(callback)), callback_thread_(QThread::currentThread()), - data_object_(data_object), - sequency_(sequency) { + data_object_(data_object) { SPDLOG_TRACE( "task {} created with runnable and callback, callback_thread_: {}", GetFullID(), static_cast<void *>(callback_thread_)); @@ -92,8 +92,6 @@ class Task::Impl : public QObject { std::string GetUUID() const { return uuid_; } - bool GetSequency() const { return sequency_; } - void Run() { SPDLOG_DEBUG("task {} is using default runnable and callback mode", GetFullID()); @@ -137,14 +135,13 @@ class Task::Impl : public QObject { boost::stacktrace::to_string(boost::stacktrace::stacktrace())); } // raise signal to anounce after runnable returned - if (parent_->autoDelete()) slot_task_run_callback(rtn_); + if (parent_->autoDelete()) emit parent_->SignalTaskShouldEnd(rtn_); } private: Task *const parent_; const std::string uuid_; const std::string name_; - const bool sequency_ = true; ///< must run in the same thread TaskCallback callback_; ///< TaskRunnable runnable_; ///< int rtn_ = 0; ///< @@ -152,14 +149,18 @@ class Task::Impl : public QObject { DataObjectPtr data_object_ = nullptr; ///< void init() { + // + HoldOnLifeCycle(false); + + // connect(parent_, &Task::SignalRun, this, &Task::Impl::slot_run); // connect(parent_, &Task::SignalTaskShouldEnd, this, - &Impl::slot_task_run_callback); + &Impl::slot_task_should_end); // - connect(parent_, &Task::SignalTaskShouldEnd, parent_, &Task::deleteLater); + connect(parent_, &Task::SignalTaskEnd, parent_, &Task::deleteLater); } /** @@ -177,7 +178,7 @@ class Task::Impl : public QObject { * @brief * */ - void slot_task_run_callback(int rtn) { + void slot_task_should_end(int rtn) { SPDLOG_TRACE("task runnable {} finished, rtn: {}", GetFullID(), rtn); // set return value this->SetRTN(rtn); @@ -218,18 +219,14 @@ class Task::Impl : public QObject { } }; -const std::string DEFAULT_TASK_NAME = "unnamed-task"; - -Task::Task(std::string name) : p_(std::make_unique<Impl>(this, name)) {} +Task::Task(std::string name) : p_(new Impl(this, name)) {} -Task::Task(TaskRunnable runnable, std::string name, DataObjectPtr data_object, - bool sequency) - : p_(std::make_unique<Impl>(this, runnable, name, data_object, sequency)) {} +Task::Task(TaskRunnable runnable, std::string name, DataObjectPtr data_object) + : p_(new Impl(this, runnable, name, data_object)) {} Task::Task(TaskRunnable runnable, std::string name, DataObjectPtr data_object, - TaskCallback callback, bool sequency) - : p_(std::make_unique<Impl>(this, runnable, name, data_object, callback, - sequency)) {} + TaskCallback callback) + : p_(new Impl(this, runnable, name, data_object, callback)) {} Task::~Task() = default; @@ -242,17 +239,19 @@ std::string Task::GetFullID() const { return p_->GetFullID(); } std::string Task::GetUUID() const { return p_->GetUUID(); } -bool Task::GetSequency() const { return p_->GetSequency(); } - void Task::HoldOnLifeCycle(bool hold_on) { p_->HoldOnLifeCycle(hold_on); } void Task::SetRTN(int rtn) { p_->SetRTN(rtn); } -void Task::SlotRun() { emit SignalRun(); } +void Task::SafelyRun() { emit SignalRun(); } void Task::Run() { p_->Run(); } -void Task::run() { this->SlotRun(); } +void Task::run() { + SPDLOG_DEBUG("interface run() of task {} was called by thread: {}", + GetFullID(), QThread::currentThread()->currentThreadId()); + this->SafelyRun(); +} } // namespace GpgFrontend::Thread diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h index 769fafd2..f6a2abe8 100644 --- a/src/core/thread/Task.h +++ b/src/core/thread/Task.h @@ -34,7 +34,6 @@ namespace GpgFrontend::Thread { class TaskRunner; -extern const std::string DEFAULT_TASK_NAME; class DataObject; using DataObjectPtr = std::shared_ptr<DataObject>; ///< @@ -51,96 +50,50 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * @brief Construct a new Task object * */ - Task(std::string name = DEFAULT_TASK_NAME); + Task(std::string name); /** * @brief Construct a new Task object * * @param callback The callback function to be executed. */ - explicit Task(TaskRunnable runnable, std::string name = DEFAULT_TASK_NAME, - DataObjectPtr data_object = nullptr, bool sequency = true); + explicit Task(TaskRunnable runnable, std::string name, + DataObjectPtr data_object = nullptr); /** * @brief Construct a new Task object * * @param runnable */ - explicit Task( - TaskRunnable runnable, std::string name, DataObjectPtr data, - TaskCallback callback = [](int, const std::shared_ptr<DataObject> &) {}, - bool sequency = true); + explicit Task(TaskRunnable runnable, std::string name, DataObjectPtr data, + TaskCallback callback); - /** - * @brief Destroy the Task object - * - */ virtual ~Task() override; - /** - * @brief Run - run the task - * - */ - virtual void Run(); - - /** - * @brief - * - * @return std::string - */ std::string GetUUID() const; - /** - * @brief - * - * @return std::string - */ std::string GetFullID() const; - /** - * @brief - * - * @return bool - */ - bool GetSequency() const; - void HoldOnLifeCycle(bool hold_on); - public slots: + virtual void Run(); - /** - * @brief - * - */ - void SlotRun(); + public slots: + void SafelyRun(); signals: - void SignalRun(); - /** - * @brief task should finish - * - */ void SignalTaskShouldEnd(int rtn); - /** - * @brief task is finished - * - */ void SignalTaskEnd(); protected: - /** - * @brief - * - * @param rtn - */ void SetRTN(int rtn); private: class Impl; - std::unique_ptr<Impl> p_; + Impl* p_; virtual void run() override; }; diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index 494e356c..e8b85e93 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -48,30 +48,36 @@ class TaskRunner::Impl : public QThread { } task->setParent(nullptr); + task->moveToThread(this); - if (task->GetSequency()) { - SPDLOG_TRACE("post task: {}, sequency mode: {}", task->GetFullID(), - task->GetSequency()); - task->moveToThread(this); - } else { - if (pool_.tryStart(task)) { - SPDLOG_TRACE("runner's pool starts concurrent task {} immediately", - task->GetFullID()); - } else { - SPDLOG_TRACE("runner's pool will start concurrent task {} later", - task->GetFullID()); - } + SPDLOG_TRACE("runner's pool starts task: {}", task->GetFullID()); + task->SafelyRun(); + } + + void PostConcurrentTask(Task* task) { + if (task == nullptr) { + SPDLOG_ERROR("task posted is null"); + return; } - emit task->SignalRun(); + + auto* concurrent_thread = new QThread(this); + + task->setParent(nullptr); + task->moveToThread(concurrent_thread); + + connect(task, &Task::SignalTaskEnd, concurrent_thread, &QThread::quit); + connect(concurrent_thread, &QThread::finished, concurrent_thread, + &QThread::deleteLater); + + concurrent_thread->start(); + + task->SafelyRun(); } void PostScheduleTask(Task* task, size_t seconds) { if (task == nullptr) return; // TODO } - - private: - QThreadPool pool_; }; GpgFrontend::Thread::TaskRunner::TaskRunner() : p_(std::make_unique<Impl>()) {} @@ -82,6 +88,10 @@ void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { p_->PostTask(task); } +void GpgFrontend::Thread::TaskRunner::PostConcurrentTask(Task* task) { + p_->PostConcurrentTask(task); +} + void TaskRunner::PostScheduleTask(Task* task, size_t seconds) { p_->PostScheduleTask(task, seconds); } diff --git a/src/core/thread/TaskRunner.h b/src/core/thread/TaskRunner.h index 25187178..a4f9c98b 100644 --- a/src/core/thread/TaskRunner.h +++ b/src/core/thread/TaskRunner.h @@ -29,6 +29,8 @@ #ifndef GPGFRONTEND_TASKRUNNER_H #define GPGFRONTEND_TASKRUNNER_H +#include <vector> + #include "core/GpgFrontendCore.h" namespace GpgFrontend::Thread { @@ -69,6 +71,13 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QObject { * @brief * * @param task + */ + void PostConcurrentTask(Task* task); + + /** + * @brief + * + * @param task * @param seconds */ void PostScheduleTask(Task* task, size_t seconds); diff --git a/src/ui/GpgFrontendApplication.cpp b/src/ui/GpgFrontendApplication.cpp index 21932f44..83866c0d 100644 --- a/src/ui/GpgFrontendApplication.cpp +++ b/src/ui/GpgFrontendApplication.cpp @@ -73,9 +73,8 @@ GpgFrontendApplication *GpgFrontendApplication::GetInstance(int argc, } bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) { - bool app_done = true; try { - app_done = QApplication::notify(receiver, event); + return QApplication::notify(receiver, event); } catch (const std::exception &ex) { SPDLOG_ERROR("exception was caught in notify: {}", ex.what()); SPDLOG_ERROR("stacktrace of the exception: {}", @@ -97,7 +96,7 @@ bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) { "serious problem, it may be the negligence of the programmer, " "please report this problem if you can.")); } - return app_done; + return -1; } } // namespace GpgFrontend::UI |