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);