diff --git a/Qv2ray.pro b/Qv2ray.pro index d1e8fd97..46ed8f3a 100644 --- a/Qv2ray.pro +++ b/Qv2ray.pro @@ -14,7 +14,7 @@ CONFIG += c++11 openssl-linked lrelease win32: QMAKE_TARGET_DESCRIPTION = "Qv2ray, a cross-platform v2ray GUI client." win32: QMAKE_TARGET_PRODUCT = "Qv2ray" -VERSION = 1.3 +VERSION = 2.0 DEFINES += "QV_MAJOR_VERSION=\"\\\"$${VERSION}\\\"\"" SOURCES += \ diff --git a/src/Qv2rayBase.h b/src/Qv2rayBase.h index 292acc9e..f8b86aef 100644 --- a/src/Qv2rayBase.h +++ b/src/Qv2rayBase.h @@ -5,7 +5,7 @@ #include "QvTinyLog.h" #include "QvCoreConfigObjects.h" -#define QV2RAY_VERSION_STRING "v" QV_MAJOR_VERSION ".4.2" +#define QV2RAY_VERSION_STRING "v" QV_MAJOR_VERSION ".0.0" #define QV2RAY_CONFIG_VERSION 2 #define QV2RAY_CONFIG_DIR_PATH (Qv2ray::Utils::GetConfigDirPath() + "/") @@ -62,7 +62,8 @@ namespace Qv2ray bool http_useAuth; AccountObject httpAccount; Qv2rayBasicInboundsConfig(): listenip(), socks_port(), socks_useAuth(), socksAccount(), http_port(), http_useAuth(), httpAccount() {} - Qv2rayBasicInboundsConfig(string listen, int socksPort, int httpPort): Qv2rayBasicInboundsConfig() { + Qv2rayBasicInboundsConfig(string listen, int socksPort, int httpPort): Qv2rayBasicInboundsConfig() + { socks_port = socksPort; http_port = httpPort; listenip = listen; @@ -96,7 +97,8 @@ namespace Qv2ray map subscribes; MuxObject mux; Qv2rayConfig(): config_version(QV2RAY_CONFIG_VERSION), runAsRoot(false), logLevel(), proxyDefault(), proxyCN(), withLocalDNS(), inBoundSettings(), configs(), subscribes(), mux() { } - Qv2rayConfig(string lang, string exePath, string assetsPath, int log, Qv2rayBasicInboundsConfig _inBoundSettings): Qv2rayConfig() { + Qv2rayConfig(string lang, string exePath, string assetsPath, int log, Qv2rayBasicInboundsConfig _inBoundSettings): Qv2rayConfig() + { // These settings below are defaults. ignoredVersion = ""; autoStartConfig = ""; diff --git a/src/QvCoreConfigObjects.h b/src/QvCoreConfigObjects.h index 859e003a..f91985c1 100644 --- a/src/QvCoreConfigObjects.h +++ b/src/QvCoreConfigObjects.h @@ -66,7 +66,42 @@ namespace Qv2ray }; // // - namespace TransferSettingObjects + struct RuleObject { + string type; + list domain; + list ip; + string port; + string network; + list source; + list user; + list inboundTag; + string protocol; + string attrs; + string outboundTag; + string balancerTag; + RuleObject() : type("field"), domain(), ip(), port(), network(), source(), user(), inboundTag(), protocol(), attrs(), outboundTag(), balancerTag() {} + XTOSTRUCT(O(type, domain, ip, port, network, source, user, inboundTag, protocol, attrs, outboundTag, balancerTag)) + }; + // + // + struct BalancerObject { + string tag ; + list selector; + BalancerObject() : tag(), selector() {} + XTOSTRUCT(O(tag, selector)) + }; + // + // + struct RoutingObject { + string domainStrategy; + list rules; + list balancers; + RoutingObject() : domainStrategy(), rules(), balancers() {} + XTOSTRUCT(O(domainStrategy, rules, balancers)) + }; + // + // + namespace TSObjects { struct HTTPRequestObject { string version; @@ -200,14 +235,14 @@ namespace Qv2ray struct StreamSettingsObject { string network; string security; - TransferSettingObjects::SockoptObject sockopt; - TransferSettingObjects::TLSObject tlsSettings; - TransferSettingObjects::TCPObject tcpSettings; - TransferSettingObjects::KCPObject kcpSettings; - TransferSettingObjects::WebSocketObject wsSettings; - TransferSettingObjects::HttpObject httpSettings; - TransferSettingObjects::DomainSocketObject dsSettings; - TransferSettingObjects::QuicObject quicSettings; + TSObjects::SockoptObject sockopt; + TSObjects::TLSObject tlsSettings; + TSObjects::TCPObject tcpSettings; + TSObjects::KCPObject kcpSettings; + TSObjects::WebSocketObject wsSettings; + TSObjects::HttpObject httpSettings; + TSObjects::DomainSocketObject dsSettings; + TSObjects::QuicObject quicSettings; StreamSettingsObject(): network("tcp"), security(), sockopt(), tlsSettings(), tcpSettings(), kcpSettings(), wsSettings(), httpSettings(), dsSettings(), quicSettings() {} XTOSTRUCT(O(network, security, sockopt, tcpSettings, tlsSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings)) }; diff --git a/src/QvCoreConfigOperations.h b/src/QvCoreConfigOperations.h index a32c5d2a..9a4973a0 100644 --- a/src/QvCoreConfigOperations.h +++ b/src/QvCoreConfigOperations.h @@ -36,7 +36,7 @@ namespace Qv2ray template QJsonObject GetRootObject(T t) { - auto json = StructToJSONString(t); + auto json = StructToJsonString(t); QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(json.toStdString())); return doc.object(); } diff --git a/src/QvCoreConfigOperations_Convertion.cpp b/src/QvCoreConfigOperations_Convertion.cpp index fa314ea8..eeda5887 100644 --- a/src/QvCoreConfigOperations_Convertion.cpp +++ b/src/QvCoreConfigOperations_Convertion.cpp @@ -7,7 +7,7 @@ namespace Qv2ray bool SaveConnectionConfig(QJsonObject obj, const QString *alias) { QFile config(QV2RAY_CONFIG_DIR_PATH + *alias + QV2RAY_CONNECTION_FILE_EXTENSION); - return StringToFile(JSONToString(obj), &config); + return StringToFile(JsonToString(obj), &config); } // This generates global config containing only one outbound.... @@ -15,7 +15,7 @@ namespace Qv2ray { DROOT QStringRef vmessJsonB64(&str, 8, str.length() - 8); - auto vmessConf = StructFromJSONString(Base64Decode(vmessJsonB64.toString())); + auto vmessConf = StructFromJsonString(Base64Decode(vmessJsonB64.toString())); // // User VMessServerObject::UserObject user; @@ -31,7 +31,7 @@ namespace Qv2ray // VMess root config QJsonObject vConf; QJsonArray vnextArray; - vnextArray.append(JSONFromString(StructToJSONString(serv))); + vnextArray.append(JsonFromString(StructToJsonString(serv))); vConf["vnext"] = vnextArray; // // Stream Settings @@ -72,7 +72,7 @@ namespace Qv2ray QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool overrideInbounds) { - auto root = JSONFromString(StringFromFile(new QFile(sourceFilePath))); + auto root = JsonFromString(StringFromFile(new QFile(sourceFilePath))); if (overrideInbounds) { JSON_ROOT_TRY_REMOVE("inbounds") @@ -92,7 +92,7 @@ namespace Qv2ray foreach (auto conn, connectionNames) { QString jsonString = StringFromFile(new QFile(QV2RAY_CONFIG_DIR_PATH + QString::fromStdString(conn) + QV2RAY_CONNECTION_FILE_EXTENSION)); - QJsonObject connectionObject = JSONFromString(jsonString); + QJsonObject connectionObject = JsonFromString(jsonString); list.insert(QString::fromStdString(conn), connectionObject); } @@ -106,7 +106,7 @@ namespace Qv2ray int StartPreparation(QJsonObject fullConfig) { - QString json = JSONToString(fullConfig); + QString json = JsonToString(fullConfig); StringToFile(json, new QFile(QV2RAY_GENERATED_FILE_PATH)); return 0; } diff --git a/src/QvCoreConfigOperations_Verification.cpp b/src/QvCoreConfigOperations_Verification.cpp index 94f910ff..18ac6b96 100644 --- a/src/QvCoreConfigOperations_Verification.cpp +++ b/src/QvCoreConfigOperations_Verification.cpp @@ -15,7 +15,7 @@ namespace Qv2ray try { QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8); auto vmessString = Base64Decode(vmessJsonB64.toString()); - auto vmessConf = StructFromJSONString(vmessString); + auto vmessConf = StructFromJsonString(vmessString); return 0; } catch (exception *e) { LOG(MODULE_CONNECTION, QObject::tr("#VMessDecodeError").toStdString() << e->what()) diff --git a/src/QvUtils.cpp b/src/QvUtils.cpp index fabdc13e..17367f6a 100644 --- a/src/QvUtils.cpp +++ b/src/QvUtils.cpp @@ -30,10 +30,40 @@ namespace Qv2ray void SaveGlobalConfig() { QFile config(QV2RAY_CONFIG_FILE_PATH); - QString str = StructToJSONString(GetGlobalConfig()); + QString str = StructToJsonString(GetGlobalConfig()); StringToFile(str, &config); } + QString Stringify(list list, QString saperator) + { + QString out; + + foreach (string item, list) { + out.append(QSTRING(item)); + out.append(saperator); + } + + if (out.length() >= 1) + out = out.remove(out.length() - 1, 1); + + return out; + } + + QString Stringify(QList list, QString saperator) + { + QString out; + + foreach (QString item, list) { + out.append(saperator); + out.append(item); + } + + if (out.length() >= 1) + out = out.remove(out.length() - 1, 1); + + return out; + } + bool StringToFile(QString text, QFile *targetFile) { bool override = targetFile->exists(); @@ -48,17 +78,17 @@ namespace Qv2ray QJsonObject JSONFromFile(QFile *sourceFile) { QString json = StringFromFile(sourceFile); - return JSONFromString(json); + return JsonFromString(json); } - QString JSONToString(QJsonObject json) + QString JsonToString(QJsonObject json) { QJsonDocument doc; doc.setObject(json); return doc.toJson(); } - QJsonObject JSONFromString(QString string) + QJsonObject JsonFromString(QString string) { QJsonDocument doc = QJsonDocument::fromJson(string.toUtf8()); return doc.object(); @@ -93,7 +123,7 @@ namespace Qv2ray file.open(QFile::ReadOnly); QTextStream stream(&file); auto str = stream.readAll(); - auto config = StructFromJSONString(str); + auto config = StructFromJsonString(str); SetGlobalConfig(config); file.close(); } diff --git a/src/QvUtils.h b/src/QvUtils.h index 63f851f7..27b9f45d 100644 --- a/src/QvUtils.h +++ b/src/QvUtils.h @@ -33,19 +33,22 @@ namespace Qv2ray bool StringToFile(QString text, QFile *target); QString StringFromFile(QFile *sourceFile); // - QJsonObject JSONFromString(QString string); - QString JSONToString(QJsonObject json); + QJsonObject JsonFromString(QString string); + QString JsonToString(QJsonObject json); + // + QString Stringify(list list, QString saperator = ";"); + QString Stringify(QList list, QString saperator = ";"); // // template - QString StructToJSONString(const TYPE t) + QString StructToJsonString(const TYPE t) { return QString::fromStdString(X::tojson(t, "", 4, ' ')); } // // template - TYPE StructFromJSONString(const QString &str) + TYPE StructFromJsonString(const QString &str) { TYPE v; X::loadjson(str.toStdString(), v, false); diff --git a/src/main.cpp b/src/main.cpp index 405ab5ee..53823631 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,7 +56,9 @@ bool initQv() return false; } } + QFile configFile(QV2RAY_CONFIG_FILE_PATH); + if (!configFile.exists()) { // This is first run! // @@ -71,13 +73,15 @@ bool initQv() LOG(MODULE_INIT, "Created initial config file.") } else { // Some config file upgrades. - auto conf = JSONFromString(StringFromFile(&configFile)); + auto conf = JsonFromString(StringFromFile(&configFile)); auto confVersion = conf["config_version"].toVariant().toString(); auto newVersion = QSTRING(to_string(QV2RAY_CONFIG_VERSION)); - if(QString::compare(confVersion, newVersion) != 0) { + + if (QString::compare(confVersion, newVersion) != 0) { conf = UpgradeConfig(stoi(conf["config_version"].toString().toStdString()), QV2RAY_CONFIG_VERSION, conf); } - auto confObject = StructFromJSONString(JSONToString(conf)); + + auto confObject = StructFromJsonString(JsonToString(conf)); SetGlobalConfig(confObject); SaveGlobalConfig(); LOG(MODULE_INIT, "Loaded config file.") @@ -135,17 +139,18 @@ int main(int argc, char *argv[]) "DEBUG_VERSION" #endif ); - -#ifdef __WIN32 +#ifndef __APPLE__ auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString().toStdString(); auto osslCurVersion = QSslSocket::sslLibraryVersionString().toStdString(); - if (osslCurVersion != osslReqVersion){ + LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion) + + if (osslCurVersion != osslReqVersion) { LOG(MODULE_NETWORK, "Required OpenSSL version: " + osslReqVersion) - LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion) QvMessageBox(nullptr, QObject::tr("DependencyMissing"), QObject::tr("osslDependMissing,PleaseReDownload")); LOG(MODULE_NETWORK, "OpenSSL library MISSING, Quitting.") return -2; } + #endif if (!guard.isSingleInstance()) { @@ -153,6 +158,7 @@ int main(int argc, char *argv[]) QvMessageBox(nullptr, "Qv2ray", QObject::tr("#AnotherInstanceRunning")); return -1; } + // Show MainWindow MainWindow w; return _qApp.exec(); diff --git a/src/w_ConnectionEditWindow.cpp b/src/w_ConnectionEditWindow.cpp index 50420272..b0a6a465 100644 --- a/src/w_ConnectionEditWindow.cpp +++ b/src/w_ConnectionEditWindow.cpp @@ -6,8 +6,6 @@ #include "w_ConnectionEditWindow.h" #include "w_MainWindow.h" -#define GEN_JSON ConnectionEditWindow::on_genJsonBtn_clicked(); - ConnectionEditWindow::ConnectionEditWindow(QWidget *parent) : QDialog(parent), _alias(), @@ -27,7 +25,6 @@ ConnectionEditWindow::ConnectionEditWindow(QWidget *parent) stream = StreamSettingsObject(); OutboundType = "vmess"; ReLoad_GUI_JSON_ModelContent(); - GEN_JSON } ConnectionEditWindow::ConnectionEditWindow(QJsonObject editRootObject, QString alias, QWidget *parent) @@ -39,20 +36,20 @@ ConnectionEditWindow::ConnectionEditWindow(QJsonObject editRootObject, QString a OutboundType = outBoundRoot["protocol"].toString(); if (OutboundType == "vmess") { - vmess = StructFromJSONString(JSONToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); - stream = StructFromJSONString(JSONToString(outBoundRoot["streamSettings"].toObject())); + vmess = StructFromJsonString(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); + stream = StructFromJsonString(JsonToString(outBoundRoot["streamSettings"].toObject())); shadowsocks.port = vmess.port; shadowsocks.address = vmess.address; socks.address = vmess.address; socks.port = vmess.port; } else if (OutboundType == "shadowsocks") { - shadowsocks = StructFromJSONString(JSONToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject())); + shadowsocks = StructFromJsonString(JsonToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject())); vmess.address = shadowsocks.address; vmess.port = shadowsocks.port; socks.address = shadowsocks.address; socks.port = shadowsocks.port; } else if (OutboundType == "socks") { - socks = StructFromJSONString(JSONToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject())); + socks = StructFromJsonString(JsonToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject())); vmess.address = socks.address; vmess.port = socks.port; shadowsocks.address = socks.address; @@ -60,7 +57,6 @@ ConnectionEditWindow::ConnectionEditWindow(QJsonObject editRootObject, QString a } ReLoad_GUI_JSON_ModelContent(); - GEN_JSON } @@ -82,8 +78,8 @@ void ConnectionEditWindow::ReLoad_GUI_JSON_ModelContent() ui->tlsCB->setChecked(stream.security == "tls"); // TCP ui->tcpHeaderTypeCB->setCurrentText(QSTRING(stream.tcpSettings.header.type)); - ui->tcpRequestTxt->setPlainText(StructToJSONString(stream.tcpSettings.header.request)); - ui->tcpRespTxt->setPlainText(StructToJSONString(stream.tcpSettings.header.response)); + ui->tcpRequestTxt->setPlainText(StructToJsonString(stream.tcpSettings.header.request)); + ui->tcpRespTxt->setPlainText(StructToJsonString(stream.tcpSettings.header.response)); // HTTP QString allHosts; @@ -174,7 +170,6 @@ void ConnectionEditWindow::on_ipLineEdit_textEdited(const QString &arg1) vmess.address = arg1.toStdString(); shadowsocks.address = arg1.toStdString(); socks.address = arg1.toStdString(); - GEN_JSON // // No thanks. //if (ui->httpHostTxt->toPlainText() == "") { @@ -194,7 +189,6 @@ void ConnectionEditWindow::on_portLineEdit_textEdited(const QString &arg1) vmess.port = stoi(arg1.toStdString()); shadowsocks.port = stoi(arg1.toStdString()); socks.port = stoi(arg1.toStdString()); - GEN_JSON } } @@ -203,7 +197,6 @@ void ConnectionEditWindow::on_idLineEdit_textEdited(const QString &arg1) if (vmess.users.size() == 0) vmess.users.push_back(VMessServerObject::UserObject()); vmess.users.front().id = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_alterLineEdit_textEdited(const QString &arg1) @@ -211,7 +204,6 @@ void ConnectionEditWindow::on_alterLineEdit_textEdited(const QString &arg1) if (vmess.users.size() == 0) vmess.users.push_back(VMessServerObject::UserObject()); vmess.users.front().alterId = stoi(arg1.toStdString()); - GEN_JSON } void ConnectionEditWindow::on_securityCombo_currentIndexChanged(const QString &arg1) @@ -219,19 +211,16 @@ void ConnectionEditWindow::on_securityCombo_currentIndexChanged(const QString &a if (vmess.users.size() == 0) vmess.users.push_back(VMessServerObject::UserObject()); vmess.users.front().security = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_tranportCombo_currentIndexChanged(const QString &arg1) { stream.network = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_httpPathTxt_textEdited(const QString &arg1) { stream.httpSettings.path = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_httpHostTxt_textChanged() @@ -245,7 +234,6 @@ void ConnectionEditWindow::on_httpHostTxt_textChanged() stream.httpSettings.host.push_back(host.trimmed().toStdString()); } - GEN_JSON BLACK(httpHostTxt) } catch (...) { RED(httpHostTxt) @@ -266,7 +254,6 @@ void ConnectionEditWindow::on_wsHeadersTxt_textChanged() stream.wsSettings.headers.insert(make_pair(content[0].toStdString(), content[1].toStdString())); } - GEN_JSON BLACK(wsHeadersTxt) } catch (...) { RED(wsHeadersTxt) @@ -285,22 +272,19 @@ void ConnectionEditWindow::on_tcpRequestDefBtn_clicked() "AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 " "Safari/601.1.46\"],\"Accept-Encoding\":[\"gzip, deflate\"]," "\"Connection\":[\"keep-alive\"],\"Pragma\":\"no-cache\"}}"); - GEN_JSON } void ConnectionEditWindow::on_tcpRespDefBtn_clicked() { ui->tcpRespTxt->clear(); ui->tcpRespTxt->insertPlainText("{\"version\":\"1.1\",\"status\":\"200\",\"reason\":\"OK\",\"headers\":{\"Content-Type\":[\"application/octet-stream\",\"video/mpeg\"],\"Transfer-Encoding\":[\"chunked\"],\"Connection\":[\"keep-alive\"],\"Pragma\":\"no-cache\"}}"); - GEN_JSON } void ConnectionEditWindow::on_tcpRequestTxt_textChanged() { try { - auto tcpReqObject = StructFromJSONString(ui->tcpRequestTxt->toPlainText()); + auto tcpReqObject = StructFromJsonString(ui->tcpRequestTxt->toPlainText()); stream.tcpSettings.header.request = tcpReqObject; - GEN_JSON BLACK(tcpRequestTxt) } catch (...) { RED(tcpRequestTxt) @@ -310,9 +294,8 @@ void ConnectionEditWindow::on_tcpRequestTxt_textChanged() void ConnectionEditWindow::on_tcpRespTxt_textChanged() { try { - auto tcpRspObject = StructFromJSONString(ui->tcpRespTxt->toPlainText()); + auto tcpRspObject = StructFromJsonString(ui->tcpRespTxt->toPlainText()); stream.tcpSettings.header.response = tcpRspObject; - GEN_JSON BLACK(tcpRespTxt) } catch (...) { RED(tcpRespTxt) @@ -322,15 +305,14 @@ void ConnectionEditWindow::on_tcpRespTxt_textChanged() void ConnectionEditWindow::on_genJsonBtn_clicked() { auto json = GenerateConnectionJson(); - ui->finalJson->setText(JSONToString(json)); } QJsonObject ConnectionEditWindow::GenerateConnectionJson() { // VMess is only a ServerObject, and we need an array { "vnext": [] } QJsonObject settings; - auto mux = JSONFromString(StructToJSONString(GetGlobalConfig().mux)); - auto streaming = JSONFromString(StructToJSONString(stream)); + auto mux = JsonFromString(StructToJsonString(GetGlobalConfig().mux)); + auto streaming = JsonFromString(StructToJsonString(stream)); if (OutboundType == "vmess") { QJsonArray vnext; @@ -355,45 +337,37 @@ QJsonObject ConnectionEditWindow::GenerateConnectionJson() void ConnectionEditWindow::on_tlsCB_stateChanged(int arg1) { stream.security = arg1 == Qt::Checked ? "tls" : "none"; - GEN_JSON } void ConnectionEditWindow::on_soMarkSpinBox_valueChanged(int arg1) { stream.sockopt.mark = arg1; - GEN_JSON } void ConnectionEditWindow::on_tcpFastOpenCB_stateChanged(int arg1) { stream.sockopt.tcpFastOpen = arg1 == Qt::Checked; - GEN_JSON } void ConnectionEditWindow::on_tProxyCB_currentIndexChanged(const QString &arg1) { stream.sockopt.tproxy = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_quicSecurityCB_currentTextChanged(const QString &arg1) { stream.quicSettings.security = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_quicKeyTxt_textEdited(const QString &arg1) { stream.quicSettings.key = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_quicHeaderTypeCB_currentIndexChanged(const QString &arg1) { stream.quicSettings.header.type = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_tcpRequestPrettifyBtn_clicked() { try { - auto tcpReqObject = StructFromJSONString(ui->tcpRequestTxt->toPlainText()); - auto tcpReqObjectStr = StructToJSONString(tcpReqObject); + auto tcpReqObject = StructFromJsonString(ui->tcpRequestTxt->toPlainText()); + auto tcpReqObjectStr = StructToJsonString(tcpReqObject); ui->tcpRequestTxt->setPlainText(tcpReqObjectStr); - GEN_JSON } catch (...) { QvMessageBox(this, tr("#JsonPrettify"), tr("#JsonContainsError")); } @@ -401,10 +375,9 @@ void ConnectionEditWindow::on_tcpRequestPrettifyBtn_clicked() void ConnectionEditWindow::on_tcpRespPrettifyBtn_clicked() { try { - auto tcpRspObject = StructFromJSONString(ui->tcpRespTxt->toPlainText()); - auto tcpRspObjectStr = StructToJSONString(tcpRspObject); + auto tcpRspObject = StructFromJsonString(ui->tcpRespTxt->toPlainText()); + auto tcpRspObjectStr = StructToJsonString(tcpRspObject); ui->tcpRespTxt->setPlainText(tcpRspObjectStr); - GEN_JSON } catch (...) { QvMessageBox(this, tr("#JsonPrettify"), tr("#JsonContainsError")); } @@ -412,62 +385,50 @@ void ConnectionEditWindow::on_tcpRespPrettifyBtn_clicked() void ConnectionEditWindow::on_tcpHeaderTypeCB_currentIndexChanged(const QString &arg1) { stream.tcpSettings.header.type = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_wsPathTxt_textEdited(const QString &arg1) { stream.wsSettings.path = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_kcpMTU_valueChanged(int arg1) { stream.kcpSettings.mtu = arg1; - GEN_JSON } void ConnectionEditWindow::on_kcpTTI_valueChanged(int arg1) { stream.kcpSettings.tti = arg1; - GEN_JSON } void ConnectionEditWindow::on_kcpUploadCapacSB_valueChanged(int arg1) { stream.kcpSettings.uplinkCapacity = arg1; - GEN_JSON } void ConnectionEditWindow::on_kcpCongestionCB_stateChanged(int arg1) { stream.kcpSettings.congestion = arg1 == Qt::Checked; - GEN_JSON } void ConnectionEditWindow::on_kcpDownCapacitySB_valueChanged(int arg1) { stream.kcpSettings.downlinkCapacity = arg1; - GEN_JSON } void ConnectionEditWindow::on_kcpReadBufferSB_valueChanged(int arg1) { stream.kcpSettings.readBufferSize = arg1; - GEN_JSON } void ConnectionEditWindow::on_kcpWriteBufferSB_valueChanged(int arg1) { stream.kcpSettings.writeBufferSize = arg1; - GEN_JSON } void ConnectionEditWindow::on_kcpHeaderType_currentTextChanged(const QString &arg1) { stream.kcpSettings.header.type = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_tranportCombo_currentIndexChanged(int index) { ui->v2rayStackView->setCurrentIndex(index); - GEN_JSON } void ConnectionEditWindow::on_dsPathTxt_textEdited(const QString &arg1) { stream.dsSettings.path = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_finalJson_textChanged() { @@ -487,47 +448,39 @@ void ConnectionEditWindow::on_outBoundTypeCombo_currentIndexChanged(int index) { ui->outboundTypeStackView->setCurrentIndex(index); OutboundType = ui->outBoundTypeCombo->currentText().toLower(); - GEN_JSON } void ConnectionEditWindow::on_ss_emailTxt_textEdited(const QString &arg1) { shadowsocks.email = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_ss_passwordTxt_textEdited(const QString &arg1) { shadowsocks.password = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_ss_encryptionMethod_currentIndexChanged(const QString &arg1) { shadowsocks.method = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_ss_levelSpin_valueChanged(int arg1) { shadowsocks.level = arg1; - GEN_JSON } void ConnectionEditWindow::on_ss_otaCheckBox_stateChanged(int arg1) { shadowsocks.ota = arg1 == Qt::Checked; - GEN_JSON } void ConnectionEditWindow::on_socks_UserNameTxt_textEdited(const QString &arg1) { socks.users.front().user = arg1.toStdString(); - GEN_JSON } void ConnectionEditWindow::on_socks_PasswordTxt_textEdited(const QString &arg1) { socks.users.front().pass = arg1.toStdString(); - GEN_JSON } diff --git a/src/w_ConnectionEditWindow.ui b/src/w_ConnectionEditWindow.ui index 8e89d537..649b103f 100644 --- a/src/w_ConnectionEditWindow.ui +++ b/src/w_ConnectionEditWindow.ui @@ -6,8 +6,8 @@ 0 0 - 911 - 614 + 920 + 570 @@ -18,8 +18,8 @@ - 0 - 0 + 920 + 570 @@ -28,8 +28,8 @@ true - - + + @@ -89,7 +89,7 @@ - + #OutBoundSettings @@ -107,23 +107,9 @@ 0 - + - - - - - #UseTLS - - - - - - - #Enabled - - - + @@ -164,6 +150,12 @@ + + + 0 + 0 + + auto @@ -186,6 +178,20 @@ + + + + #UseTLS + + + + + + + #Enabled + + + @@ -230,7 +236,7 @@ - + #TransportSettings @@ -247,32 +253,7 @@ 0 - - - - - - - - none - - - - - http - - - - - - - - #Type - - - - - + @@ -303,6 +284,12 @@ + + + 0 + 0 + + QPlainTextEdit::NoWrap @@ -316,6 +303,12 @@ + + + 0 + 0 + + QPlainTextEdit::NoWrap @@ -338,6 +331,31 @@ + + + + + + #Type + + + + + + + + none + + + + + http + + + + + + @@ -404,219 +422,211 @@ - + - - - - - #MTU - - - - - - - - 0 - 0 - - - - 576 - - - 1460 - - - 1350 - - - - - - - #TTI (ms) - - - - - - - - 0 - 0 - - - - 10 - - - 100 - - - 50 - - - - - - - #UplinkCapacity (MB/s) - - - - - - - - 0 - 0 - - - - 4096 - - - 5 - - - - - - - #Congestion - - - - - - - #Enabled - - - - + + + #MTU + + - - - - - #DownlinkCapacity (MB/s) - - + + + + 0 + 0 + + + + 576 + + + 1460 + + + 1350 + + + + + + + #TTI (ms) + + + + + + + + 0 + 0 + + + + 10 + + + 100 + + + 50 + + + + + + + #UplinkCapacity (MB/s) + + + + + + + + 0 + 0 + + + + 4096 + + + 5 + + + + + + + #Congestion + + + + + + + #Enabled + + + + + + + #DownlinkCapacity (MB/s) + + + + + + + + 0 + 0 + + + + 4096 + + + 20 + + + + + + + #ReadBufferSize (MB) + + + + + + + + 0 + 0 + + + + 1024 + + + 2 + + + + + + + #WriteBufferSize (MB) + + + + + + + + 0 + 0 + + + + 1024 + + + 2 + + + + + + + #Type + + + + + + + + 0 + 0 + + + + + none + - - - - - 0 - 0 - - - - 4096 - - - 20 - - + + + srtp + - - - - #ReadBufferSize (MB) - - + + + utp + - - - - - 0 - 0 - - - - 1024 - - - 2 - - + + + wechat-video + - - - - #WriteBufferSize (MB) - - + + + dtls + - - - - - 0 - 0 - - - - 1024 - - - 2 - - + + + wireguard + - - - - #Type - - - - - - - - 0 - 0 - - - - - none - - - - - srtp - - - - - utp - - - - - wechat-video - - - - - dtls - - - - - wireguard - - - - - + @@ -929,32 +939,7 @@ - - - - - 0 - 0 - - - - #JsonPreview - - - - - - QTextEdit::NoWrap - - - true - - - - - - - + Qt::Horizontal @@ -979,8 +964,8 @@ accept() - 586 - 523 + 592 + 655 157 @@ -995,8 +980,8 @@ reject() - 654 - 523 + 660 + 655 286 diff --git a/src/w_MainWindow.cpp b/src/w_MainWindow.cpp index ae935ef6..e9c5a336 100644 --- a/src/w_MainWindow.cpp +++ b/src/w_MainWindow.cpp @@ -19,6 +19,7 @@ #include "w_ImportConfig.h" #include "w_ConnectionEditWindow.h" #include "w_MainWindow.h" +#include "w_RouteEditor.h" #define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING "\r\n" @@ -104,7 +105,7 @@ void MainWindow::VersionUpdate(QByteArray &data) { auto conf = GetGlobalConfig(); QString jsonString(data); - QJsonObject root = JSONFromString(jsonString); + QJsonObject root = JsonFromString(jsonString); // QVersionNumber newversion = QVersionNumber::fromString(root["tag_name"].toString("").remove(0, 1)); QVersionNumber current = QVersionNumber::fromString(QSTRING(QV2RAY_VERSION_STRING).remove(0, 1)); @@ -304,6 +305,7 @@ void MainWindow::QTextScrollToBottom() void MainWindow::ShowAndSetConnection(int index, bool SetConnection, bool ApplyConnection) { if (index < 0) return; + auto guiConnectionName = ui->connectionListWidget->item(index)->text(); // --------- BRGIN Show Connection auto outBoundRoot = (connections[guiConnectionName])["outbounds"].toArray().first().toObject(); @@ -312,10 +314,10 @@ void MainWindow::ShowAndSetConnection(int index, bool SetConnection, bool ApplyC ui->_OutBoundTypeLabel->setText(outboundType); if (outboundType == "vmess") { - auto Server = StructFromJSONString(JSONToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); - ui->_hostLabel->setText(QSTRING(Server.address)); - ui->_portLabel->setText(QSTRING(to_string(Server.port))); - auto user = QList::fromStdList(Server.users).first(); + auto x = StructFromJsonString(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); + ui->_hostLabel->setText(QSTRING(x.address)); + ui->_portLabel->setText(QSTRING(to_string(x.port))); + auto user = QList::fromStdList(x.users).first(); auto _configString = tr("#UUID") + ": " + QSTRING(user.id) + "\r\n" + tr("#AlterID") + ": " + QSTRING(to_string(user.alterId)) @@ -323,8 +325,8 @@ void MainWindow::ShowAndSetConnection(int index, bool SetConnection, bool ApplyC + tr("#Transport") + ": " + outBoundRoot["streamSettings"].toObject()["network"].toString(); ui->detailInfoTxt->setPlainText(_configString); } else if (outboundType == "shadowsocks") { - auto x = JSONToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject()); - auto Server = StructFromJSONString(x); + auto x = JsonToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject()); + auto Server = StructFromJsonString(x); ui->_hostLabel->setText(QSTRING(Server.address)); ui->_portLabel->setText(QSTRING(to_string(Server.port))); auto _configString = tr("#Email") + ": " + QSTRING(Server.email) @@ -332,8 +334,8 @@ void MainWindow::ShowAndSetConnection(int index, bool SetConnection, bool ApplyC + tr("#Encryption") + ": " + QSTRING(Server.method); ui->detailInfoTxt->setPlainText(_configString); } else if (outboundType == "socks") { - auto x = JSONToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject()); - auto Server = StructFromJSONString(x); + auto x = JsonToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject()); + auto Server = StructFromJsonString(x); ui->_hostLabel->setText(QSTRING(Server.address)); ui->_portLabel->setText(QSTRING(to_string(Server.port))); auto _configString = tr("#Username") + ": " + QSTRING(Server.users.front().user); @@ -471,14 +473,14 @@ void MainWindow::on_importConfigButton_clicked() { ImportConfigWindow *w = new ImportConfigWindow(this); connect(w, &ImportConfigWindow::s_reload_config, this, &MainWindow::save_reload_globalconfig); - w->show(); + w->exec(); } void MainWindow::on_addConfigButton_clicked() { ConnectionEditWindow *w = new ConnectionEditWindow(this); connect(w, &ConnectionEditWindow::s_reload_config, this, &MainWindow::save_reload_globalconfig); - w->show(); + w->exec(); } void MainWindow::on_editConfigButton_clicked() @@ -491,7 +493,21 @@ void MainWindow::on_editConfigButton_clicked() return; } - ConnectionEditWindow *w = new ConnectionEditWindow(connections.values()[index], connections.keys()[index], this); + ConnectionEditWindow *w = new ConnectionEditWindow(connections[ui->connectionListWidget->currentItem()->text()], ui->connectionListWidget->currentItem()->text(), this); connect(w, &ConnectionEditWindow::s_reload_config, this, &MainWindow::save_reload_globalconfig); - w->show(); + w->exec(); +} + +void MainWindow::on_editConfigAdvButton_clicked() +{ + // Check if we have a connection selected... + auto index = ui->connectionListWidget->currentIndex().row(); + + if (index < 0) { + QvMessageBox(this, tr("#NoConfigSelected"), tr("#PleaseSelectAConfig")); + return; + } + + RouteEditor *w = new RouteEditor(connections[ui->connectionListWidget->currentItem()->text()], ui->connectionListWidget->currentItem()->text(), this); + w->exec(); } diff --git a/src/w_MainWindow.h b/src/w_MainWindow.h index a2095718..aef08ff1 100644 --- a/src/w_MainWindow.h +++ b/src/w_MainWindow.h @@ -57,6 +57,8 @@ class MainWindow : public QMainWindow void on_editConfigButton_clicked(); + void on_editConfigAdvButton_clicked(); + private: void on_action_StartThis_triggered(); void on_action_RenameConnection_triggered(); diff --git a/src/w_MainWindow.ui b/src/w_MainWindow.ui index ebfb0baf..dbf328f2 100644 --- a/src/w_MainWindow.ui +++ b/src/w_MainWindow.ui @@ -298,6 +298,13 @@ + + + + # + + + diff --git a/src/w_RouteEditor.cpp b/src/w_RouteEditor.cpp index d77f5c3e..a96a3ae1 100644 --- a/src/w_RouteEditor.cpp +++ b/src/w_RouteEditor.cpp @@ -1,14 +1,110 @@ #include "w_RouteEditor.h" -#include "ui_w_OutboundEditor.h" +#include "ui_w_RouteEditor.h" -RouteEditor::RouteEditor(QWidget *parent) : +RouteEditor::RouteEditor(QJsonObject connection, const QString alias, QWidget *parent) : QDialog(parent), + root(connection), + rootAlias(alias), ui(new Ui::RouteEditor) { + inbounds = root["inbounds"].toArray(); + outbounds = root["outbounds"].toArray(); + routes = StructFromJsonString(JsonToString(root["routing"].toObject())); ui->setupUi(this); + ui->outboundsList->clear(); + + foreach (auto out, outbounds) { + bool hasTag = out.toObject().contains("tag"); + + if (hasTag) { + ui->outboundsList->addItem(out.toObject()["tag"].toString()); + } else { + ui->outboundsList->addItem(out.toObject()["protocol"].toString()); + } + } + + foreach (auto in, inbounds) { + bool hasTag = in.toObject().contains("tag"); + auto inItem = new QListWidgetItem(); + inItem->setCheckState(Qt::Unchecked); + + if (hasTag) { + inItem->setText(in.toObject()["tag"].toString()); + } else { + inItem->setText(in.toObject()["protocol"].toString()); + } + + ui->inboundsList->addItem(inItem); + } + + foreach (auto route, routes.rules) { + ui->routesTable->insertRow(ui->routesTable->rowCount()); + ui->routesTable->setItem(ui->routesTable->rowCount() - 1, 0, + new QTableWidgetItem(route.inboundTag.size() > 0 ? Stringify(route.inboundTag) : "Any")); + // + auto tmplist = QList::fromStdList(route.ip); + tmplist.append(QList::fromStdList(route.domain)); + // + ui->routesTable->setItem(ui->routesTable->rowCount() - 1, 1, + new QTableWidgetItem(Stringify(tmplist.toStdList()))); + ui->routesTable->setItem(ui->routesTable->rowCount() - 1, 2, + new QTableWidgetItem(QSTRING(route.outboundTag))); + } } RouteEditor::~RouteEditor() { delete ui; } + +void RouteEditor::on_buttonBox_accepted() +{ +} + +void RouteEditor::on_outboundsList_currentRowChanged(int currentRow) +{ + LOG(MODULE_UI, "Outbound selected: " + to_string(currentRow)) + auto outBoundRoot = outbounds[currentRow].toObject(); + ui->outboundTagLabel->setText(outBoundRoot.contains("tag") ? outBoundRoot["tag"].toString() : tr("#NoTag")); + auto outboundType = outBoundRoot["protocol"].toString(); + ui->outboundTypeLabel->setText(outboundType); + + if (outboundType == "vmess") { + auto x = StructFromJsonString(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); + ui->outboundAddressLabel->setText(QSTRING(x.address)); + ui->outboundPortLabel->setText(QSTRING(to_string(x.port))); + } else if (outboundType == "shadowsocks") { + auto x = JsonToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject()); + auto Server = StructFromJsonString(x); + ui->outboundAddressLabel->setText(QSTRING(Server.address)); + ui->outboundPortLabel->setText(QSTRING(to_string(Server.port))); + } else if (outboundType == "socks") { + auto x = JsonToString(outBoundRoot["settings"].toObject()["servers"].toArray().first().toObject()); + auto Server = StructFromJsonString(x); + ui->outboundAddressLabel->setText(QSTRING(Server.address)); + ui->outboundPortLabel->setText(QSTRING(to_string(Server.port))); + } +} + +void RouteEditor::on_inboundsList_currentRowChanged(int currentRow) +{ + LOG(MODULE_UI, "Inbound selected: " + to_string(currentRow)) + auto inBoundRoot = inbounds[currentRow].toObject(); + ui->inboundTagLabel->setText(inBoundRoot.contains("tag") ? inBoundRoot["tag"].toString() : tr("#NoTag")); + ui->inboundTypeLabel->setText(inBoundRoot["protocol"].toString()); + ui->inboundAddressLabel->setText(inBoundRoot["listen"].toString()); + ui->inboundPortLabel->setText(inBoundRoot["port"].toVariant().toString()); +} + +void RouteEditor::on_routesTable_cellClicked(int row, int column) +{ + Q_UNUSED(column) + auto outboundTag = ui->routesTable->item(row, 2)->text(); + ui->outboundsList->setCurrentItem(ui->outboundsList->findItems(outboundTag, Qt::MatchExactly).first()); + // + auto inboundTagList = ui->routesTable->item(row, 0)->text(); + bool isAnyInbounds = inboundTagList == "any"; + + if (isAnyInbounds) { + } +} diff --git a/src/w_RouteEditor.h b/src/w_RouteEditor.h index 16bf6037..8f33fb88 100644 --- a/src/w_RouteEditor.h +++ b/src/w_RouteEditor.h @@ -1,7 +1,11 @@ #ifndef W_QVOUTBOUNDEDITOR_H #define W_QVOUTBOUNDEDITOR_H +#include #include +#include +#include +#include "QvUtils.h" namespace Ui { @@ -13,10 +17,24 @@ class RouteEditor : public QDialog Q_OBJECT public: - explicit RouteEditor(QWidget *parent = nullptr); + explicit RouteEditor(QJsonObject connection, const QString alias, QWidget *parent = nullptr); ~RouteEditor(); + private slots: + void on_buttonBox_accepted(); + + void on_outboundsList_currentRowChanged(int currentRow); + + void on_inboundsList_currentRowChanged(int currentRow); + + void on_routesTable_cellClicked(int row, int column); + private: + QJsonArray inbounds; + QJsonArray outbounds; + RoutingObject routes; + QJsonObject root; + QString rootAlias; Ui::RouteEditor *ui; }; diff --git a/src/w_RouteEditor.ui b/src/w_RouteEditor.ui index 2e5f9739..68b76f2e 100644 --- a/src/w_RouteEditor.ui +++ b/src/w_RouteEditor.ui @@ -24,10 +24,13 @@ - + + + QAbstractItemView::NoEditTriggers + - #Type + #InBounds @@ -136,11 +139,7 @@ - - - QAbstractItemView::MultiSelection - - + @@ -191,7 +190,7 @@ - TextLabel + @@ -205,7 +204,35 @@ - TextLabel + + + + + + + + #Address + + + + + + + #Port + + + + + + + + + + + + + + @@ -215,7 +242,7 @@ - + @@ -269,14 +296,14 @@ #OutboundDetail - + #Tag - + @@ -320,45 +347,45 @@ - + #Type - + #Address - + #Port - + - xx - - - - - - - xx + + + + + + + + - xx +