/** * Copyright (C) 2021 Saturneric * * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GpgFrontend is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GpgFrontend. If not, see . * * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by * Saturneric starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GpgCommandExecutor.h" #include "GpgFunctionObject.h" #include "core/thread/TaskRunnerGetter.h" GpgFrontend::GpgCommandExecutor::GpgCommandExecutor(int channel) : SingletonFunctionObject(channel) {} void GpgFrontend::GpgCommandExecutor::Execute( std::string cmd, std::vector arguments, std::function callback, std::function interact_func) { LOG(INFO) << "called" << "cmd" << cmd << "arguments size" << arguments.size(); Thread::Task::TaskCallback result_callback = [](int rtn, Thread::Task::DataObjectPtr data_object) { LOG(INFO) << "called"; if (data_object->GetObjectSize() != 4) throw std::runtime_error("invalid data object size"); auto exit_code = data_object->PopObject(); auto process_stdout = data_object->PopObject(); auto process_stderr = data_object->PopObject(); auto callback = data_object->PopObject< std::function>(); // call callback callback(exit_code, process_stdout, process_stderr); }; Thread::Task::TaskRunnable runner = [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { LOG(INFO) << "process runner called, data object size" << data_object->GetObjectSize(); if (data_object->GetObjectSize() != 4) throw std::runtime_error("invalid data object size"); // get arguments auto cmd = data_object->PopObject(); LOG(INFO) << "get cmd" << cmd; auto arguments = data_object->PopObject>(); auto interact_func = data_object->PopObject>(); auto *cmd_process = new QProcess(); cmd_process->setProcessChannelMode(QProcess::MergedChannels); QObject::connect(cmd_process, &QProcess::started, []() -> void { LOG(INFO) << "process started"; }); QObject::connect( cmd_process, &QProcess::readyReadStandardOutput, [interact_func, cmd_process]() { interact_func(cmd_process); }); QObject::connect(cmd_process, &QProcess::errorOccurred, [=]() { LOG(ERROR) << "error in executing command:" << cmd; }); QObject::connect(cmd_process, qOverload(&QProcess::finished), [=](int, QProcess::ExitStatus status) { if (status == QProcess::NormalExit) LOG(INFO) << "succeed in executing command:" << cmd; else LOG(WARNING) << "error in executing command:" << cmd; }); cmd_process->setProgram(QString::fromStdString(cmd)); QStringList q_arguments; for (const auto &argument : arguments) q_arguments.append(QString::fromStdString(argument)); cmd_process->setArguments(q_arguments); LOG(INFO) << "process execute ready"; cmd_process->start(); cmd_process->waitForFinished(30); std::string process_stdout = cmd_process->readAllStandardOutput().toStdString(), process_stderr = cmd_process->readAllStandardError().toStdString(); int exit_code = cmd_process->exitCode(); cmd_process->close(); cmd_process->deleteLater(); // transfer result data_object->AppendObject(std::move(process_stderr)); data_object->AppendObject(std::move(process_stdout)); data_object->AppendObject(std::move(exit_code)); return 0; }; // data transfer into task auto data_object = std::make_shared(); data_object->AppendObject(std::move(callback)); data_object->AppendObject(std::move(interact_func)); data_object->AppendObject(std::move(arguments)); data_object->AppendObject(std::move(cmd)); auto *process_task = new GpgFrontend::Thread::Task( std::move(runner), std::move(result_callback), data_object); QEventLoop looper; QObject::connect(process_task, &Thread::Task::SignalTaskFinished, &looper, &QEventLoop::quit); GpgFrontend::Thread::TaskRunnerGetter::GetInstance() .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) ->PostTask(process_task); // block until task finished // this is to keep reference vaild until task finished looper.exec(); }