mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 12:34:37 +03:00
fix: core log thread
This commit is contained in:
@@ -15,8 +15,8 @@ namespace NekoRay {
|
|||||||
|
|
||||||
QStringList getAutoBypassExternalProcessPaths(const QSharedPointer<BuildConfigResult> &result) {
|
QStringList getAutoBypassExternalProcessPaths(const QSharedPointer<BuildConfigResult> &result) {
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
for (const auto &ext: result->exts) {
|
for (const auto &extR: result->extRs) {
|
||||||
auto path = ext.first.program;
|
auto path = extR->program;
|
||||||
if (path.trimmed().isEmpty()) continue;
|
if (path.trimmed().isEmpty()) continue;
|
||||||
paths << path.replace("\\", "/");
|
paths << path.replace("\\", "/");
|
||||||
}
|
}
|
||||||
@@ -553,7 +553,7 @@ namespace NekoRay {
|
|||||||
auto stream = GetStreamSettings(ent->bean.data());
|
auto stream = GetStreamSettings(ent->bean.data());
|
||||||
|
|
||||||
if (thisExternalStat > 0) {
|
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()) {
|
if (extR.program.isEmpty()) {
|
||||||
status->result->error = QObject::tr("Core not found: %1").arg(ent->bean->DisplayType());
|
status->result->error = QObject::tr("Core not found: %1").arg(ent->bean->DisplayType());
|
||||||
return {};
|
return {};
|
||||||
@@ -562,6 +562,8 @@ namespace NekoRay {
|
|||||||
status->result->error = extR.error;
|
status->result->error = extR.error;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
extR.tag = ent->bean->DisplayType();
|
||||||
|
status->result->extRs.emplace_back(std::make_shared<fmt::ExternalBuildResult>(extR));
|
||||||
|
|
||||||
// SOCKS OUTBOUND
|
// SOCKS OUTBOUND
|
||||||
if (IS_NEKO_BOX) {
|
if (IS_NEKO_BOX) {
|
||||||
@@ -579,14 +581,6 @@ namespace NekoRay {
|
|||||||
settings["servers"] = servers;
|
settings["servers"] = servers;
|
||||||
outbound["settings"] = settings;
|
outbound["settings"] = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTERNAL PROCESS
|
|
||||||
QSharedPointer<sys::ExternalProcess> 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 {
|
} else {
|
||||||
const auto coreR = IS_NEKO_BOX ? ent->bean->BuildCoreObjSingBox() : ent->bean->BuildCoreObjV2Ray();
|
const auto coreR = IS_NEKO_BOX ? ent->bean->BuildCoreObjSingBox() : ent->bean->BuildCoreObjV2Ray();
|
||||||
if (coreR.outbound.isEmpty()) {
|
if (coreR.outbound.isEmpty()) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace NekoRay {
|
|||||||
QSharedPointer<traffic::TrafficData> outboundStat; // main
|
QSharedPointer<traffic::TrafficData> outboundStat; // main
|
||||||
QStringList ignoreConnTag;
|
QStringList ignoreConnTag;
|
||||||
|
|
||||||
std::list<std::pair<fmt::ExternalBuildResult, QSharedPointer<sys::ExternalProcess>>> exts; // extR to extC
|
std::list<std::shared_ptr<NekoRay::fmt::ExternalBuildResult>> extRs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BuildConfigStatus {
|
class BuildConfigStatus {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ namespace NekoRay::fmt {
|
|||||||
QString program;
|
QString program;
|
||||||
QStringList env;
|
QStringList env;
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
|
//
|
||||||
|
QString tag;
|
||||||
|
//
|
||||||
QString error;
|
QString error;
|
||||||
QString config_export;
|
QString config_export;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -210,7 +210,12 @@ int MessageBoxInfo(const QString &title, const QString &text) {
|
|||||||
void runOnUiThread(const std::function<void()> &callback, QObject *parent) {
|
void runOnUiThread(const std::function<void()> &callback, QObject *parent) {
|
||||||
// any thread
|
// any thread
|
||||||
auto *timer = new QTimer();
|
auto *timer = new QTimer();
|
||||||
timer->moveToThread(parent == nullptr ? mainwindow->thread() : parent->thread());
|
auto thread = dynamic_cast<QThread *>(parent);
|
||||||
|
if (thread == nullptr) {
|
||||||
|
timer->moveToThread(parent == nullptr ? mainwindow->thread() : parent->thread());
|
||||||
|
} else {
|
||||||
|
timer->moveToThread(thread);
|
||||||
|
}
|
||||||
timer->setSingleShot(true);
|
timer->setSingleShot(true);
|
||||||
QObject::connect(timer, &QTimer::timeout, [=]() {
|
QObject::connect(timer, &QTimer::timeout, [=]() {
|
||||||
// main thread
|
// main thread
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ inline std::function<void(QString, QString)> MW_show_log_ext;
|
|||||||
inline std::function<void(QString)> MW_show_log_ext_vt100;
|
inline std::function<void(QString)> MW_show_log_ext_vt100;
|
||||||
inline std::function<void(QString, QString)> MW_dialog_message;
|
inline std::function<void(QString, QString)> MW_dialog_message;
|
||||||
|
|
||||||
|
// Dispatchers
|
||||||
|
|
||||||
|
class QThread;
|
||||||
|
inline QThread *DS_cores;
|
||||||
|
|
||||||
// String
|
// String
|
||||||
|
|
||||||
#define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a
|
#define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "3rdparty/RunGuard.hpp"
|
#include "3rdparty/RunGuard.hpp"
|
||||||
#include "main/NekoRay.hpp"
|
#include "main/NekoRay.hpp"
|
||||||
@@ -121,6 +122,10 @@ int main(int argc, char* argv[]) {
|
|||||||
delete preQApp;
|
delete preQApp;
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
|
// dispatchers
|
||||||
|
DS_cores = new QThread;
|
||||||
|
DS_cores->start();
|
||||||
|
|
||||||
// RunGuard
|
// RunGuard
|
||||||
RunGuard guard("nekoray" + wd.absolutePath());
|
RunGuard guard("nekoray" + wd.absolutePath());
|
||||||
quint64 guard_data_in = GetRandomUint64();
|
quint64 guard_data_in = GetRandomUint64();
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
namespace NekoRay::sys {
|
namespace NekoRay::sys {
|
||||||
|
|
||||||
ExternalProcess::ExternalProcess() : QProcess() {
|
ExternalProcess::ExternalProcess() : QProcess() {
|
||||||
// qDebug() << "[Debug] ExternalProcess()" << this << running_ext;
|
// qDebug() << "[Debug] ExternalProcess()" << this << running_ext;
|
||||||
this->env = QProcessEnvironment::systemEnvironment().toStringList();
|
this->env = QProcessEnvironment::systemEnvironment().toStringList();
|
||||||
@@ -21,7 +23,9 @@ namespace NekoRay::sys {
|
|||||||
|
|
||||||
if (managed) {
|
if (managed) {
|
||||||
connect(this, &QProcess::readyReadStandardOutput, this, [&]() {
|
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, [&]() {
|
connect(this, &QProcess::readyReadStandardError, this, [&]() {
|
||||||
MW_show_log_ext_vt100(readAllStandardError().trimmed());
|
MW_show_log_ext_vt100(readAllStandardError().trimmed());
|
||||||
@@ -36,7 +40,7 @@ namespace NekoRay::sys {
|
|||||||
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
|
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
|
||||||
if (state == QProcess::NotRunning) {
|
if (state == QProcess::NotRunning) {
|
||||||
if (killed) { // 用户命令退出
|
if (killed) { // 用户命令退出
|
||||||
MW_show_log_ext(tag, "Stopped");
|
MW_show_log_ext(tag, "External core stopped");
|
||||||
} else if (!crashed) { // 异常退出
|
} else if (!crashed) { // 异常退出
|
||||||
crashed = true;
|
crashed = true;
|
||||||
MW_show_log_ext(tag, "[Error] Program exited accidentally: " + errorString());
|
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);
|
QProcess::setEnvironment(env);
|
||||||
@@ -76,7 +80,9 @@ namespace NekoRay::sys {
|
|||||||
ExternalProcess::arguments = args;
|
ExternalProcess::arguments = args;
|
||||||
|
|
||||||
connect(this, &QProcess::readyReadStandardOutput, this, [&]() {
|
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, [&]() {
|
connect(this, &QProcess::readyReadStandardError, this, [&]() {
|
||||||
auto log = readAllStandardError().trimmed();
|
auto log = readAllStandardError().trimmed();
|
||||||
|
|||||||
@@ -40,5 +40,7 @@ namespace NekoRay::sys {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 手动管理
|
// 手动管理
|
||||||
inline QList<QSharedPointer<ExternalProcess>> running_ext;
|
inline std::list<QSharedPointer<ExternalProcess>> running_ext;
|
||||||
|
|
||||||
|
inline QAtomicInt logCounter;
|
||||||
} // namespace NekoRay::sys
|
} // namespace NekoRay::sys
|
||||||
|
|||||||
@@ -115,15 +115,14 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
|||||||
MessageBoxInfo(software_name, result->error);
|
MessageBoxInfo(software_name, result->error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto &ext: result->exts) {
|
for (const auto &extR: result->extRs) {
|
||||||
auto extR = ext.first;
|
auto command = QStringList{extR->program};
|
||||||
auto command = QStringList{extR.program};
|
command += extR->arguments;
|
||||||
command += extR.arguments;
|
|
||||||
auto btn = QMessageBox::information(this, tr("Preview config"),
|
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);
|
"OK", "Copy", "", 0, 0);
|
||||||
if (btn == 1) {
|
if (btn == 1) {
|
||||||
QApplication::clipboard()->setText(extR.config_export);
|
QApplication::clipboard()->setText(extR->config_export);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,7 +47,6 @@
|
|||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
QElapsedTimer coreRestartTimer;
|
QElapsedTimer coreRestartTimer;
|
||||||
// QAtomicInt logCounter;
|
|
||||||
|
|
||||||
void UI_InitMainWindow() {
|
void UI_InitMainWindow() {
|
||||||
mainwindow = new MainWindow;
|
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) {
|
MW_show_log_ext_vt100 = [=](const QString &log) {
|
||||||
runOnUiThread([=] { show_log_impl(cleanVT100String(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
|
// table UI
|
||||||
ui->proxyListTable->callback_save_order = [=] {
|
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");
|
if (NekoRay::dataStore->flag_debug) args.push_back("-debug");
|
||||||
|
|
||||||
// Start core
|
// Start core
|
||||||
core_process = new NekoRay::sys::CoreProcess(core_path, args);
|
runOnUiThread(
|
||||||
core_process->Start();
|
[=] {
|
||||||
|
core_process = new NekoRay::sys::CoreProcess(core_path, args);
|
||||||
setup_grpc();
|
core_process->Start();
|
||||||
|
setup_grpc();
|
||||||
|
},
|
||||||
|
DS_cores);
|
||||||
|
|
||||||
// Start last
|
// Start last
|
||||||
if (NekoRay::dataStore->remember_enable) {
|
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);
|
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();
|
if (!NekoRay::dataStore->flag_tray) show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1497,7 +1502,6 @@ void MainWindow::show_log_impl(const QString &log) {
|
|||||||
if (showThisLine) newLines << line;
|
if (showThisLine) newLines << line;
|
||||||
}
|
}
|
||||||
if (newLines.isEmpty()) return;
|
if (newLines.isEmpty()) return;
|
||||||
// if (logCounter.fetchAndAddRelaxed(newLines.count()) > NekoRay::dataStore->max_log_line) return;
|
|
||||||
|
|
||||||
FastAppendTextDocument(newLines.join("\n"), qvLogDocument);
|
FastAppendTextDocument(newLines.join("\n"), qvLogDocument);
|
||||||
// qvLogDocument->setPlainText(qvLogDocument->toPlainText() + log);
|
// qvLogDocument->setPlainText(qvLogDocument->toPlainText() + log);
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ private:
|
|||||||
|
|
||||||
// grpc and ...
|
// grpc and ...
|
||||||
|
|
||||||
void setup_grpc();
|
static void setup_grpc();
|
||||||
|
|
||||||
void speedtest_current_group(int mode);
|
void speedtest_current_group(int mode);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,26 @@
|
|||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
// ext core
|
||||||
|
|
||||||
|
std::list<QSharedPointer<NekoRay::sys::ExternalProcess>> CreateExtCFromExtR(const std::list<std::shared_ptr<NekoRay::fmt::ExternalBuildResult>> &extRs, bool start) {
|
||||||
|
// plz run and start in same thread
|
||||||
|
std::list<QSharedPointer<NekoRay::sys::ExternalProcess>> l;
|
||||||
|
for (const auto &extR: extRs) {
|
||||||
|
QSharedPointer<NekoRay::sys::ExternalProcess> 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
|
#ifndef NKR_NO_GRPC
|
||||||
using namespace NekoRay::rpc;
|
using namespace NekoRay::rpc;
|
||||||
#endif
|
#endif
|
||||||
@@ -89,16 +109,13 @@ void MainWindow::speedtest_current_group(int mode) {
|
|||||||
req.set_url(NekoRay::dataStore->test_url.toStdString());
|
req.set_url(NekoRay::dataStore->test_url.toStdString());
|
||||||
|
|
||||||
//
|
//
|
||||||
std::list<std::pair<NekoRay::fmt::ExternalBuildResult, QSharedPointer<NekoRay::sys::ExternalProcess>>> exts;
|
std::list<QSharedPointer<NekoRay::sys::ExternalProcess>> extCs;
|
||||||
|
|
||||||
if (mode == libcore::TestMode::UrlTest || mode == libcore::FullTest) {
|
if (mode == libcore::TestMode::UrlTest || mode == libcore::FullTest) {
|
||||||
auto c = NekoRay::BuildConfig(profile, true, false);
|
auto c = NekoRay::BuildConfig(profile, true, false);
|
||||||
// TODO refactor external test
|
// TODO refactor external test
|
||||||
if (!c->exts.empty()) {
|
if (!c->extRs.empty()) {
|
||||||
exts = c->exts;
|
extCs = CreateExtCFromExtR(c->extRs, true);
|
||||||
for (const auto &ext: exts) {
|
|
||||||
ext.second->Start();
|
|
||||||
}
|
|
||||||
QThread::msleep(500);
|
QThread::msleep(500);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -117,8 +134,8 @@ void MainWindow::speedtest_current_group(int mode) {
|
|||||||
|
|
||||||
bool rpcOK;
|
bool rpcOK;
|
||||||
auto result = defaultClient->Test(&rpcOK, req);
|
auto result = defaultClient->Test(&rpcOK, req);
|
||||||
for (const auto &ext: exts) {
|
for (const auto &extC: extCs) {
|
||||||
ext.second->Kill();
|
extC->Kill();
|
||||||
}
|
}
|
||||||
if (!rpcOK) return;
|
if (!rpcOK) return;
|
||||||
|
|
||||||
@@ -178,16 +195,6 @@ void MainWindow::speedtest_current() {
|
|||||||
} else if (latency > 0) {
|
} else if (latency > 0) {
|
||||||
ui->label_running->setText(tr("Test Result") + ": " + QString("%1 ms").arg(latency));
|
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
|
#endif
|
||||||
@@ -245,10 +252,12 @@ void MainWindow::neko_start(int _id) {
|
|||||||
NekoRay::traffic::trafficLooper->loop_enabled = true;
|
NekoRay::traffic::trafficLooper->loop_enabled = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (const auto &ext: result->exts) {
|
runOnUiThread(
|
||||||
NekoRay::sys::running_ext.push_back(ext.second);
|
[=] {
|
||||||
ext.second->Start();
|
auto extCs = CreateExtCFromExtR(result->extRs, true);
|
||||||
}
|
NekoRay::sys::running_ext.splice(NekoRay::sys::running_ext.end(), extCs);
|
||||||
|
},
|
||||||
|
DS_cores);
|
||||||
|
|
||||||
NekoRay::dataStore->UpdateStartedId(ent->id);
|
NekoRay::dataStore->UpdateStartedId(ent->id);
|
||||||
running = ent;
|
running = ent;
|
||||||
@@ -301,10 +310,15 @@ void MainWindow::neko_stop(bool crash, bool sem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto neko_stop_stage2 = [=] {
|
auto neko_stop_stage2 = [=] {
|
||||||
while (!NekoRay::sys::running_ext.isEmpty()) {
|
runOnUiThread(
|
||||||
auto extC = NekoRay::sys::running_ext.takeFirst();
|
[=] {
|
||||||
extC->Kill();
|
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
|
#ifndef NKR_NO_GRPC
|
||||||
NekoRay::traffic::trafficLooper->loop_enabled = false;
|
NekoRay::traffic::trafficLooper->loop_enabled = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user