From d49c2d4e90acfdeed9ff02a2cf743480d641a575 Mon Sep 17 00:00:00 2001 From: arm64v8a <48624112+arm64v8a@users.noreply.github.com> Date: Fri, 21 Oct 2022 19:44:02 +0900 Subject: [PATCH] feat: improve custom config --- db/ConfigBuilder.cpp | 12 +++++++++--- fmt/Bean2CoreObj_box.cpp | 4 ++++ fmt/Bean2CoreObj_ray.cpp | 10 ++++++++++ fmt/Bean2External.cpp | 8 -------- fmt/CustomBean.hpp | 23 +++++++++++++++++++++- go/cmd/nekobox_core/grpc_box.go | 3 +-- main/NekoRay_Utils.hpp | 1 + translations/zh_CN.ts | 20 +++++++++++-------- ui/edit/dialog_edit_profile.cpp | 24 +++++++++++------------ ui/edit/edit_custom.cpp | 34 +++++++++++++++++++++++++++------ ui/mainwindow.cpp | 15 +++++++-------- 11 files changed, 105 insertions(+), 49 deletions(-) diff --git a/db/ConfigBuilder.cpp b/db/ConfigBuilder.cpp index 71a8d11..9719501 100644 --- a/db/ConfigBuilder.cpp +++ b/db/ConfigBuilder.cpp @@ -420,9 +420,13 @@ namespace NekoRay { if (ent->bean->NeedExternal()) { auto ext_socks_port = MkPort(); extR = ent->bean->BuildExternal(mapping_port, ext_socks_port); + if (extR.program.isEmpty()) { + status->result->error = QObject::tr("Core not found: %1").arg(ent->bean->DisplayType()); + return {}; + } if (!extR.error.isEmpty()) { // rejected status->result->error = extR.error; - return ""; + return {}; } // SOCKS OUTBOUND @@ -528,7 +532,9 @@ namespace NekoRay { status->result = result; // Log - result->coreConfig["log"] = QJsonObject{{"level", dataStore->log_level}}; + auto level = dataStore->log_level; + level = level.replace("warning", "warn"); + result->coreConfig["log"] = QJsonObject{{"level", level}}; // Inbounds @@ -723,7 +729,7 @@ namespace NekoRay { }); // api - if (dataStore->traffic_loop_interval > 0) { + if (!forTest && dataStore->traffic_loop_interval > 0) { result->coreConfig.insert("experimental", QJsonObject{ {"v2ray_api", QJsonObject{ {"listen", "127.0.0.1:" + Int2String(dataStore->inbound_socks_port + 10)}, diff --git a/fmt/Bean2CoreObj_box.cpp b/fmt/Bean2CoreObj_box.cpp index 526684f..39450cf 100644 --- a/fmt/Bean2CoreObj_box.cpp +++ b/fmt/Bean2CoreObj_box.cpp @@ -144,6 +144,10 @@ namespace NekoRay::fmt { result.outbound = outbound; } + if (core == "internal") { + result.outbound = QString2QJsonObject(config_simple); + } + return result; } } diff --git a/fmt/Bean2CoreObj_ray.cpp b/fmt/Bean2CoreObj_ray.cpp index b371972..47bc2dd 100644 --- a/fmt/Bean2CoreObj_ray.cpp +++ b/fmt/Bean2CoreObj_ray.cpp @@ -193,4 +193,14 @@ namespace NekoRay::fmt { result.outbound = outbound; return result; } + + CoreObjOutboundBuildResult CustomBean::BuildCoreObjV2Ray() { + CoreObjOutboundBuildResult result; + + if (core == "internal") { + result.outbound = QString2QJsonObject(config_simple); + } + + return result; + } } \ No newline at end of file diff --git a/fmt/Bean2External.cpp b/fmt/Bean2External.cpp index d943ee1..aaf0d53 100644 --- a/fmt/Bean2External.cpp +++ b/fmt/Bean2External.cpp @@ -21,10 +21,6 @@ auto TempFile = QFileInfo(f).absoluteFilePath(); namespace NekoRay::fmt { ExternalBuildResult NaiveBean::BuildExternal(int mapping_port, int socks_port) { ExternalBuildResult result{dataStore->extraCore->Get("naive")}; - if (result.program.isEmpty()) { - result.error = QObject::tr("Core not found: %1").arg(DisplayType()); - return result; - } auto is_export = mapping_port == 114514; auto domain_address = sni.isEmpty() ? serverAddress : sni; @@ -53,10 +49,6 @@ namespace NekoRay::fmt { ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port) { ExternalBuildResult result{dataStore->extraCore->Get(core)}; - if (result.program.isEmpty()) { - result.error = QObject::tr("Core not found: %1").arg(DisplayType()); - return result; - } result.arguments = command; // TODO split? diff --git a/fmt/CustomBean.hpp b/fmt/CustomBean.hpp index ac11753..b721ef7 100644 --- a/fmt/CustomBean.hpp +++ b/fmt/CustomBean.hpp @@ -17,11 +17,30 @@ namespace NekoRay::fmt { _add(new configItem("cs", &config_simple, itemType::string)); }; - QString DisplayType() override { return core; }; + QString DisplayType() override { + if (core == "internal") { + auto obj = QString2QJsonObject(config_simple); + return obj[IS_NEKO_BOX ? "type" : "protocol"].toString(); + } + return core; + }; QString DisplayCoreType() override { return NeedExternal() ? core : software_core_name; }; + QString DisplayAddress() override { + if (core == "internal") { + auto obj = QString2QJsonObject(config_simple); + if (IS_NEKO_BOX) { + return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt()); + } else { + return {}; + } + } + return AbstractBean::DisplayAddress(); + }; + bool NeedExternal() override { + if (core == "internal") return false; if (IS_NEKO_BOX && core == "hysteria") return false; return true; }; @@ -29,5 +48,7 @@ namespace NekoRay::fmt { ExternalBuildResult BuildExternal(int mapping_port, int socks_port) override; CoreObjOutboundBuildResult BuildCoreObjSingBox() override; + + CoreObjOutboundBuildResult BuildCoreObjV2Ray() override; }; } \ No newline at end of file diff --git a/go/cmd/nekobox_core/grpc_box.go b/go/cmd/nekobox_core/grpc_box.go index 20fdb39..98cac50 100644 --- a/go/cmd/nekobox_core/grpc_box.go +++ b/go/cmd/nekobox_core/grpc_box.go @@ -104,14 +104,13 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, var i *box.Box if in.Config != nil { // Test instance - instance, instance_cancel, err = box_main.Create([]byte(in.Config.CoreConfig), true) + i, instance_cancel, err = box_main.Create([]byte(in.Config.CoreConfig), true) if instance_cancel != nil { defer instance_cancel() } if err != nil { return } - i = instance } else { // Test running instance i = instance diff --git a/main/NekoRay_Utils.hpp b/main/NekoRay_Utils.hpp index c81fe65..aa86662 100644 --- a/main/NekoRay_Utils.hpp +++ b/main/NekoRay_Utils.hpp @@ -142,6 +142,7 @@ inline QString WrapIPV6Host(QString &str) { } inline QString DisplayAddress(QString serverAddress, int serverPort) { + if (serverAddress.isEmpty() && serverPort == 0) return {}; return WrapIPV6Host(serverAddress) + ":" + Int2String(serverPort); }; diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index e1b43da..fd55489 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -189,7 +189,7 @@ Switching the core to %1, click "Yes" to complete the switch and the program will restart. This feature may be unstable, please do not switch frequently. - 将核心切换到 %1,点击 "是 "完成切换,程序将重新启动。此功能可能不稳定,请不要频繁切换。 + 将核心切换到 %1。点击 "是" 完成切换,程序将重新启动。此功能可能不稳定,请不要频繁切换。 @@ -337,10 +337,6 @@ Host 主机(Host) - - Custom - 自定义 - Packet Encoding 包编码 @@ -350,8 +346,12 @@ 设置 - None - + Custom (Extra Core) + 自定义 (其他核心) + + + Custom (%1) + 自定义 (%1) @@ -587,6 +587,10 @@ Json Editor JSON 编辑器 + + Please pick a core. + 请选择一个核心。 + EditNaive @@ -1254,7 +1258,7 @@ Direct: %2 Core not found: %1 - 找不到 %1 核心 + 找不到 "%1" 核心。请前往设置 Update diff --git a/ui/edit/dialog_edit_profile.cpp b/ui/edit/dialog_edit_profile.cpp index 3123f59..84151df 100644 --- a/ui/edit/dialog_edit_profile.cpp +++ b/ui/edit/dialog_edit_profile.cpp @@ -10,7 +10,6 @@ #include "ui/edit/edit_custom.h" #include "fmt/includes.h" -#include "fmt/Preset.hpp" #include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp" #include "main/GuiUtils.hpp" @@ -101,7 +100,8 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, LOAD_TYPE("vless"); LOAD_TYPE("naive"); ui->type->addItem("Hysteria", "hysteria"); - ui->type->addItem(tr("Custom"), "custom"); + ui->type->addItem(tr("Custom (%1)").arg(software_core_name), "internal"); + ui->type->addItem(tr("Custom (Extra Core)"), "custom"); LOAD_TYPE("chain"); // type changed @@ -124,6 +124,7 @@ DialogEditProfile::~DialogEditProfile() { } void DialogEditProfile::typeSelected(const QString &newType) { + QString customType; type = newType; bool validType = true; @@ -151,15 +152,12 @@ void DialogEditProfile::typeSelected(const QString &newType) { auto _innerWidget = new EditNaive(this); innerWidget = _innerWidget; innerEditor = _innerWidget; - } else if (type == "custom" || type == "hysteria") { + } else if (type == "custom" || type == "internal" || type == "hysteria") { auto _innerWidget = new EditCustom(this); innerWidget = _innerWidget; innerEditor = _innerWidget; - if (type == "hysteria" || (!newEnt && ent->CustomBean()->core == "hysteria")) { - _innerWidget->preset_core = type; - _innerWidget->preset_command = Preset::Hysteria::command; - _innerWidget->preset_config = Preset::Hysteria::config; - } + customType = newEnt ? type : ent->CustomBean()->core; + if (customType != "custom") _innerWidget->preset_core = customType; type = "custom"; } else { validType = false; @@ -176,11 +174,11 @@ void DialogEditProfile::typeSelected(const QString &newType) { } // hide some widget - auto notChain = type != "chain"; - ui->address->setVisible(notChain); - ui->address_l->setVisible(notChain); - ui->port->setVisible(notChain); - ui->port_l->setVisible(notChain); + auto showAddressPort = type != "chain" && customType != "internal"; + ui->address->setVisible(showAddressPort); + ui->address_l->setVisible(showAddressPort); + ui->port->setVisible(showAddressPort); + ui->port_l->setVisible(showAddressPort); // 右边 Outbound: settings auto stream = GetStreamSettings(ent->bean.data()); diff --git a/ui/edit/edit_custom.cpp b/ui/edit/edit_custom.cpp index 6c94d30..eea61f3 100644 --- a/ui/edit/edit_custom.cpp +++ b/ui/edit/edit_custom.cpp @@ -3,6 +3,7 @@ #include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp" #include "fmt/CustomBean.hpp" +#include "fmt/Preset.hpp" #include "ui/edit/gen_hysteria.h" EditCustom::EditCustom(QWidget *parent) : @@ -15,12 +16,6 @@ EditCustom::EditCustom(QWidget *parent) : " host: your-domain.com\n" " sni: your-domain.com\n" ); - if (IS_NEKO_BOX) { - ui->core->hide(); - ui->core_l->hide(); - ui->command->hide(); - ui->command_l->hide(); - } } EditCustom::~EditCustom() { @@ -34,13 +29,27 @@ void EditCustom::onStart(QSharedPointer _ent) { // load known core auto core_map = QString2QJsonObject(NekoRay::dataStore->extraCore->core_map); for (const auto &key: core_map.keys()) { + if (key == "naive" || key == "hysteria") continue; ui->core->addItem(key); } + if (preset_core == "hysteria") { + preset_command = Preset::Hysteria::command; + preset_config = Preset::Hysteria::config; + ui->config_simple->setPlaceholderText(""); + } else if (preset_core == "internal") { + preset_command = preset_config = ""; + ui->config_simple->setPlaceholderText("{\n" + " \"type\": \"socks\",\n" + " // ...\n" + "}"); + } + // load core ui P_LOAD_COMBO(core) ui->command->setText(bean->command.join(" ")); P_LOAD_STRING(config_simple) + // custom external if (!bean->core.isEmpty()) { ui->core->setDisabled(true); } else if (!preset_core.isEmpty()) { @@ -51,6 +60,14 @@ void EditCustom::onStart(QSharedPointer _ent) { ui->config_simple->setText(preset_config); } + // custom internal + if (preset_core == "internal") { + ui->core->hide(); + ui->core_l->hide(); + ui->command->hide(); + ui->command_l->hide(); + } + // Generators if (bean->core == "hysteria") { ui->generator->setVisible(true); @@ -71,6 +88,11 @@ bool EditCustom::onEnd() { bean->command = ui->command->text().split(" "); P_SAVE_STRING_QTEXTEDIT(config_simple) + if (bean->core.isEmpty()) { + MessageBoxWarning(software_name, tr("Please pick a core.")); + return false; + } + return true; } diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 69b3532..6f899f5 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -346,14 +346,18 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2); }); // connect(ui->menu_share_item, &QMenu::aboutToShow, this, [=] { - auto name = software_core_name; + QString name; auto selected = get_now_selected(); if (!selected.isEmpty()) { auto ent = selected.first(); name = ent->bean->DisplayCoreType(); } + ui->menu_export_config->setVisible(name == software_core_name); ui->menu_export_config->setText(tr("Export %1 config").arg(name)); }); + connect(ui->menugroup, &QMenu::aboutToShow, this, [=] { + ui->menu_full_test->setVisible(!IS_NEKO_BOX); + }); refresh_status(); // Prepare core @@ -1014,13 +1018,8 @@ void MainWindow::on_menu_export_config_triggered() { auto ent = ents.first(); QString config_core; - if (ent->bean->NeedExternal()) { - auto result = ent->bean->BuildExternal(114514, MkPort()); - config_core = result.config_export.replace("127.0.0.1:114514", ent->bean->DisplayAddress()); - } else { - auto result = NekoRay::BuildConfig(ent, false); - config_core = QJsonObject2QString(result->coreConfig, true); - } + auto result = NekoRay::BuildConfig(ent, false); + config_core = QJsonObject2QString(result->coreConfig, true); QApplication::clipboard()->setText(config_core); MessageBoxWarning(tr("Config copied"), config_core);