[fix] Several further fixes

Former-commit-id: 12fb3bcd29
This commit is contained in:
Leroy.H.Y 2019-11-27 10:39:04 +08:00
parent ce218f1ada
commit 22ecbe25a3
14 changed files with 759 additions and 504 deletions

View File

@ -1 +1 @@
887 917

View File

@ -34,7 +34,7 @@ namespace Qv2ray
bool RenameConnection(QString originalName, QString newName); bool RenameConnection(QString originalName, QString newName);
// VMess URI Protocol // VMess URI Protocol
QJsonObject ConvertConfigFromVMessString(QString vmess, QString *alias, QString *errMessage); QJsonObject ConvertConfigFromVMessString(QString vmess, QString *alias, QString *errMessage);
QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool overrideInbounds); QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool keepInbounds);
QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias); QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias);
} }

View File

@ -1,4 +1,4 @@
#include "QvCoreConfigOperations.hpp" #include "QvCoreConfigOperations.hpp"
namespace Qv2ray namespace Qv2ray
{ {
@ -224,7 +224,7 @@ namespace Qv2ray
RROOT RROOT
} }
QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool overrideInbounds) QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool keepInbounds)
{ {
QFile source(sourceFilePath); QFile source(sourceFilePath);
@ -233,9 +233,9 @@ namespace Qv2ray
return QJsonObject(); return QJsonObject();
} }
auto root = JsonFromString(StringFromFile(new QFile(sourceFilePath))); auto root = JsonFromString(StringFromFile(&source));
if (overrideInbounds) { if (!keepInbounds) {
JSON_ROOT_TRY_REMOVE("inbounds") JSON_ROOT_TRY_REMOVE("inbounds")
} }

View File

