mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
feat: improve custom config
This commit is contained in:
@@ -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)},
|
||||
|
||||
@@ -144,6 +144,10 @@ namespace NekoRay::fmt {
|
||||
result.outbound = outbound;
|
||||
}
|
||||
|
||||
if (core == "internal") {
|
||||
result.outbound = QString2QJsonObject(config_simple);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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?
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
</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>
|
||||
<translation>将核心切换到 %1,点击 "是 "完成切换,程序将重新启动。此功能可能不稳定,请不要频繁切换。</translation>
|
||||
<translation>将核心切换到 %1。点击 "是" 完成切换,程序将重新启动。此功能可能不稳定,请不要频繁切换。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -337,10 +337,6 @@
|
||||
<source>Host</source>
|
||||
<translation>主机(Host)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom</source>
|
||||
<translation>自定义</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Packet Encoding</source>
|
||||
<translation>包编码</translation>
|
||||
@@ -350,8 +346,12 @@
|
||||
<translation>设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation type="obsolete">无</translation>
|
||||
<source>Custom (Extra Core)</source>
|
||||
<translation>自定义 (其他核心)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom (%1)</source>
|
||||
<translation>自定义 (%1)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -587,6 +587,10 @@
|
||||
<source>Json Editor</source>
|
||||
<translation>JSON 编辑器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please pick a core.</source>
|
||||
<translation>请选择一个核心。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>EditNaive</name>
|
||||
@@ -1254,7 +1258,7 @@ Direct: %2</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Core not found: %1</source>
|
||||
<translation>找不到 %1 核心</translation>
|
||||
<translation>找不到 "%1" 核心。请前往设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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<NekoRay::ProxyEntity> _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<NekoRay::ProxyEntity> _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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user