diff --git a/db/ConfigBuilder.cpp b/db/ConfigBuilder.cpp index 5ea8ad5..62f0855 100644 --- a/db/ConfigBuilder.cpp +++ b/db/ConfigBuilder.cpp @@ -15,8 +15,8 @@ namespace NekoRay { QStringList getAutoBypassExternalProcessPaths(const QSharedPointer &result) { QStringList paths; - for (const auto &ext: result->exts) { - auto path = ext.first.program; + for (const auto &extR: result->extRs) { + auto path = extR->program; if (path.trimmed().isEmpty()) continue; paths << path.replace("\\", "/"); } @@ -553,7 +553,7 @@ namespace NekoRay { auto stream = GetStreamSettings(ent->bean.data()); if (thisExternalStat > 0) { - const auto extR = ent->bean->BuildExternal(ext_mapping_port, ext_socks_port, thisExternalStat); + auto extR = ent->bean->BuildExternal(ext_mapping_port, ext_socks_port, thisExternalStat); if (extR.program.isEmpty()) { status->result->error = QObject::tr("Core not found: %1").arg(ent->bean->DisplayType()); return {}; @@ -562,6 +562,8 @@ namespace NekoRay { status->result->error = extR.error; return {}; } + extR.tag = ent->bean->DisplayType(); + status->result->extRs.emplace_back(std::make_shared(extR)); // SOCKS OUTBOUND if (IS_NEKO_BOX) { @@ -579,14 +581,6 @@ namespace NekoRay { settings["servers"] = servers; outbound["settings"] = settings; } - - // EXTERNAL PROCESS - QSharedPointer extC(new sys::ExternalProcess()); - extC->tag = ent->bean->DisplayType(); - extC->program = extR.program; - extC->arguments = extR.arguments; - extC->env = extR.env; - status->result->exts.emplace_back(extR, extC); } else { const auto coreR = IS_NEKO_BOX ? ent->bean->BuildCoreObjSingBox() : ent->bean->BuildCoreObjV2Ray(); if (coreR.outbound.isEmpty()) { diff --git a/db/ConfigBuilder.hpp b/db/ConfigBuilder.hpp index 1fa35dc..ed411b8 100644 --- a/db/ConfigBuilder.hpp +++ b/db/ConfigBuilder.hpp @@ -13,7 +13,7 @@ namespace NekoRay { QSharedPointer outboundStat; // main QStringList ignoreConnTag; - std::list>> exts; // extR to extC + std::list> extRs; }; class BuildConfigStatus { diff --git a/fmt/AbstractBean.hpp b/fmt/AbstractBean.hpp index 88aec9b..db6784b 100644 --- a/fmt/AbstractBean.hpp +++ b/fmt/AbstractBean.hpp @@ -17,6 +17,9 @@ namespace NekoRay::fmt { QString program; QStringList env; QStringList arguments; + // + QString tag; + // QString error; QString config_export; }; diff --git a/main/NekoRay_Utils.cpp b/main/NekoRay_Utils.cpp index cac07bc..b8d2ab8 100644 --- a/main/NekoRay_Utils.cpp +++ b/main/NekoRay_Utils.cpp @@ -210,7 +210,12 @@ int MessageBoxInfo(const QString &title, const QString &text) { void runOnUiThread(const std::function &callback, QObject *parent) { // any thread auto *timer = new QTimer(); - timer->moveToThread(parent == nullptr ? mainwindow->thread() : parent->thread()); + auto thread = dynamic_cast(parent); + if (thread == nullptr) { + timer->moveToThread(parent == nullptr ? mainwindow->thread() : parent->thread()); + } else { + timer->moveToThread(thread); + } timer->setSingleShot(true); QObject::connect(timer, &QTimer::timeout, [=]() { // main thread diff --git a/main/NekoRay_Utils.hpp b/main/NekoRay_Utils.hpp index 2007b4a..f164ba6 100644 --- a/main/NekoRay_Utils.hpp +++ b/main/NekoRay_Utils.hpp @@ -23,6 +23,11 @@ inline std::function MW_show_log_ext; inline std::function MW_show_log_ext_vt100; inline std::function MW_dialog_message; +// Dispatchers + +class QThread; +inline QThread *DS_cores; + // String #define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a diff --git a/main/main.cpp b/main/main.cpp index 22c6b52..359704d 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "3rdparty/RunGuard.hpp" #include "main/NekoRay.hpp" @@ -121,6 +122,10 @@ int main(int argc, char* argv[]) { delete preQApp; QApplication a(argc, argv); + // dispatchers + DS_cores = new QThread; + DS_cores->start(); + // RunGuard RunGuard guard("nekoray" + wd.absolutePath()); quint64 guard_data_in = GetRandomUint64(); diff --git a/sys/ExternalProcess.cpp b/sys/ExternalProcess.cpp index b19afe7..07f7a38 100644 --- a/sys/ExternalProcess.cpp +++ b/sys/ExternalProcess.cpp @@ -4,8 +4,10 @@ #include #include #include +#include namespace NekoRay::sys { + ExternalProcess::ExternalProcess() : QProcess() { // qDebug() << "[Debug] ExternalProcess()" << this << running_ext; this->env = QProcessEnvironment::systemEnvironment().toStringList(); @@ -21,7 +23,9 @@ namespace NekoRay::sys { if (managed) { connect(this, &QProcess::readyReadStandardOutput, this, [&]() { - MW_show_log_ext_vt100(readAllStandardOutput().trimmed()); + auto log = readAllStandardOutput(); + if (logCounter.fetchAndAddRelaxed(log.count("\n")) > NekoRay::dataStore->max_log_line) return; + MW_show_log_ext_vt100(log); }); connect(this, &QProcess::readyReadStandardError, this, [&]() { MW_show_log_ext_vt100(readAllStandardError().trimmed()); @@ -36,7 +40,7 @@ namespace NekoRay::sys { connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) { if (state == QProcess::NotRunning) { if (killed) { // 用户命令退出 - MW_show_log_ext(tag, "Stopped"); + MW_show_log_ext(tag, "External core stopped"); } else if (!crashed) { // 异常退出 crashed = true; MW_show_log_ext(tag, "[Error] Program exited accidentally: " + errorString()); @@ -45,7 +49,7 @@ namespace NekoRay::sys { } } }); - MW_show_log_ext(tag, "[Starting] " + env.join(" ") + " " + program + " " + arguments.join(" ")); + MW_show_log_ext(tag, "External core starting: " + env.join(" ") + " " + program + " " + arguments.join(" ")); } QProcess::setEnvironment(env); @@ -76,7 +80,9 @@ namespace NekoRay::sys { ExternalProcess::arguments = args; connect(this, &QProcess::readyReadStandardOutput, this, [&]() { - MW_show_log(readAllStandardOutput().trimmed()); + auto log = readAllStandardOutput(); + if (logCounter.fetchAndAddRelaxed(log.count("\n")) > NekoRay::dataStore->max_log_line) return; + MW_show_log(log); }); connect(this, &QProcess::readyReadStandardError, this, [&]() { auto log = readAllStandardError().trimmed(); diff --git a/sys/ExternalProcess.hpp b/sys/ExternalProcess.hpp index 90c701f..225709b 100644 --- a/sys/ExternalProcess.hpp +++ b/sys/ExternalProcess.hpp @@ -40,5 +40,7 @@ namespace NekoRay::sys { }; // 手动管理 - inline QList> running_ext; + inline std::list> running_ext; + + inline QAtomicInt logCounter; } // namespace NekoRay::sys diff --git a/ui/edit/edit_custom.cpp b/ui/edit/edit_custom.cpp index 10de99b..46f0830 100644 --- a/ui/edit/edit_custom.cpp +++ b/ui/edit/edit_custom.cpp @@ -115,15 +115,14 @@ void EditCustom::onStart(QSharedPointer _ent) { MessageBoxInfo(software_name, result->error); return; } - for (const auto &ext: result->exts) { - auto extR = ext.first; - auto command = QStringList{extR.program}; - command += extR.arguments; + for (const auto &extR: result->extRs) { + auto command = QStringList{extR->program}; + command += extR->arguments; auto btn = QMessageBox::information(this, tr("Preview config"), - QString("Command: %1\n\n%2").arg(QStringList2Command(command), extR.config_export), + QString("Command: %1\n\n%2").arg(QStringList2Command(command), extR->config_export), "OK", "Copy", "", 0, 0); if (btn == 1) { - QApplication::clipboard()->setText(extR.config_export); + QApplication::clipboard()->setText(extR->config_export); } } }); diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index dc9ba9e..63fdad8 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -47,7 +47,6 @@ #include QElapsedTimer coreRestartTimer; -// QAtomicInt logCounter; void UI_InitMainWindow() { mainwindow = new MainWindow; @@ -150,11 +149,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi MW_show_log_ext_vt100 = [=](const QString &log) { runOnUiThread([=] { show_log_impl(cleanVT100String(log)); }); }; - // - // auto logCounterTimer = new QTimer(this); - // connect(logCounterTimer, &QTimer::timeout, this, [&] { logCounter.fetchAndStoreRelaxed(0); }); - // logCounterTimer->setInterval(1000); - // logCounterTimer->start(); // table UI ui->proxyListTable->callback_save_order = [=] { @@ -416,10 +410,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi if (NekoRay::dataStore->flag_debug) args.push_back("-debug"); // Start core - core_process = new NekoRay::sys::CoreProcess(core_path, args); - core_process->Start(); - - setup_grpc(); + runOnUiThread( + [=] { + core_process = new NekoRay::sys::CoreProcess(core_path, args); + core_process->Start(); + setup_grpc(); + }, + DS_cores); // Start last if (NekoRay::dataStore->remember_enable) { @@ -436,6 +433,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi connect(qApp, &QGuiApplication::commitDataRequest, this, &MainWindow::on_commitDataRequest); + auto t = new QTimer; + connect(t, &QTimer::timeout, this, [=]() { refresh_status(); }); + t->start(2000); + + t = new QTimer; + connect(t, &QTimer::timeout, this, [&] { NekoRay::sys::logCounter.fetchAndStoreRelaxed(0); }); + t->start(1000); + if (!NekoRay::dataStore->flag_tray) show(); } @@ -1497,7 +1502,6 @@ void MainWindow::show_log_impl(const QString &log) { if (showThisLine) newLines << line; } if (newLines.isEmpty()) return; - // if (logCounter.fetchAndAddRelaxed(newLines.count()) > NekoRay::dataStore->max_log_line) return; FastAppendTextDocument(newLines.join("\n"), qvLogDocument); // qvLogDocument->setPlainText(qvLogDocument->toPlainText() + log); diff --git a/ui/mainwindow.h b/ui/mainwindow.h index d98d1ae..9849561 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -185,7 +185,7 @@ private: // grpc and ... - void setup_grpc(); + static void setup_grpc(); void speedtest_current_group(int mode); diff --git a/ui/mainwindow_grpc.cpp b/ui/mainwindow_grpc.cpp index 1c3f3e1..928c045 100644 --- a/ui/mainwindow_grpc.cpp +++ b/ui/mainwindow_grpc.cpp @@ -14,6 +14,26 @@ #include #include +// ext core + +std::list> CreateExtCFromExtR(const std::list> &extRs, bool start) { + // plz run and start in same thread + std::list> l; + for (const auto &extR: extRs) { + QSharedPointer extC(new NekoRay::sys::ExternalProcess()); + extC->tag = extR->tag; + extC->program = extR->program; + extC->arguments = extR->arguments; + extC->env = extR->env; + l.emplace_back(extC); + // + if (start) extC->Start(); + } + return l; +} + +// grpc + #ifndef NKR_NO_GRPC using namespace NekoRay::rpc; #endif @@ -89,16 +109,13 @@ void MainWindow::speedtest_current_group(int mode) { req.set_url(NekoRay::dataStore->test_url.toStdString()); // - std::list>> exts; + std::list> extCs; if (mode == libcore::TestMode::UrlTest || mode == libcore::FullTest) { auto c = NekoRay::BuildConfig(profile, true, false); // TODO refactor external test - if (!c->exts.empty()) { - exts = c->exts; - for (const auto &ext: exts) { - ext.second->Start(); - } + if (!c->extRs.empty()) { + extCs = CreateExtCFromExtR(c->extRs, true); QThread::msleep(500); } // @@ -117,8 +134,8 @@ void MainWindow::speedtest_current_group(int mode) { bool rpcOK; auto result = defaultClient->Test(&rpcOK, req); - for (const auto &ext: exts) { - ext.second->Kill(); + for (const auto &extC: extCs) { + extC->Kill(); } if (!rpcOK) return; @@ -178,16 +195,6 @@ void MainWindow::speedtest_current() { } else if (latency > 0) { ui->label_running->setText(tr("Test Result") + ": " + QString("%1 ms").arg(latency)); } - // - auto t = new QTimer(this); - connect(t, &QTimer::timeout, this, [=] { - last_test_time = QTime(); - refresh_status(); - t->deleteLater(); - }); - t->setInterval(1000); - t->setSingleShot(true); - t->start(); }); }); #endif @@ -245,10 +252,12 @@ void MainWindow::neko_start(int _id) { NekoRay::traffic::trafficLooper->loop_enabled = true; #endif - for (const auto &ext: result->exts) { - NekoRay::sys::running_ext.push_back(ext.second); - ext.second->Start(); - } + runOnUiThread( + [=] { + auto extCs = CreateExtCFromExtR(result->extRs, true); + NekoRay::sys::running_ext.splice(NekoRay::sys::running_ext.end(), extCs); + }, + DS_cores); NekoRay::dataStore->UpdateStartedId(ent->id); running = ent; @@ -301,10 +310,15 @@ void MainWindow::neko_stop(bool crash, bool sem) { } auto neko_stop_stage2 = [=] { - while (!NekoRay::sys::running_ext.isEmpty()) { - auto extC = NekoRay::sys::running_ext.takeFirst(); - extC->Kill(); - } + runOnUiThread( + [=] { + while (!NekoRay::sys::running_ext.empty()) { + auto extC = NekoRay::sys::running_ext.front(); + extC->Kill(); + NekoRay::sys::running_ext.pop_front(); + } + }, + DS_cores); #ifndef NKR_NO_GRPC NekoRay::traffic::trafficLooper->loop_enabled = false;