@ -24,6 +24,15 @@ ImportConfigWindow::ImportConfigWindow(QWidget *parent)
nameTxt->setText(QDateTime::currentDateTime().toString("MM-dd_hh-mm") + "_" + tr("Imported") + "_"); nameTxt->setText(QDateTime::currentDateTime().toString("MM-dd_hh-mm") + "_" + tr("Imported") + "_");
} }
QMap<QString, QJsonObject> ImportConfigWindow::OpenImport(bool outboundsOnly)
{
// if Outbound Only, set keepImported to false and disable the checkbox
// keepImportedInboundCheckBox->setChecked(!outboundsOnly);
keepImportedInboundCheckBox->setEnabled(!outboundsOnly);
this->exec();
return this->result() == QDialog::Accepted ? connections : QMap<QString, QJsonObject>();
}
void ImportConfigWindow::on_importSourceCombo_currentIndexChanged(int index) void ImportConfigWindow::on_importSourceCombo_currentIndexChanged(int index)
{ {
stackedWidget->setCurrentIndex(index); stackedWidget->setCurrentIndex(index);
@ -37,17 +46,7 @@ void ImportConfigWindow::on_selectFileBtn_clicked()
void ImportConfigWindow::on_qrFromScreenBtn_clicked() void ImportConfigWindow::on_qrFromScreenBtn_clicked()
{ {
// QRubberBand
QThread::msleep(static_cast<ulong>(doubleSpinBox->value() * 1000)); QThread::msleep(static_cast<ulong>(doubleSpinBox->value() * 1000));
//bool hasVmessDetected = false;
//for (auto screen : qApp->screens()) {
// if (!screen) {
// LOG(MODULE_UI, "Cannot even find a screen. RARE")
// QvMessageBox(this, tr("Screenshot failed"), tr("Cannot find a valid screen, it's rare."));
// return;
// }
//auto pix = screen->grabWindow(0);
//
ScreenShotWindow w; ScreenShotWindow w;
auto pix = w.DoScreenShot(); auto pix = w.DoScreenShot();
@ -57,32 +56,25 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
if (str.trimmed().isEmpty()) { if (str.trimmed().isEmpty()) {
LOG(MODULE_UI, "Cannot decode QR Code from an image, size: h=" + to_string(pix.width()) + ", v=" + to_string(pix.height())) LOG(MODULE_UI, "Cannot decode QR Code from an image, size: h=" + to_string(pix.width()) + ", v=" + to_string(pix.height()))
QvMessageBox(this, tr("Capture QRCode"), tr("Cannot find a valid QRCode from this region.")); QvMessageBox(this, tr("Capture QRCode"), tr("Cannot find a valid QRCode from this region."));
// continue;
} else { } else {
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE); vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
//hasVmessDetected = true;
} }
} }
//}
//if (!hasVmessDetected) {
//QvMessageBox(this, tr("QRCode scanning failed"), tr("Cannot find any QRCode from any screens."));
//}
} }
void ImportConfigWindow::on_beginImportBtn_clicked() void ImportConfigWindow::on_beginImportBtn_clicked()
{ {
QString aliasPrefix = nameTxt->text(); QString aliasPrefix = nameTxt->text();
QJsonObject config; QJsonObject config;
auto conf = GetGlobalConfig(); //auto conf = GetGlobalConfig();
switch (importSourceCombo->currentIndex()) { switch (importSourceCombo->currentIndex()) {
case 0: { case 0: {
// From File... // From File...
bool overrideInBound = !keepImportedInboundCheckBox->isChecked(); bool keepInBound = keepImportedInboundCheckBox->isChecked();
QString path = fileLineTxt->text(); QString path = fileLineTxt->text();
aliasPrefix = aliasPrefix.isEmpty() ? aliasPrefix : QFileInfo(path).fileName(); aliasPrefix = aliasPrefix.isEmpty() ? aliasPrefix : QFileInfo(path).fileName();
config = ConvertConfigFromFile(path, overrideInBound); config = ConvertConfigFromFile(path, keepInBound);
if (config.isEmpty()) { if (config.isEmpty()) {
QvMessageBox(this, tr("Import config file"), tr("Import from file failed, for more information, please check the log file.")); QvMessageBox(this, tr("Import config file"), tr("Import from file failed, for more information, please check the log file."));
@ -91,14 +83,7 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
QvMessageBox(this, tr("Import config file"), tr("Failed to check the validity of the config file.")); QvMessageBox(this, tr("Import config file"), tr("Failed to check the validity of the config file."));
return; return;
} else { } else {
// We save first, "alias" may change to prevent override existing file. connections[aliasPrefix] = config;
bool alwaysFalse = SaveConnectionConfig(config, &aliasPrefix, false);
if (alwaysFalse) {
QvMessageBox(this, tr("Assertion Failed"), tr("Assertion failed: ::SaveConnectionConfig should returns false."));
}
conf.configs.push_back(aliasPrefix.toStdString());
break; break;
} }
} }
@ -125,13 +110,7 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
vmessErrors[vmess] = QString::number(vmessErrors.count() + 1) + ": " + errMessage; vmessErrors[vmess] = QString::number(vmessErrors.count() + 1) + ": " + errMessage;
continue; continue;
} else { } else {
bool alwaysFalse = SaveConnectionConfig(config, &aliasPrefix, false); connections[aliasPrefix] = config;
if (alwaysFalse) {
QvMessageBox(this, tr("Assertion Failed"), "Assertion failed: ::SaveConnectionConfig should returns false.");
}
conf.configs.push_back(aliasPrefix.toStdString());
} }
} }
@ -141,24 +120,19 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
vmessConnectionStringTxt->appendPlainText(vmessErrors.key(item)); vmessConnectionStringTxt->appendPlainText(vmessErrors.key(item));
errorsList->addItem(item); errorsList->addItem(item);
} }
// Don't quit;
return;
} }
break; break;
} }
case 2: { case 2: {
QvMessageBox(this, tr("TODO"), tr("TODO"));
// Subscription link. // Subscription link.
break; break;
} }
} }
SetGlobalConfig(conf); accept();
// Never restart current connection after import.
emit s_reload_config(false);
close();
} }
void ImportConfigWindow::on_selectImageBtn_clicked() void ImportConfigWindow::on_selectImageBtn_clicked()
{ {
@ -197,7 +171,7 @@ void ImportConfigWindow::on_errorsList_currentItemChanged(QListWidgetItem *curre
return; return;
} }
// // Select vmess string that is invalid.
QTextCursor c = vmessConnectionStringTxt->textCursor(); QTextCursor c = vmessConnectionStringTxt->textCursor();
c.setPosition(startPos); c.setPosition(startPos);
c.setPosition(endPos, QTextCursor::KeepAnchor); c.setPosition(endPos, QTextCursor::KeepAnchor);
@ -218,8 +192,7 @@ void ImportConfigWindow::on_editFileBtn_clicked()
if (!jsonCheckingError.isEmpty()) { if (!jsonCheckingError.isEmpty()) {
LOG(MODULE_FILE, "Currupted JSON file detected") LOG(MODULE_FILE, "Currupted JSON file detected")
if (QvMessageBoxAsk(this, tr("Edit file as JSON"), tr("The file you selected has json syntax error. Continue editing may make you lose data. Would you like to continue?") + if (QvMessageBoxAsk(this, tr("Edit file as JSON"), tr("The file you selected has json syntax error. Continue editing may make you lose data. Would you like to continue?") + NEWLINE + jsonCheckingError) != QMessageBox::Yes) {
NEWLINE + jsonCheckingError) != QMessageBox::Yes) {
return; return;
} else { } else {
LOG(MODULE_FILE, "Continue editing curruped json file, data loss is expected.") LOG(MODULE_FILE, "Continue editing curruped json file, data loss is expected.")
@ -257,13 +230,15 @@ void ImportConfigWindow::on_connectionEditBtn_clicked()
root.insert("outbounds", outboundsList); root.insert("outbounds", outboundsList);
// //
// WARN This one will change the connection name, because of some duplicates. // WARN This one will change the connection name, because of some duplicates.
SaveConnectionConfig(root, &alias, false); connections[alias] = root;
//SaveConnectionConfig(root, &alias, false);
// //
auto conf = GetGlobalConfig(); // WARN Add connection here
auto connectionList = conf.configs; //auto conf = GetGlobalConfig();
connectionList.push_back(alias.toStdString()); //auto connectionList = conf.configs;
conf.configs = connectionList; //connectionList.push_back(alias.toStdString());
SetGlobalConfig(conf); //conf.configs = connectionList;
//SetGlobalConfig(conf);
close(); close();
} else { } else {
return; return;

View File

@ -2,6 +2,8 @@
#define IMPORTCONF_H #define IMPORTCONF_H
#include <QDialog> #include <QDialog>
#include <QString>
#include <QJsonObject>
#include "ui_w_ImportConfig.h" #include "ui_w_ImportConfig.h"
class ImportConfigWindow : public QDialog, private Ui::ImportConfigWindow class ImportConfigWindow : public QDialog, private Ui::ImportConfigWindow
@ -11,8 +13,7 @@ class ImportConfigWindow : public QDialog, private Ui::ImportConfigWindow
public: public:
explicit ImportConfigWindow(QWidget *parent = nullptr); explicit ImportConfigWindow(QWidget *parent = nullptr);
~ImportConfigWindow() { } ~ImportConfigWindow() { }
signals: QMap<QString, QJsonObject> OpenImport(bool outboundsOnly = false);
void s_reload_config(bool need_restart);
private slots: private slots:
void on_importSourceCombo_currentIndexChanged(int index); void on_importSourceCombo_currentIndexChanged(int index);
@ -30,6 +31,7 @@ class ImportConfigWindow : public QDialog, private Ui::ImportConfigWindow
void on_cancelImportBtn_clicked(); void on_cancelImportBtn_clicked();
private: private:
QMap<QString, QJsonObject> connections;
QMap<QString, QString> vmessErrors; QMap<QString, QString> vmessErrors;
}; };

View File

@ -24,9 +24,13 @@ InboundEditor::InboundEditor(QJsonObject root, QWidget *parent) :
} else if (inboundType == "mtproto") { } else if (inboundType == "mtproto") {
mtSettings = root["settings"].toObject(); mtSettings = root["settings"].toObject();
} else { } else {
LOG(MODULE_UI, "Unsupported inbound type: " + inboundType.toStdString() + ", decisions should be made if to open JSONEDITOR") if (!root["protocol"].toString().isEmpty()) {
LOG(MODULE_UI, "Unsupported inbound type: " + inboundType.toStdString())
QvMessageBox(this, tr("Inbound type not supported"), tr("The inbound type is not supported by Qv2ray (yet). Please use JsonEditor to change the settings") + "\r\n" + QvMessageBox(this, tr("Inbound type not supported"), tr("The inbound type is not supported by Qv2ray (yet). Please use JsonEditor to change the settings") + "\r\n" +
tr("Inbound: ") + inboundType); tr("Inbound: ") + inboundType);
} else {
LOG(MODULE_UI, "Creating new inbound config")
}
} }
LoadUIData(); LoadUIData();
@ -61,7 +65,10 @@ QJsonObject InboundEditor::GenerateNewRoot()
void InboundEditor::LoadUIData() void InboundEditor::LoadUIData()
{ {
isLoading = true; isLoading = true;
strategyCombo->setCurrentText(allocate["strategy"].toString()); auto x = allocate["strategy"].toString();
allocate["strategy"] = x.isEmpty() ? "always" : x;
strategyCombo->setCurrentText(x);
//
refreshNumberBox->setValue(allocate["refresh"].toInt()); refreshNumberBox->setValue(allocate["refresh"].toInt());
concurrencyNumberBox->setValue(allocate["concurrency"].toInt()); concurrencyNumberBox->setValue(allocate["concurrency"].toInt());
enableSniffingCB->setChecked(sniffing["enabled"].toBool()); enableSniffingCB->setChecked(sniffing["enabled"].toBool());

View File

@ -65,6 +65,7 @@ MainWindow::MainWindow(QWidget *parent)
// //
QAction *action_RCM_RenameConnection = new QAction(tr("Rename"), this); QAction *action_RCM_RenameConnection = new QAction(tr("Rename"), this);
QAction *action_RCM_StartThis = new QAction(tr("Connect to this"), this); QAction *action_RCM_StartThis = new QAction(tr("Connect to this"), this);
QAction *action_RCM_ConvToComplex = new QAction(tr("Edit as Complex Config"), this);
QAction *action_RCM_EditJson = new QAction(QICON_R("json.png"), tr("Edit as Json"), this); QAction *action_RCM_EditJson = new QAction(QICON_R("json.png"), tr("Edit as Json"), this);
QAction *action_RCM_ShareQR = new QAction(QICON_R("share.png"), tr("Share as QRCode/VMess URL"), this); QAction *action_RCM_ShareQR = new QAction(QICON_R("share.png"), tr("Share as QRCode/VMess URL"), this);
// //
@ -88,6 +89,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(action_RCM_RenameConnection, &QAction::triggered, this, &MainWindow::on_action_RenameConnection_triggered); connect(action_RCM_RenameConnection, &QAction::triggered, this, &MainWindow::on_action_RenameConnection_triggered);
connect(action_RCM_StartThis, &QAction::triggered, this, &MainWindow::on_action_StartThis_triggered); connect(action_RCM_StartThis, &QAction::triggered, this, &MainWindow::on_action_StartThis_triggered);
connect(action_RCM_EditJson, &QAction::triggered, this, &MainWindow::on_action_RCM_EditJson_triggered); connect(action_RCM_EditJson, &QAction::triggered, this, &MainWindow::on_action_RCM_EditJson_triggered);
connect(action_RCM_ConvToComplex, &QAction::triggered, this, &MainWindow::on_action_RCM_ConvToComplex_triggered);
// //
// Share optionss // Share optionss
connect(action_RCM_ShareQR, &QAction::triggered, this, &MainWindow::on_action_RCM_ShareQR_triggered); connect(action_RCM_ShareQR, &QAction::triggered, this, &MainWindow::on_action_RCM_ShareQR_triggered);
@ -102,6 +104,7 @@ MainWindow::MainWindow(QWidget *parent)
listMenu = new QMenu(this); listMenu = new QMenu(this);
listMenu->addAction(action_RCM_RenameConnection); listMenu->addAction(action_RCM_RenameConnection);
listMenu->addAction(action_RCM_StartThis); listMenu->addAction(action_RCM_StartThis);
listMenu->addAction(action_RCM_ConvToComplex);
listMenu->addAction(action_RCM_EditJson); listMenu->addAction(action_RCM_EditJson);
listMenu->addAction(action_RCM_ShareQR); listMenu->addAction(action_RCM_ShareQR);
// //
@ -308,8 +311,6 @@ void MainWindow::on_startButton_clicked()
bool httpEnabled = conf.inboundConfig.useHTTP; bool httpEnabled = conf.inboundConfig.useHTTP;
bool socksEnabled = conf.inboundConfig.useSocks; bool socksEnabled = conf.inboundConfig.useSocks;
// TODO: Set PAC proxy string
if (usePAC) { if (usePAC) {
bool canStartPAC = true; bool canStartPAC = true;
QString pacProxyString; // Something like this --> SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT; http://proxy:8080 QString pacProxyString; // Something like this --> SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT; http://proxy:8080
@ -498,16 +499,26 @@ void MainWindow::ShowAndSetConnection(QString guiConnectionName, bool SetConnect
// Check empty again... // Check empty again...
if (guiConnectionName.isEmpty()) return; if (guiConnectionName.isEmpty()) return;
// --------- BRGIN Show Connection
auto root = connections[guiConnectionName];
auto outBoundRoot = root["outbounds"].toArray().first().toObject();
// //
auto outboundType = outBoundRoot["protocol"].toString();
_OutBoundTypeLabel->setText(outboundType);
removeConfigButton->setEnabled(true); removeConfigButton->setEnabled(true);
editConfigButton->setEnabled(true); editConfigButton->setEnabled(true);
editJsonBtn->setEnabled(true); editJsonBtn->setEnabled(true);
duplicateBtn->setEnabled(true); duplicateBtn->setEnabled(true);
//
// --------- BRGIN Show Connection
auto root = connections[guiConnectionName];
//
auto isComplexConfig = root["routing"].toObject()["rules"].toArray().count() > 0;
routeCountLabel->setText(isComplexConfig > 0 ? tr("Complex") : tr("Simple"));
if (isComplexConfig) {
_OutBoundTypeLabel->setText(tr("N/A"));
_hostLabel->setText(tr("N/A"));
_portLabel->setText(tr("N/A"));
} else {
auto outBoundRoot = root["outbounds"].toArray().first().toObject();
auto outboundType = outBoundRoot["protocol"].toString();
_OutBoundTypeLabel->setText(outboundType);
if (outboundType == "vmess") { if (outboundType == "vmess") {
auto Server = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); auto Server = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject()));
@ -524,8 +535,7 @@ void MainWindow::ShowAndSetConnection(QString guiConnectionName, bool SetConnect
_hostLabel->setText(QSTRING(Server.address)); _hostLabel->setText(QSTRING(Server.address));
_portLabel->setText(QSTRING(to_string(Server.port))); _portLabel->setText(QSTRING(to_string(Server.port)));
} }
}
routeCountLabel->setText(QString::number(root["routing"].toObject()["rules"].toArray().count()));
// --------- END Show Connection // --------- END Show Connection
// //
@ -660,8 +670,22 @@ void MainWindow::on_removeConfigButton_clicked()
} }
void MainWindow::on_importConfigButton_clicked() void MainWindow::on_importConfigButton_clicked()
{ {
// BETA
ImportConfigWindow *w = new ImportConfigWindow(this); ImportConfigWindow *w = new ImportConfigWindow(this);
w->exec(); auto configs = w->OpenImport();
auto gConf = GetGlobalConfig();
for (auto conf : configs) {
auto name = configs.key(conf, "");
if (name.isEmpty())
continue;
SaveConnectionConfig(conf, &name, false);
gConf.configs.push_back(name.toStdString());
}
SetGlobalConfig(gConf);
OnConfigListChanged(false); OnConfigListChanged(false);
} }
void MainWindow::on_editConfigButton_clicked() void MainWindow::on_editConfigButton_clicked()
@ -677,7 +701,7 @@ void MainWindow::on_editConfigButton_clicked()
QJsonObject root; QJsonObject root;
bool isChanged = false; bool isChanged = false;
if (outBoundRoot["outbounds"].toArray().count() > 1) { if (CheckIsComplexConfig(outBoundRoot)) {
LOG(MODULE_UI, "INFO: Opening route editor.") LOG(MODULE_UI, "INFO: Opening route editor.")
RouteEditor *routeWindow = new RouteEditor(outBoundRoot, this); RouteEditor *routeWindow = new RouteEditor(outBoundRoot, this);
root = routeWindow->OpenEditor(); root = routeWindow->OpenEditor();
@ -705,6 +729,34 @@ void MainWindow::on_reconnectButton_clicked()
on_stopButton_clicked(); on_stopButton_clicked();
on_startButton_clicked(); on_startButton_clicked();
} }
void MainWindow::on_action_RCM_ConvToComplex_triggered()
{
// Check if we have a connection selected...
if (connectionListWidget->currentIndex().row() < 0) {
QvMessageBox(this, tr("No Config Selected"), tr("Please Select a Config"));
return;
}
auto alias = connectionListWidget->currentItem()->text();
auto outBoundRoot = connections[alias];
QJsonObject root;
bool isChanged = false;
//
LOG(MODULE_UI, "INFO: Opening route editor.")
RouteEditor *routeWindow = new RouteEditor(outBoundRoot, this);
root = routeWindow->OpenEditor();
isChanged = routeWindow->result() == QDialog::Accepted;
if (isChanged) {
connections[alias] = root;
// true indicates the alias will NOT change
SaveConnectionConfig(root, &alias, true);
OnConfigListChanged(alias == CurrentConnectionName);
ShowAndSetConnection(CurrentConnectionName, false, false);
}
}
void MainWindow::on_action_RCM_EditJson_triggered() void MainWindow::on_action_RCM_EditJson_triggered()
{ {
// Check if we have a connection selected... // Check if we have a connection selected...
@ -745,10 +797,9 @@ void MainWindow::on_shareBtn_clicked()
auto alias = connectionListWidget->currentItem()->text(); auto alias = connectionListWidget->currentItem()->text();
auto root = connections[alias]; auto root = connections[alias];
auto outBoundRoot = root["outbounds"].toArray().first().toObject(); auto outBoundRoot = root["outbounds"].toArray().first().toObject();
//
auto outboundType = outBoundRoot["protocol"].toString(); auto outboundType = outBoundRoot["protocol"].toString();
if (outboundType == "vmess") { if (CheckIsComplexConfig(root) && outboundType == "vmess") {
auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject()));
auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outBoundRoot["streamSettings"].toObject())); auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outBoundRoot["streamSettings"].toObject()));
auto vmess = ConvertConfigToVMessString(transport, vmessServer, alias); auto vmess = ConvertConfigToVMessString(transport, vmessServer, alias);

