/**
* 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();
}