mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 12:34:37 +03:00
feat: improve custom config
This commit is contained in:
@@ -420,9 +420,13 @@ namespace NekoRay {
|
|||||||
if (ent->bean->NeedExternal()) {
|
if (ent->bean->NeedExternal()) {
|
||||||
auto ext_socks_port = MkPort();
|
auto ext_socks_port = MkPort();
|
||||||
extR = ent->bean->BuildExternal(mapping_port, ext_socks_port);
|
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
|
if (!extR.error.isEmpty()) { // rejected
|
||||||
status->result->error = extR.error;
|
status->result->error = extR.error;
|
||||||
return "";
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOCKS OUTBOUND
|
// SOCKS OUTBOUND
|
||||||
@@ -528,7 +532,9 @@ namespace NekoRay {
|
|||||||
status->result = result;
|
status->result = result;
|
||||||
|
|
||||||
// Log
|
// 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
|
// Inbounds
|
||||||
|
|
||||||
@@ -723,7 +729,7 @@ namespace NekoRay {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// api
|
// api
|
||||||
if (dataStore->traffic_loop_interval > 0) {
|
if (!forTest && dataStore->traffic_loop_interval > 0) {
|
||||||
result->coreConfig.insert("experimental", QJsonObject{
|
result->coreConfig.insert("experimental", QJsonObject{
|
||||||
{"v2ray_api", QJsonObject{
|
{"v2ray_api", QJsonObject{
|
||||||
{"listen", "127.0.0.1:" + Int2String(dataStore->inbound_socks_port + 10)},
|
{"listen", "127.0.0.1:" + Int2String(dataStore->inbound_socks_port + 10)},
|
||||||
|
|||||||
@@ -144,6 +144,10 @@ namespace NekoRay::fmt {
|
|||||||
result.outbound = outbound;
|
result.outbound = outbound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (core == "internal") {
|
||||||
|
result.outbound = QString2QJsonObject(config_simple);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,4 +193,14 @@ namespace NekoRay::fmt {
|
|||||||
result.outbound = outbound;
|
result.outbound = outbound;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoreObjOutboundBuildResult CustomBean::BuildCoreObjV2Ray() {
|
||||||
|
CoreObjOutboundBuildResult result;
|
||||||
|
|
||||||
|
if (core == "internal") {
|
||||||
|
result.outbound = QString2QJsonObject(config_simple);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -21,10 +21,6 @@ auto TempFile = QFileInfo(f).absoluteFilePath();
|
|||||||
namespace NekoRay::fmt {
|
namespace NekoRay::fmt {
|
||||||
ExternalBuildResult NaiveBean::BuildExternal(int mapping_port, int socks_port) {
|
ExternalBuildResult NaiveBean::BuildExternal(int mapping_port, int socks_port) {
|
||||||
ExternalBuildResult result{dataStore->extraCore->Get("naive")};
|
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 is_export = mapping_port == 114514;
|
||||||
auto domain_address = sni.isEmpty() ? serverAddress : sni;
|
auto domain_address = sni.isEmpty() ? serverAddress : sni;
|
||||||
@@ -53,10 +49,6 @@ namespace NekoRay::fmt {
|
|||||||
|
|
||||||
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port) {
|
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port) {
|
||||||
ExternalBuildResult result{dataStore->extraCore->Get(core)};
|
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?
|
result.arguments = command; // TODO split?
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,30 @@ namespace NekoRay::fmt {
|
|||||||
_add(new configItem("cs", &config_simple, itemType::string));
|
_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 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 {
|
bool NeedExternal() override {
|
||||||
|
if (core == "internal") return false;
|
||||||
if (IS_NEKO_BOX && core == "hysteria") return false;
|
if (IS_NEKO_BOX && core == "hysteria") return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -29,5 +48,7 @@ namespace NekoRay::fmt {
|
|||||||
ExternalBuildResult BuildExternal(int mapping_port, int socks_port) override;
|
ExternalBuildResult BuildExternal(int mapping_port, int socks_port) override;
|
||||||
|
|
||||||
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
|
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
|
||||||
|
|
||||||
|
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -104,14 +104,13 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp,
|
|||||||
var i *box.Box
|
var i *box.Box
|
||||||
if in.Config != nil {
|
if in.Config != nil {
|
||||||
// Test instance
|
// 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 {
|
if instance_cancel != nil {
|
||||||
defer instance_cancel()
|
defer instance_cancel()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i = instance
|
|
||||||
} else {
|
} else {
|
||||||
// Test running instance
|
// Test running instance
|
||||||
i = instance
|
i = instance
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ inline QString WrapIPV6Host(QString &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline QString DisplayAddress(QString serverAddress, int serverPort) {
|
inline QString DisplayAddress(QString serverAddress, int serverPort) {
|
||||||
|
if (serverAddress.isEmpty() && serverPort == 0) return {};
|
||||||
return WrapIPV6Host(serverAddress) + ":" + Int2String(serverPort);
|
return WrapIPV6Host(serverAddress) + ":" + Int2String(serverPort);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>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.</source>
|
<source>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.</source>
|
||||||
<translation>将核心切换到 %1,点击 "是 "完成切换,程序将重新启动。此功能可能不稳定,请不要频繁切换。</translation>
|
<translation>将核心切换到 %1。点击 "是" 完成切换,程序将重新启动。此功能可能不稳定,请不要频繁切换。</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -337,10 +337,6 @@
|
|||||||
<source>Host</source>
|
<source>Host</source>
|
||||||
<translation>主机(Host)</translation>
|
<translation>主机(Host)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Custom</source>
|
|
||||||
<translation>自定义</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Packet Encoding</source>
|
<source>Packet Encoding</source>
|
||||||
<translation>包编码</translation>
|
<translation>包编码</translation>
|
||||||
@@ -350,8 +346,12 @@
|
|||||||
<translation>设置</translation>
|
<translation>设置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>None</source>
|
<source>Custom (Extra Core)</source>
|
||||||
<translation type="obsolete">无</translation>
|
<translation>自定义 (其他核心)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Custom (%1)</source>
|
||||||
|
<translation>自定义 (%1)</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -587,6 +587,10 @@
|
|||||||
<source>Json Editor</source>
|
<source>Json Editor</source>
|
||||||
<translation>JSON 编辑器</translation>
|
<translation>JSON 编辑器</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Please pick a core.</source>
|
||||||
|
<translation>请选择一个核心。</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>EditNaive</name>
|
<name>EditNaive</name>
|
||||||
@@ -1254,7 +1258,7 @@ Direct: %2</source>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Core not found: %1</source>
|
<source>Core not found: %1</source>
|
||||||
<translation>找不到 %1 核心</translation>
|
<translation>找不到 "%1" 核心。请前往设置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Update</source>
|
<source>Update</source>
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "ui/edit/edit_custom.h"
|
#include "ui/edit/edit_custom.h"
|
||||||
|
|
||||||
#include "fmt/includes.h"
|
#include "fmt/includes.h"
|
||||||
#include "fmt/Preset.hpp"
|
|
||||||
|
|
||||||
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
||||||
#include "main/GuiUtils.hpp"
|
#include "main/GuiUtils.hpp"
|
||||||
@@ -101,7 +100,8 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
|
|||||||
LOAD_TYPE("vless");
|
LOAD_TYPE("vless");
|
||||||
LOAD_TYPE("naive");
|
LOAD_TYPE("naive");
|
||||||
ui->type->addItem("Hysteria", "hysteria");
|
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");
|
LOAD_TYPE("chain");
|
||||||
|
|
||||||
// type changed
|
// type changed
|
||||||
@@ -124,6 +124,7 @@ DialogEditProfile::~DialogEditProfile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DialogEditProfile::typeSelected(const QString &newType) {
|
void DialogEditProfile::typeSelected(const QString &newType) {
|
||||||
|
QString customType;
|
||||||
type = newType;
|
type = newType;
|
||||||
bool validType = true;
|
bool validType = true;
|
||||||
|
|
||||||
@@ -151,15 +152,12 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
|||||||
auto _innerWidget = new EditNaive(this);
|
auto _innerWidget = new EditNaive(this);
|
||||||
innerWidget = _innerWidget;
|
innerWidget = _innerWidget;
|
||||||
innerEditor = _innerWidget;
|
innerEditor = _innerWidget;
|
||||||
} else if (type == "custom" || type == "hysteria") {
|
} else if (type == "custom" || type == "internal" || type == "hysteria") {
|
||||||
auto _innerWidget = new EditCustom(this);
|
auto _innerWidget = new EditCustom(this);
|
||||||
innerWidget = _innerWidget;
|
innerWidget = _innerWidget;
|
||||||
innerEditor = _innerWidget;
|
innerEditor = _innerWidget;
|
||||||
if (type == "hysteria" || (!newEnt && ent->CustomBean()->core == "hysteria")) {
|
customType = newEnt ? type : ent->CustomBean()->core;
|
||||||
_innerWidget->preset_core = type;
|
if (customType != "custom") _innerWidget->preset_core = customType;
|
||||||
_innerWidget->preset_command = Preset::Hysteria::command;
|
|
||||||
_innerWidget->preset_config = Preset::Hysteria::config;
|
|
||||||
}
|
|
||||||
type = "custom";
|
type = "custom";
|
||||||
} else {
|
} else {
|
||||||
validType = false;
|
validType = false;
|
||||||
@@ -176,11 +174,11 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hide some widget
|
// hide some widget
|
||||||
auto notChain = type != "chain";
|
auto showAddressPort = type != "chain" && customType != "internal";
|
||||||
ui->address->setVisible(notChain);
|
ui->address->setVisible(showAddressPort);
|
||||||
ui->address_l->setVisible(notChain);
|
ui->address_l->setVisible(showAddressPort);
|
||||||
ui->port->setVisible(notChain);
|
ui->port->setVisible(showAddressPort);
|
||||||
ui->port_l->setVisible(notChain);
|
ui->port_l->setVisible(showAddressPort);
|
||||||
|
|
||||||
// 右边 Outbound: settings
|
// 右边 Outbound: settings
|
||||||
auto stream = GetStreamSettings(ent->bean.data());
|
auto stream = GetStreamSettings(ent->bean.data());
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
||||||
#include "fmt/CustomBean.hpp"
|
#include "fmt/CustomBean.hpp"
|
||||||
|
#include "fmt/Preset.hpp"
|
||||||
#include "ui/edit/gen_hysteria.h"
|
#include "ui/edit/gen_hysteria.h"
|
||||||
|
|
||||||
EditCustom::EditCustom(QWidget *parent) :
|
EditCustom::EditCustom(QWidget *parent) :
|
||||||
@@ -15,12 +16,6 @@ EditCustom::EditCustom(QWidget *parent) :
|
|||||||
" host: your-domain.com\n"
|
" host: your-domain.com\n"
|
||||||
" sni: 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() {
|
EditCustom::~EditCustom() {
|
||||||
@@ -34,13 +29,27 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
|||||||
// load known core
|
// load known core
|
||||||
auto core_map = QString2QJsonObject(NekoRay::dataStore->extraCore->core_map);
|
auto core_map = QString2QJsonObject(NekoRay::dataStore->extraCore->core_map);
|
||||||
for (const auto &key: core_map.keys()) {
|
for (const auto &key: core_map.keys()) {
|
||||||
|
if (key == "naive" || key == "hysteria") continue;
|
||||||
ui->core->addItem(key);
|
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)
|
P_LOAD_COMBO(core)
|
||||||
ui->command->setText(bean->command.join(" "));
|
ui->command->setText(bean->command.join(" "));
|
||||||
P_LOAD_STRING(config_simple)
|
P_LOAD_STRING(config_simple)
|
||||||
|
|
||||||
|
// custom external
|
||||||
if (!bean->core.isEmpty()) {
|
if (!bean->core.isEmpty()) {
|
||||||
ui->core->setDisabled(true);
|
ui->core->setDisabled(true);
|
||||||
} else if (!preset_core.isEmpty()) {
|
} else if (!preset_core.isEmpty()) {
|
||||||
@@ -51,6 +60,14 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
|||||||
ui->config_simple->setText(preset_config);
|
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
|
// Generators
|
||||||
if (bean->core == "hysteria") {
|
if (bean->core == "hysteria") {
|
||||||
ui->generator->setVisible(true);
|
ui->generator->setVisible(true);
|
||||||
@@ -71,6 +88,11 @@ bool EditCustom::onEnd() {
|
|||||||
bean->command = ui->command->text().split(" ");
|
bean->command = ui->command->text().split(" ");
|
||||||
P_SAVE_STRING_QTEXTEDIT(config_simple)
|
P_SAVE_STRING_QTEXTEDIT(config_simple)
|
||||||
|
|
||||||
|
if (bean->core.isEmpty()) {
|
||||||
|
MessageBoxWarning(software_name, tr("Please pick a core."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -346,14 +346,18 @@ 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); });
|
||||||
//
|
//
|
||||||
connect(ui->menu_share_item, &QMenu::aboutToShow, this, [=] {
|
connect(ui->menu_share_item, &QMenu::aboutToShow, this, [=] {
|
||||||
auto name = software_core_name;
|
QString name;
|
||||||
auto selected = get_now_selected();
|
auto selected = get_now_selected();
|
||||||
if (!selected.isEmpty()) {
|
if (!selected.isEmpty()) {
|
||||||
auto ent = selected.first();
|
auto ent = selected.first();
|
||||||
name = ent->bean->DisplayCoreType();
|
name = ent->bean->DisplayCoreType();
|
||||||
}
|
}
|
||||||
|
ui->menu_export_config->setVisible(name == software_core_name);
|
||||||
ui->menu_export_config->setText(tr("Export %1 config").arg(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();
|
refresh_status();
|
||||||
|
|
||||||
// Prepare core
|
// Prepare core
|
||||||
@@ -1014,13 +1018,8 @@ void MainWindow::on_menu_export_config_triggered() {
|
|||||||
auto ent = ents.first();
|
auto ent = ents.first();
|
||||||
QString config_core;
|
QString config_core;
|
||||||
|
|
||||||
if (ent->bean->NeedExternal()) {
|
auto result = NekoRay::BuildConfig(ent, false);
|
||||||
auto result = ent->bean->BuildExternal(114514, MkPort());
|
config_core = QJsonObject2QString(result->coreConfig, true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
QApplication::clipboard()->setText(config_core);
|
QApplication::clipboard()->setText(config_core);
|
||||||
MessageBoxWarning(tr("Config copied"), config_core);
|
MessageBoxWarning(tr("Config copied"), config_core);
|
||||||
|
|||||||
Reference in New Issue
Block a user