View File

@ -90,6 +90,7 @@ class MainWindow : public QMainWindow, Ui::MainWindow
// //
void on_action_StartThis_triggered(); void on_action_StartThis_triggered();
void on_action_RCM_EditJson_triggered(); void on_action_RCM_EditJson_triggered();
void on_action_RCM_ConvToComplex_triggered();
void on_action_RenameConnection_triggered(); void on_action_RenameConnection_triggered();
// //
QvHttpRequestHelper HTTPRequestHelper; QvHttpRequestHelper HTTPRequestHelper;

View File

@ -331,26 +331,12 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Mux</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="muxLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
<string>Actions</string> <string>Operations</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -387,6 +373,9 @@
</item> </item>
<item> <item>
<widget class="QPushButton" name="pingTestBtn"> <widget class="QPushButton" name="pingTestBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>Ping Test</string> <string>Ping Test</string>
</property> </property>

View File

@ -6,6 +6,7 @@
#include "w_OutboundEditor.hpp" #include "w_OutboundEditor.hpp"
#include "w_MainWindow.hpp" #include "w_MainWindow.hpp"
#include "w_JsonEditor.hpp" #include "w_JsonEditor.hpp"
#include "w_RoutesEditor.hpp"
OutboundEditor::OutboundEditor(QWidget *parent) OutboundEditor::OutboundEditor(QWidget *parent)
: QDialog(parent), : QDialog(parent),

