refactor core_process (1)

This commit is contained in:
arm64v8a
2022-09-11 11:38:48 +08:00
parent dbbd54077b
commit 06b0163319
7 changed files with 120 additions and 103 deletions

View File

@@ -399,8 +399,11 @@ namespace NekoRay {
outbound["settings"] = settings; outbound["settings"] = settings;
// EXTERNAL PROCESS // EXTERNAL PROCESS
auto extC = new sys::ExternalProcess(ent->bean->DisplayType(), auto extC = new sys::ExternalProcess();
extR.program, extR.arguments, extR.env); extC->tag = ent->bean->DisplayType();
extC->program = extR.program;
extC->arguments = extR.arguments;
extC->env = extR.env;
status->result->ext += extC; status->result->ext += extC;
} else { } else {
coreR = ent->bean->BuildCoreObj(); coreR = ent->bean->BuildCoreObj();

View File

@@ -41,6 +41,8 @@ namespace NekoRay {
QString core_token; QString core_token;
int core_port = 19810; int core_port = 19810;
int started_id = -1919; int started_id = -1919;
bool core_running = false;
bool core_prepare_exit = false;
Routing *routing = new Routing; Routing *routing = new Routing;
int imported_count = 0; int imported_count = 0;

View File

@@ -23,8 +23,6 @@ namespace QtGrpc {
const char *GrpcStatusMessage = "grpc-message"; const char *GrpcStatusMessage = "grpc-message";
const int GrpcMessageSizeHeaderSize = 5; const int GrpcMessageSizeHeaderSize = 5;
bool core_crashed = false;
class Http2GrpcChannelPrivate : public QObject { class Http2GrpcChannelPrivate : public QObject {
private: private:
QString url_base; QString url_base;
@@ -135,7 +133,7 @@ namespace QtGrpc {
QNetworkReply::NetworkError Call(const QString &methodName, QNetworkReply::NetworkError Call(const QString &methodName,
const google::protobuf::Message &req, google::protobuf::Message *rsp, const google::protobuf::Message &req, google::protobuf::Message *rsp,
int timeout_ms = 0) { int timeout_ms = 0) {
if (core_crashed) return QNetworkReply::NetworkError(-1919); if (!NekoRay::dataStore->core_running) return QNetworkReply::NetworkError(-1919);
std::string reqStr; std::string reqStr;
req.SerializeToString(&reqStr); req.SerializeToString(&reqStr);

View File

@@ -1,57 +1,46 @@
#include "ExternalProcess.hpp" #include "ExternalProcess.hpp"
#include <QTimer>
namespace NekoRay::sys { namespace NekoRay::sys {
ExternalProcess::ExternalProcess(const QString &tag, ExternalProcess::ExternalProcess() : QProcess() {}
const QString &program,
const QStringList &arguments,
const QStringList &env)
: QProcess() {
this->tag = tag;
this->program = program;
this->arguments = arguments;
this->env = env;
this->running_list = &running_ext;
}
void ExternalProcess::Start() { void ExternalProcess::Start() {
if (started) return; if (started) return;
started = true; started = true;
*running_list += this; if (managed) running_ext.push_back(this);
if (show_log) { if (show_log) {
connect(this, &QProcess::readyReadStandardOutput, this, connect(this, &QProcess::readyReadStandardOutput, this, [&]() {
[&]() { showLog_ext_vt100(readAllStandardOutput().trimmed());
showLog_ext_vt100(readAllStandardOutput().trimmed()); });
}); connect(this, &QProcess::readyReadStandardError, this, [&]() {
connect(this, &QProcess::readyReadStandardError, this, showLog_ext_vt100(readAllStandardError().trimmed());
[&]() { });
showLog_ext_vt100(readAllStandardError().trimmed());
});
} }
connect(this, &QProcess::errorOccurred, this, if (managed) {
[&](QProcess::ProcessError error) { connect(this, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
if (!killed) { if (!killed) {
crashed = true;
showLog_ext(tag, "errorOccurred:" + errorString());
dialog_message("ExternalProcess", "Crashed");
}
});
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
if (state == QProcess::NotRunning) {
if (killed) { // 用户命令退出
showLog_ext(tag, "Stopped");
} else if (!crashed) { // 异常退出
crashed = true; crashed = true;
showLog_ext(tag, "[Error] Crashed:" + QProcess::errorString()); showLog_ext(tag, "[Error] Program exited accidentally: " + errorString());
Kill();
dialog_message("ExternalProcess", "Crashed"); dialog_message("ExternalProcess", "Crashed");
} }
}); }
connect(this, &QProcess::stateChanged, this, });
[&](QProcess::ProcessState state) { showLog_ext(tag, "[Starting] " + env.join(" ") + " " + program + " " + arguments.join(" "));
if (state == QProcess::NotRunning) { }
if (killed) {
showLog_ext(tag, "Stopped");
} else if (!crashed) {
crashed = true;
Kill();
showLog_ext(tag, "[Error] Program exited accidentally");
dialog_message("ExternalProcess", "Crashed");
}
}
});
showLog_ext(tag, "[Starting] " + env.join(" ") + " " + program + " " + arguments.join(" "));
QProcess::setEnvironment(env); QProcess::setEnvironment(env);
QProcess::start(program, arguments); QProcess::start(program, arguments);
@@ -60,11 +49,71 @@ namespace NekoRay::sys {
void ExternalProcess::Kill() { void ExternalProcess::Kill() {
if (killed) return; if (killed) return;
killed = true; killed = true;
running_list->removeAll(this); if (managed) running_ext.removeAll(this);
if (!crashed) { if (!crashed) {
QProcess::kill(); QProcess::kill();
QProcess::waitForFinished(500); QProcess::waitForFinished(500);
} }
} }
CoreProcess::CoreProcess(const QString &core_path, const QStringList &args) {
ExternalProcess::managed = false;
ExternalProcess::show_log = false;
ExternalProcess::program = core_path;
ExternalProcess::arguments = args;
connect(this, &QProcess::readyReadStandardOutput, this, [&]() {
showLog(readAllStandardOutput().trimmed());
});
connect(this, &QProcess::readyReadStandardError, this, [&]() {
auto log = readAllStandardError().trimmed();
if (show_stderr) {
showLog(log);
return;
}
if (log.contains("token is set")) {
show_stderr = true;
}
});
connect(this, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
if (error == QProcess::ProcessError::FailedToStart) {
failed_to_start = true;
showLog("start nekoray_core errorOccurred: " + errorString() + "\n");
}
});
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
NekoRay::dataStore->core_running = state == QProcess::Running;
if (!dataStore->core_prepare_exit && state == QProcess::NotRunning) {
if (failed_to_start) return; // no retry
showLog("[Error] nekoray_core exited, restarting.\n");
// Restart
auto t = new QTimer;
connect(t, &QTimer::timeout, this, [=] {
Kill();
ExternalProcess::started = false;
Start();
t->deleteLater();
});
t->setSingleShot(true);
t->setInterval(1000);
t->start();
}
});
}
void CoreProcess::Start() {
show_stderr = false;
if (!dataStore->v2ray_asset_dir.isEmpty()) {
setEnvironment(QStringList{
"V2RAY_LOCATION_ASSET=" + dataStore->v2ray_asset_dir
});
}
ExternalProcess::Start();
write((dataStore->core_token + "\n").toUtf8());
}
} }

View File

@@ -12,26 +12,34 @@ namespace NekoRay::sys {
QStringList arguments; QStringList arguments;
QStringList env; QStringList env;
bool managed = true; // running_ext & stateChanged
bool show_log = true; bool show_log = true;
QList<ExternalProcess *> *running_list;
ExternalProcess(const QString &tag, ExternalProcess();
const QString &program,
const QStringList &arguments,
const QStringList &env);
// start & kill is one time // start & kill is one time
void Start(); virtual void Start();
void Kill(); void Kill();
private: protected:
bool started = false; bool started = false;
bool killed = false; bool killed = false;
bool crashed = false; bool crashed = false;
}; };
class CoreProcess : public ExternalProcess {
public:
CoreProcess(const QString &core_path, const QStringList &args);
void Start() override;
private:
bool show_stderr = false;
bool failed_to_start = false;
};
// start & kill change this list // start & kill change this list
inline QList<ExternalProcess *> running_ext; inline QList<ExternalProcess *> running_ext;
} }

View File

@@ -52,10 +52,6 @@
#include <QFileInfo> #include <QFileInfo>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
namespace QtGrpc {
extern bool core_crashed;
}
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) { : QMainWindow(parent), ui(new Ui::MainWindow) {
mainwindow = this; mainwindow = this;
@@ -343,21 +339,14 @@ MainWindow::MainWindow(QWidget *parent)
connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2); }); connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2); });
refresh_status(); refresh_status();
// Start Core // Prepare core
NekoRay::dataStore->core_token = GetRandomString(32); NekoRay::dataStore->core_token = GetRandomString(32);
NekoRay::dataStore->core_port = MkPort(); NekoRay::dataStore->core_port = MkPort();
if (NekoRay::dataStore->core_port <= 0) NekoRay::dataStore->core_port = 19810; if (NekoRay::dataStore->core_port <= 0) NekoRay::dataStore->core_port = 19810;
QString starting_info;
auto core_path = NekoRay::dataStore->core_path; auto core_path = NekoRay::dataStore->core_path;
#ifdef Q_OS_WIN
if (!core_path.endsWith(".exe")) core_path += ".exe";
#endif
if (NekoRay::dataStore->flag_use_appdata) { if (NekoRay::dataStore->flag_use_appdata) {
core_path = QApplication::applicationDirPath() + "/nekoray_core"; core_path = QApplication::applicationDirPath() + "/nekoray_core";
} else if (!QFile(core_path).exists()) {
starting_info = "(not found)";
core_path = "";
} }
QStringList args; QStringList args;
@@ -368,40 +357,9 @@ MainWindow::MainWindow(QWidget *parent)
args.push_back("-debug"); args.push_back("-debug");
#endif #endif
showLog("Starting nekoray core " + starting_info + "\n"); // Start core
core_process = new NekoRay::sys::CoreProcess(core_path, args);
if (!core_path.isEmpty()) { core_process->Start();
core_process = new QProcess;
core_process_show_stderr = false;
connect(core_process, &QProcess::readyReadStandardOutput, this, [&]() {
showLog(core_process->readAllStandardOutput().trimmed());
});
connect(core_process, &QProcess::readyReadStandardError, this, [&]() {
auto log = core_process->readAllStandardError().trimmed();
if (core_process_show_stderr) {
showLog(log);
return;
}
if (log.contains("token is set")) {
core_process_show_stderr = true;
}
});
connect(core_process, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
if (!prepare_exit_core && state == QProcess::NotRunning) {
QtGrpc::core_crashed = true;
showLog("[Error] nekoray_core crashed, please restart the program.");
}
});
if (!NekoRay::dataStore->v2ray_asset_dir.isEmpty()) {
core_process->setEnvironment(QStringList{
"V2RAY_LOCATION_ASSET=" + NekoRay::dataStore->v2ray_asset_dir
});
}
core_process->start(core_path, args);
core_process->write((NekoRay::dataStore->core_token + "\n").toUtf8());
}
setup_grpc(); setup_grpc();
@@ -563,7 +521,7 @@ void MainWindow::on_menu_exit_triggered() {
// //
on_commitDataRequest(); on_commitDataRequest();
// //
prepare_exit_core = true; NekoRay::dataStore->core_prepare_exit = true;
hide(); hide();
ExitNekorayCore(); ExitNekorayCore();
// //

View File

@@ -15,6 +15,7 @@
#include "main/GuiUtils.hpp" #include "main/GuiUtils.hpp"
class QFileSystemWatcher; class QFileSystemWatcher;
namespace NekoRay::sys { class CoreProcess; }
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui {
@@ -120,9 +121,7 @@ private:
QShortcut *shortcut_ctrl_f = new QShortcut(QKeySequence("Ctrl+F"), this); QShortcut *shortcut_ctrl_f = new QShortcut(QKeySequence("Ctrl+F"), this);
QShortcut *shortcut_esc = new QShortcut(QKeySequence("Esc"), this); QShortcut *shortcut_esc = new QShortcut(QKeySequence("Esc"), this);
// //
QProcess *core_process; NekoRay::sys::CoreProcess *core_process;
bool prepare_exit_core = false;
bool core_process_show_stderr = false;
qint64 vpn_pid = 0; qint64 vpn_pid = 0;
QFileSystemWatcher *watcher = nullptr; QFileSystemWatcher *watcher = nullptr;
// //