View File

@ -28,7 +28,7 @@
<property name="modal"> <property name="modal">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout_4" columnstretch="8,3"> <layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0"> <item row="0" column="0">
<layout class="QFormLayout" name="formLayout_5"> <layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0"> <item row="0" column="0">
@ -327,7 +327,7 @@
<item row="3" column="5"> <item row="3" column="5">
<widget class="QPushButton" name="tcpRespDefBtn"> <widget class="QPushButton" name="tcpRespDefBtn">
<property name="text"> <property name="text">
<string>Default Value</string> <string>Default</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -428,7 +428,7 @@
<item row="3" column="2"> <item row="3" column="2">
<widget class="QPushButton" name="tcpRequestDefBtn"> <widget class="QPushButton" name="tcpRequestDefBtn">
<property name="text"> <property name="text">
<string>Default Value</string> <string>Default</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -1045,7 +1045,9 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -1056,6 +1058,8 @@
</widget> </widget>
</item> </item>
</layout> </layout>
</item>
</layout>
</widget> </widget>
<resources/> <resources/>
<connections> <connections>

View File

@ -1,12 +1,12 @@
#include "w_RoutesEditor.hpp" #include "w_RoutesEditor.hpp"
#include "QvCoreConfigOperations.hpp" #include "QvCoreConfigOperations.hpp"
#include "w_OutboundEditor.hpp" #include "w_OutboundEditor.hpp"
#include "w_JsonEditor.hpp" #include "w_JsonEditor.hpp"
#include "w_InboundEditor.hpp" #include "w_InboundEditor.hpp"
#include "w_ImportConfig.hpp"
static bool isLoading = false; static bool isLoading = false;
#define CurrentRule this->rules[this->currentRuleIndex] #define CurrentRule this->rules[this->currentRuleIndex]
#define STATUS(msg) statusLabel->setText(tr(msg));
#define LOADINGCHECK if(isLoading) return; #define LOADINGCHECK if(isLoading) return;
RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) :
@ -318,9 +318,9 @@ void RouteEditor::ShowRuleDetail(RuleObject rule)
inboundsList->item(_index)->setCheckState(Qt::Checked); inboundsList->item(_index)->setCheckState(Qt::Checked);
inboundsList->setCurrentRow(_index); inboundsList->setCurrentRow(_index);
STATUS("OK") statusLabel->setText(tr("OK"));
} else { } else {
STATUS("Cannot find inbound by a tag, possible currupted files?") statusLabel->setText(tr("Cannot find inbound by a tag, possible currupted files?"));
LOG(MODULE_UI, "An inbound could not be determined by tag.") LOG(MODULE_UI, "An inbound could not be determined by tag.")
return; return;
} }
@ -335,7 +335,7 @@ void RouteEditor::on_editOutboundBtn_clicked()
int row = outboundsList->currentRow(); int row = outboundsList->currentRow();
if (row < 0) { if (row < 0) {
STATUS("No row selected.") statusLabel->setText(tr("No row selected."));
LOG(MODULE_UI, "No outbound row selected.") LOG(MODULE_UI, "No outbound row selected.")
return; return;
} }
@ -348,19 +348,19 @@ void RouteEditor::on_editOutboundBtn_clicked()
tr("This outbound entry is not supported by the GUI editor.") + "\r\n" + tr("This outbound entry is not supported by the GUI editor.") + "\r\n" +
tr("We will launch Json Editor instead.")); tr("We will launch Json Editor instead."));
JsonEditor *w = new JsonEditor(currentOutbound, this); JsonEditor *w = new JsonEditor(currentOutbound, this);
STATUS("Opening JSON editor") statusLabel->setText(tr("Opening JSON editor"));
result = w->OpenEditor(); result = w->OpenEditor();
delete w; delete w;
} else { } else {
OutboundEditor *w = new OutboundEditor(currentOutbound, this); OutboundEditor *w = new OutboundEditor(currentOutbound, this);
STATUS("Opening default outbound editor.") statusLabel->setText(tr("Opening default outbound editor."));
result = w->OpenEditor(); result = w->OpenEditor();
delete w; delete w;
} }
outbounds[row] = result; outbounds[row] = result;
on_outboundsList_currentRowChanged(row); on_outboundsList_currentRowChanged(row);
STATUS("OK") statusLabel->setText(tr("OK"));
} }
void RouteEditor::on_insertDirectBtn_clicked() void RouteEditor::on_insertDirectBtn_clicked()
@ -370,7 +370,7 @@ void RouteEditor::on_insertDirectBtn_clicked()
auto out = GenerateOutboundEntry("freedom", freedom, QJsonObject(), QJsonObject(), "0.0.0.0", tag); auto out = GenerateOutboundEntry("freedom", freedom, QJsonObject(), QJsonObject(), "0.0.0.0", tag);
this->outbounds.append(out); this->outbounds.append(out);
outboundsList->addItem(tag); outboundsList->addItem(tag);
STATUS("Added DIRECT outbound") statusLabel->setText(tr("Added DIRECT outbound"));
} }
void RouteEditor::on_editInboundBtn_clicked() void RouteEditor::on_editInboundBtn_clicked()
@ -386,20 +386,20 @@ void RouteEditor::on_editInboundBtn_clicked()
if (protocol != "http" && protocol != "mtproto" && protocol != "socks" && protocol != "dokodemo-door") { if (protocol != "http" && protocol != "mtproto" && protocol != "socks" && protocol != "dokodemo-door") {
QvMessageBox(this, tr("Cannot Edit"), tr("Currently, this type of outbound is not supported by the editor.") + "\r\n" + QvMessageBox(this, tr("Cannot Edit"), tr("Currently, this type of outbound is not supported by the editor.") + "\r\n" +
tr("We will launch Json Editor instead.")); tr("We will launch Json Editor instead."));
STATUS("Opening JSON editor") statusLabel->setText(tr("Opening JSON editor"));
JsonEditor *w = new JsonEditor(currentInbound, this); JsonEditor *w = new JsonEditor(currentInbound, this);
result = w->OpenEditor(); result = w->OpenEditor();
delete w; delete w;
} else { } else {
InboundEditor *w = new InboundEditor(currentInbound, this); InboundEditor *w = new InboundEditor(currentInbound, this);
STATUS("Opening default inbound editor") statusLabel->setText(tr("Opening default inbound editor"));
result = w->OpenEditor(); result = w->OpenEditor();
delete w; delete w;
} }
inbounds[row] = result; inbounds[row] = result;
on_inboundsList_currentRowChanged(row); on_inboundsList_currentRowChanged(row);
STATUS("OK") statusLabel->setText(tr("OK"));
} }
void RouteEditor::on_routeProtocolHTTPCB_stateChanged(int arg1) void RouteEditor::on_routeProtocolHTTPCB_stateChanged(int arg1)
@ -414,7 +414,7 @@ void RouteEditor::on_routeProtocolHTTPCB_stateChanged(int arg1)
if (routeProtocolBTCB->isChecked()) protocols << "bittorrent"; if (routeProtocolBTCB->isChecked()) protocols << "bittorrent";
CurrentRule.protocol = protocols.toStdList(); CurrentRule.protocol = protocols.toStdList();
STATUS("Protocol list changed.") statusLabel->setText(tr("Protocol list changed."));
} }
void RouteEditor::on_routeProtocolTLSCB_stateChanged(int arg1) void RouteEditor::on_routeProtocolTLSCB_stateChanged(int arg1)
@ -429,7 +429,7 @@ void RouteEditor::on_routeProtocolTLSCB_stateChanged(int arg1)
if (routeProtocolBTCB->isChecked()) protocols << "bittorrent"; if (routeProtocolBTCB->isChecked()) protocols << "bittorrent";
CurrentRule.protocol = protocols.toStdList(); CurrentRule.protocol = protocols.toStdList();
STATUS("Protocol list changed.") statusLabel->setText(tr("Protocol list changed."));
} }
void RouteEditor::on_routeProtocolBTCB_stateChanged(int arg1) void RouteEditor::on_routeProtocolBTCB_stateChanged(int arg1)
@ -444,7 +444,7 @@ void RouteEditor::on_routeProtocolBTCB_stateChanged(int arg1)
if (routeProtocolTLSCB->isChecked()) protocols << "tls"; if (routeProtocolTLSCB->isChecked()) protocols << "tls";
CurrentRule.protocol = protocols.toStdList(); CurrentRule.protocol = protocols.toStdList();
STATUS("Protocol list changed.") statusLabel->setText(tr("Protocol list changed."));
} }
void RouteEditor::on_balabcerAddBtn_clicked() void RouteEditor::on_balabcerAddBtn_clicked()
@ -460,9 +460,9 @@ void RouteEditor::on_balabcerAddBtn_clicked()
if (!balancerTx.isEmpty()) { if (!balancerTx.isEmpty()) {
balancerList->addItem(balancerTx); balancerList->addItem(balancerTx);
balancerSelectionCombo->setEditText(""); balancerSelectionCombo->setEditText("");
STATUS("OK") statusLabel->setText(tr("OK"));
} else { } else {
STATUS("Balacer is empty, not processing.") statusLabel->setText(tr("Balacer is empty, not processing."));
} }
} }
@ -476,7 +476,7 @@ void RouteEditor::on_balancerDelBtn_clicked()
Balancers[QSTRING(CurrentRule.balancerTag)].removeAt(balancerList->currentRow()); Balancers[QSTRING(CurrentRule.balancerTag)].removeAt(balancerList->currentRow());
balancerList->takeItem(balancerList->currentRow()); balancerList->takeItem(balancerList->currentRow());
STATUS("Removed a balancer entry.") statusLabel->setText(tr("Removed a balancer entry."));
} }
void RouteEditor::on_hostList_textChanged() void RouteEditor::on_hostList_textChanged()
@ -569,7 +569,7 @@ void RouteEditor::on_routesTable_cellChanged(int row, int column)
} }
rules[row].QV2RAY_RULE_ENABLED = routesTable->item(row, column)->checkState() == Qt::Checked; rules[row].QV2RAY_RULE_ENABLED = routesTable->item(row, column)->checkState() == Qt::Checked;
STATUS((rules[row].QV2RAY_RULE_ENABLED ? "Enabled a route" : "Disabled a route")) statusLabel->setText(tr((rules[row].QV2RAY_RULE_ENABLED ? "Enabled a route" : "Disabled a route")));
} }
void RouteEditor::on_netBothRB_clicked() void RouteEditor::on_netBothRB_clicked()
@ -647,7 +647,7 @@ void RouteEditor::on_inboundsList_itemChanged(QListWidgetItem *item)
} }
CurrentRule.inboundTag = new_inbounds.toStdList(); CurrentRule.inboundTag = new_inbounds.toStdList();
STATUS("OK") statusLabel->setText(tr("OK"));
} }
void RouteEditor::on_delRouteBtn_clicked() void RouteEditor::on_delRouteBtn_clicked()
@ -730,3 +730,35 @@ void RouteEditor::on_delInboundBtn_clicked()
inbounds.removeAt(index); inbounds.removeAt(index);
inboundsList->takeItem(index); inboundsList->takeItem(index);
} }
void RouteEditor::on_addInboundBtn_clicked()
{
LOADINGCHECK
InboundEditor w(QJsonObject(), this);
auto _result = w.OpenEditor();
inbounds.append(_result);
inboundsList->addItem(tr("New Inbound"));
}
void RouteEditor::on_addOutboundBtn_clicked()
{
LOADINGCHECK
ImportConfigWindow *w = new ImportConfigWindow(this);
// True here for not keep the inbounds.
auto configs = w->OpenImport(true);
for (auto conf : configs) {
auto name = configs.key(conf, "");
if (name.isEmpty())
continue;
// conf is rootObject, needs to unwrap it.
auto confList = conf["outbounds"].toArray();
for (int i = 0; i < confList.count(); i++) {
outbounds.append(confList[i]);
outboundsList->addItem(name + "_" + QString::number(i));
}
}
}

View File

@ -1,4 +1,4 @@
#ifndef W_QVOUTBOUNDEDITOR_H #ifndef W_QVOUTBOUNDEDITOR_H
#define W_QVOUTBOUNDEDITOR_H #define W_QVOUTBOUNDEDITOR_H
#include <list> #include <list>
@ -80,12 +80,16 @@ class RouteEditor : public QDialog, private Ui::RouteEditor
void on_delInboundBtn_clicked(); void on_delInboundBtn_clicked();
void on_addInboundBtn_clicked();
void on_addOutboundBtn_clicked();
private: private:
void ShowRuleDetail(RuleObject rule); void ShowRuleDetail(RuleObject rule);
int currentRuleIndex; int currentRuleIndex;
QString DomainStrategy;
QMap<QString, QStringList> Balancers; QMap<QString, QStringList> Balancers;
QList<RuleObject> rules; QList<RuleObject> rules;
QString DomainStrategy;
// //
QJsonArray inbounds; QJsonArray inbounds;
QJsonArray outbounds; QJsonArray outbounds;

File diff suppressed because it is too large Load Diff