From d3e3f14ae2e7c3e33e7c45fbe392b54ed844b02e Mon Sep 17 00:00:00 2001 From: "Leroy.H.Y" Date: Wed, 3 Jul 2019 00:18:39 +0800 Subject: [PATCH] [Added][Fixed] Added JSON parse libraries, and fixed namespace structure. Signed-off-by: Leroy.H.Y Former-commit-id: 7aaff60ff43e1d3640adede4cd86b5b8d967bc28 --- .appveyor.yml | 1 + .gitmodules | 3 + .travis.yml | 1 + 3rdparty/jsoncons | 1 + Hv2ray.pro | 53 +- src/HUtils.h | 46 ++ src/{utils.cpp => Hutils.cpp} | 54 +- src/Hv2ConfigObject.h | 387 +++++++++++ src/constants.h | 15 - src/main.cpp | 136 ++-- src/runguard.cpp | 124 ++-- src/runguard.h | 38 +- src/utils.h | 15 - src/vinteract.cpp | 128 ++-- src/vinteract.h | 44 +- src/w_ConnectionEditWindow.cpp | 50 +- src/w_ConnectionEditWindow.h | 45 +- src/w_ConnectionEditWindow.ui | 8 +- src/w_ImportConfig.cpp | 215 +++--- src/w_ImportConfig.h | 44 +- src/w_ImportConfig.ui | 8 +- src/w_MainWindow.cpp | 513 +++++++------- src/w_MainWindow.h | 94 +-- src/w_MainWindow.ui | 4 +- src/w_PrefrencesWindow.cpp | 299 ++++---- src/w_PrefrencesWindow.h | 50 +- src/w_PrefrencesWindow.ui | 8 +- translations/en-US.ts | 1164 ++++++++++++++++++++++---------- translations/zh-CN.ts | 1164 ++++++++++++++++++++++---------- 29 files changed, 3021 insertions(+), 1691 deletions(-) create mode 100644 .gitmodules create mode 160000 3rdparty/jsoncons create mode 100644 src/HUtils.h rename src/{utils.cpp => Hutils.cpp} (60%) create mode 100644 src/Hv2ConfigObject.h delete mode 100644 src/constants.h delete mode 100644 src/utils.h diff --git a/.appveyor.yml b/.appveyor.yml index b6d19aa9..d462cdee 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,6 +2,7 @@ install: - set QTDIR=C:\Qt\5.10\mingw53_32 - choco install -y InnoSetup - set PATH=%QTDIR%\bin;C:\Qt\Tools\mingw730_32\bin;%PATH%;"C:\Program Files (x86)\Inno Setup 5" + - git submodule update --init build_script: - mkdir python37 && xcopy C:\Python37 python37 /E /H /Q diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..98496f5f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "3rdparty/jsoncons"] + path = 3rdparty/jsoncons + url = https://github.com/danielaparker/jsoncons diff --git a/.travis.yml b/.travis.yml index f2b2dcce..c362f953 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ before_script: - if [ "$BADGE" = "osx" ]; then export PATH="/usr/local/opt/qt/bin:$PATH"; fi script: + - git submodule update --init - lrelease ./Hv2ray.pro - mkdir build && cd ./build - QT_SELECT=5 QTDIR=/usr/share/qt5 qmake ../ diff --git a/3rdparty/jsoncons b/3rdparty/jsoncons new file mode 160000 index 00000000..11d0da64 --- /dev/null +++ b/3rdparty/jsoncons @@ -0,0 +1 @@ +Subproject commit 11d0da64cf9e8725aa9963c307c8df4957359eef diff --git a/Hv2ray.pro b/Hv2ray.pro index 3d2e4fc6..c5eb7d2b 100644 --- a/Hv2ray.pro +++ b/Hv2ray.pro @@ -22,44 +22,49 @@ DEFINES += QT_DEPRECATED_WARNINGS # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 -CONFIG += c++11 +CONFIG += c++17 +QMAKE_CXXFLAGS += -std=c++17 SOURCES += \ - ./src/w_MainWindow.cpp \ - ./src/w_ConnectionEditWindow.cpp \ - ./src/w_ImportConfig.cpp \ - ./src/w_PrefrencesWindow.cpp \ - ./src/main.cpp \ - ./src/vinteract.cpp \ - ./src/utils.cpp \ - ./src/runguard.cpp + src/Hutils.cpp \ + src/w_MainWindow.cpp \ + src/w_ConnectionEditWindow.cpp \ + src/w_ImportConfig.cpp \ + src/w_PrefrencesWindow.cpp \ + src/main.cpp \ + src/vinteract.cpp \ + src/runguard.cpp HEADERS += \ - ./src/w_MainWindow.h \ - ./src/w_ConnectionEditWindow.h \ - ./src/w_ImportConfig.h \ - ./src/w_PrefrencesWindow.h \ - ./src/constants.h \ - ./src/vinteract.h \ - ./src/utils.h \ - ./src/runguard.h + src/HUtils.h \ + src/Hv2ConfigObject.h \ + src/w_MainWindow.h \ + src/w_ConnectionEditWindow.h \ + src/w_ImportConfig.h \ + src/w_PrefrencesWindow.h \ + src/vinteract.h \ + src/runguard.h FORMS += \ - ./src/w_MainWindow.ui \ - ./src/w_ConnectionEditWindow.ui \ - ./src/w_ImportConfig.ui \ - ./src/w_PrefrencesWindow.ui + src/w_MainWindow.ui \ + src/w_ConnectionEditWindow.ui \ + src/w_ImportConfig.ui \ + src/w_PrefrencesWindow.ui RESOURCES += \ - ./resources.qrc + resources.qrc TRANSLATIONS += \ - ./translations/zh-CN.ts \ - ./translations/en-US.ts + translations/zh-CN.ts \ + translations/en-US.ts RC_ICONS += ./icons/Hv2ray.ico +INCLUDEPATH += 3rdparty/\ + 3rdparty/jsoncons/include + + # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin diff --git a/src/HUtils.h b/src/HUtils.h new file mode 100644 index 00000000..a43fb854 --- /dev/null +++ b/src/HUtils.h @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Hv2ConfigObject.h" + +#ifndef UTILS_H +#define UTILS_H + +namespace Hv2ray::Utils +{ + QJsonObject switchJsonArrayObject(QJsonObject objest, QString value); + QJsonObject findValueFromJsonArray(QJsonArray arr, QString key, QString val); + QJsonObject loadRootObjFromConf(); + QJsonArray getInbounds(); + void showWarnMessageBox(QWidget *parent, QString title, QString text); + void overrideInbounds(QString path); + int getIndexByValue(QJsonArray array, QString key, QString val); + + QStringList getAllFilesList(QDir *dir); + bool hasFile(QDir *dir, QString fileName); + + template + QString StructToJSON(const TYPE &t) + { + string s; + encode_json(t, s, indenting::indent); + return QString::fromStdString(s); + } + + template + TYPE StructFromJSON(const std::string &str) + { + TYPE v = decode_json(str); + return v; + } +} + +#endif // UTILS_H diff --git a/src/utils.cpp b/src/Hutils.cpp similarity index 60% rename from src/utils.cpp rename to src/Hutils.cpp index 7b2a2e6f..ae138047 100644 --- a/src/utils.cpp +++ b/src/Hutils.cpp @@ -1,31 +1,27 @@ -#include -#include -#include -#include -#include -#include +#include "HUtils.h" -#include "utils.h" +using namespace Hv2ray; -QJsonObject switchJsonArrayObject(QJsonObject obj, QString value) +QJsonObject Utils::switchJsonArrayObject(QJsonObject obj, QString value) { QJsonObject returnObj = obj.value(value).isNull() - ? obj.value(value).toObject() - : obj.value(value).toArray().first().toObject(); + ? obj.value(value).toObject() + : obj.value(value).toArray().first().toObject(); return returnObj; } -QJsonObject findValueFromJsonArray(QJsonArray arr, QString key, QString val) +QJsonObject Utils::findValueFromJsonArray(QJsonArray arr, QString key, QString val) { for (const auto obj : arr) { if (obj.toObject().value(key).toString() == val) { return obj.toObject(); } } + return QJsonObject(); } -QJsonObject loadRootObjFromConf() +QJsonObject Utils::loadRootObjFromConf() { QFile globalConfigFile("Hv2ray.conf"); globalConfigFile.open(QIODevice::ReadOnly); @@ -36,25 +32,19 @@ QJsonObject loadRootObjFromConf() return rootObj; } -QJsonArray getInbounds() +QJsonArray Utils::getInbounds() { QJsonArray inbounds; inbounds = loadRootObjFromConf().value("inbounds").toArray(); return inbounds; } -bool getRootEnabled() -{ - return loadRootObjFromConf().value("v2suidEnabled").toBool(); -} - - -void showWarnMessageBox(QWidget* parent, QString title, QString text) +void Utils::showWarnMessageBox(QWidget *parent, QString title, QString text) { QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0); } -void overrideInbounds(QString path) +void Utils::overrideInbounds(QString path) { QFile confFile(path); confFile.open(QIODevice::ReadOnly); @@ -74,15 +64,29 @@ void overrideInbounds(QString path) confFile.close(); } -int getIndexByValue(QJsonArray array, QString key, QString val) +int Utils::getIndexByValue(QJsonArray array, QString key, QString val) { QJsonArray::iterator it; int index = 0; - for(it = array.begin(); it != array.end(); it ++) { - if(it->toObject().value(key) == val) { + + for (it = array.begin(); it != array.end(); it++) { + if (it->toObject().value(key) == val) { return index; } - index ++; + + index++; } + return -1; } + +/// Get file list in a Dir +QStringList Utils::getAllFilesList(QDir *dir) +{ + return dir->entryList(QStringList() << "*" << "*.*", QDir::Hidden | QDir::Files); +} + +bool Utils::hasFile(QDir *dir, QString fileName) +{ + return getAllFilesList(dir).indexOf(fileName) >= 0; +} diff --git a/src/Hv2ConfigObject.h b/src/Hv2ConfigObject.h new file mode 100644 index 00000000..da4b015b --- /dev/null +++ b/src/Hv2ConfigObject.h @@ -0,0 +1,387 @@ +#include +#include +#include +#include +#include + +#define USE_JSON_CONS +#ifdef USE_JSON_CONS +#include +#else +#include +using namespace x2struct; +#endif +#ifndef V2CONFIG_H +#define V2CONFIG_H + +// Macros +#define HV2RAY_CONFIG_DIR_NAME "/.hv2ray" + +using namespace std; +using namespace jsoncons; // for convenience +/*------------------------------------------------------------------------------------------------------------*/ + +namespace Hv2ray::V2ConfigModels +{ + struct LogObject { + string access; + string error; + string loglevel; + LogObject(): access(), error(), loglevel() {} + //XTOSTRUCT(O(access, error, loglevel)) + }; + + struct ApiObject { + string tag; + list services; + ApiObject() : tag(), services() {} + //XTOSTRUCT(O(tag, services)) + }; + + struct ServerObject { + string address; + int port; + list domains; + ServerObject(): address(), port(), domains() {} + //XTOSTRUCT(O(address, port, domains)) + }; + + struct DnsObject { + map hosts; + tuple> servers; + DnsObject(): hosts(), servers() {} + //XTOSTRUCT(O(hosts, servers)) + }; + + struct RuleObject { + string type = "field"; + list domain; + list ip; + string port; + string network; + list source; + list user; + string inboundTag; + string protocol; + string attrs; + RuleObject() : type(), domain(), ip(), port(), network(), source(), user(), inboundTag(), protocol(), attrs() {} + //XTOSTRUCT(O(type, domain, ip, port, network, source, user, inboundTag, protocol, attrs)) + }; + 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)) + }; + + struct SystemPolicyObject { + bool statsInboundUplink; + bool statsInboundDownlink; + SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink() {} + //XTOSTRUCT(O(statsInboundUplink, statsInboundDownlink)) + }; + + struct LevelPolicyObject { + int handshake; + int connIdle; + int uplinkOnly; + int downlinkOnly; + bool statsUserUplink; + bool statsUserDownlink; + int bufferSize; + LevelPolicyObject(): handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize() {} + //XTOSTRUCT(O(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize)) + }; + struct PolicyObject { + map level; + list system; + PolicyObject(): level(), system() {} + //XTOSTRUCT(O(level, system)) + }; + + struct HTTPRequestObject { + string version; + string method; + list path; + map> headers; + HTTPRequestObject(): version(), method(), path(), headers() {} + //XTOSTRUCT(O(version, method, path, headers)) + }; + + struct HTTPResponseObject { + string version; + string status; + string reason; + map> headers; + HTTPResponseObject(): version(), status(), reason(), headers() {} + //XTOSTRUCT(O(version, status, reason, headers)) + }; + + struct TCPHeader_M_Object { + string type; + HTTPRequestObject request; + HTTPResponseObject response; + TCPHeader_M_Object(): type(), request(), response() {} + //XTOSTRUCT(O(type, request, response)) + }; + + struct TCPObject { + TCPHeader_M_Object header; + TCPObject(): header() {} + //XTOSTRUCT(O(header)) + }; + + struct HeaderObject { + string type; + HeaderObject(): type() {} + //XTOSTRUCT(O(type)) + }; + + struct KCPObject { + int mtu; + int tti; + int uplinkCapacity; + int downlinkCapacity; + bool congestion; + int readBufferSize; + int writeBufferSize; + HeaderObject header; + KCPObject(): mtu(), tti(), uplinkCapacity(), downlinkCapacity(), congestion(), readBufferSize(), writeBufferSize(), header() {} + //XTOSTRUCT(O(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header)) + }; + + + struct WebSocketObject { + string path; + map headers; + WebSocketObject(): path(), headers() {} + //XTOSTRUCT(O(path, headers)) + }; + + struct HttpObject { + list host; + string path; + HttpObject() : host(), path() {} + //XTOSTRUCT(O(host, path)) + }; + + struct DomainSocketObject { + string path; + DomainSocketObject(): path() {} + //XTOSTRUCT(O(path)) + }; + + struct QuicObject { + string security; + string key; + HeaderObject header; + QuicObject(): security(), key(), header() {} + //XTOSTRUCT(O(security, key, header)) + }; + + struct TransportObject { + TCPObject tcpSettings; + KCPObject kcpSettings; + WebSocketObject wsSettings; + HttpObject httpSettings; + DomainSocketObject dsSettings; + QuicObject quicSettings; + TransportObject(): tcpSettings(), kcpSettings(), wsSettings(), httpSettings(), dsSettings(), quicSettings() {} + //XTOSTRUCT(O(tcpSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings)) + }; + + struct SniffingObject { + bool enabled; + string destOverride; + SniffingObject(): enabled(), destOverride() {} + //XTOSTRUCT(O(enabled, destOverride)) + }; + + struct AllocateObject { + string strategy; + int refresh; + int concurrency; + AllocateObject(): strategy(), refresh(), concurrency() {} + //XTOSTRUCT(O(strategy, refresh, concurrency)) + }; + + struct InboundObject { + int port; + string listen; + string protocol; + string settings; + TransportObject streamSettings; + string tag; + SniffingObject sniffing; + AllocateObject allocate; + InboundObject(): port(), listen(), protocol(), settings(), streamSettings(), tag(), sniffing(), allocate() {} + //XTOSTRUCT(O(port, listen, protocol, settings, streamSettings, tag, sniffing, allocate)) + }; + + struct ProxySettingsObject { + string tag; + ProxySettingsObject(): tag() {} + //XTOSTRUCT(O(tag)) + }; + + struct MuxObject { + bool enabled; + int concurrency; + MuxObject(): enabled(), concurrency() {} + //XTOSTRUCT(O(enabled, concurrency)) + }; + + struct OutboundObject { + string sendThrough; + string protocol; + string settings; + string tag; + TransportObject streamSettings; + ProxySettingsObject proxySettings; + MuxObject mux; + OutboundObject(): sendThrough(), protocol(), settings(), tag(), streamSettings(), proxySettings(), mux() {} + //XTOSTRUCT(O(sendThrough, protocol, settings, tag, streamSettings, proxySettings, mux)) + }; + + struct StatsObject { + bool _; // Placeholder... + StatsObject(): _() {} + }; + + struct BridgeObject { + string tag; + string domain; + BridgeObject() : tag(), domain() {} + //XTOSTRUCT(O(tag, domain)) + }; + + struct PortalObject { + string tag; + string domain; + PortalObject() : tag(), domain() {} + //XTOSTRUCT(O(tag, domain)) + }; + + struct ReverseObject { + list bridges; + list portals; + ReverseObject() : bridges(), portals() {} + //XTOSTRUCT(O(bridges, portals)) + }; + struct RootObject { + LogObject log; + ApiObject api; + DnsObject dns; + RoutingObject routing; + list inbounds; + list outbounds; + TransportObject transport; + StatsObject stats; + ReverseObject reverse; + RootObject(): log(), api(), dns(), routing(), inbounds(), outbounds(), transport(), stats(), reverse() {} + //XTOSTRUCT(O(log, api, dns, routing, inbounds, outbounds, transport, stats, reverse)) + }; +} + +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::LogObject, access, error, loglevel) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::ApiObject, tag, services) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::ServerObject, address, port, domains) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::DnsObject, hosts, servers) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::RuleObject, type, domain, ip, port, network, source, user, inboundTag, protocol, attrs) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::BalancerObject, tag, selector) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::RoutingObject, domainStrategy, rules, balancers) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::SystemPolicyObject, statsInboundUplink, statsInboundDownlink) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::LevelPolicyObject, handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::PolicyObject, level, system) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::HTTPRequestObject, version, method, path, headers) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::HTTPResponseObject, version, status, reason, headers) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::TCPHeader_M_Object, type, request, response) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::TCPObject, header) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::HeaderObject, type) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::KCPObject, mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::WebSocketObject, path, headers) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::HttpObject, host, path) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::DomainSocketObject, path) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::QuicObject, security, key, header) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::TransportObject, tcpSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::SniffingObject, enabled, destOverride) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::AllocateObject, strategy, refresh, concurrency) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::InboundObject, port, listen, protocol, settings, streamSettings, tag, sniffing, allocate) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::ProxySettingsObject, tag) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::MuxObject, enabled, concurrency) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::OutboundObject, sendThrough, protocol, settings, tag, streamSettings, proxySettings, mux) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::StatsObject, _) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::BridgeObject, tag, domain) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::PortalObject, tag, domain) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::ReverseObject, bridges, portals) +JSONCONS_MEMBER_TRAITS_DECL(Hv2ray::V2ConfigModels::RootObject, log, api, dns, routing, inbounds, outbounds, transport, stats, reverse) + + +namespace Hv2ray::HConfigModels +{ + struct HInbondSetting { + bool enabled; + string ip; + int port; + bool useAuthentication; + string authUsername; + string authPassword; + HInbondSetting() {} + HInbondSetting(bool _enabled, string _ip, int _port) + : ip(_ip), authUsername(""), authPassword("") + { + enabled = _enabled; + port = _port; + useAuthentication = false; + } + HInbondSetting(bool _enabled, string _ip, int _port, string _username, string _password) + : ip(_ip), authUsername(_username), authPassword(_password) + { + enabled = _enabled; + port = _port; + useAuthentication = true; + } + //XTOSTRUCT(O(enabled, ip, port, useAuthentication, authUsername, authPassword)) + }; + + struct Hv2Config { + string language; + bool runAsRoot; + string logLevel; + //Hv2ray::V2ConfigModels::MuxObject muxSetting; + HInbondSetting httpSetting; + HInbondSetting socksSetting; + Hv2Config() {} + Hv2Config(string lang, const bool _runAsRoot, const string _loglevel, HInbondSetting _http, HInbondSetting _socks) + : httpSetting(_http), + socksSetting(_socks) + + { + language = lang; + runAsRoot = _runAsRoot; + logLevel = _loglevel; + } + //XTOSTRUCT(O(language, runAsRoot, logLevel, httpSetting, socksSetting)) + }; +} +using namespace Hv2ray; +JSONCONS_MEMBER_TRAITS_DECL(HConfigModels::Hv2Config, language, runAsRoot, logLevel, httpSetting, socksSetting) +JSONCONS_MEMBER_TRAITS_DECL(HConfigModels::HInbondSetting, enabled, ip, port, useAuthentication, authUsername, authPassword) + +namespace Hv2ray +{ + /// ConfigGlobalConfigthis is platform-independent as it's solved to be in the best + /// place at first in main.cpp + static QDir ConfigDir; + static HConfigModels::Hv2Config GlobalConfig; +} +#endif // V2CONFIG_H + diff --git a/src/constants.h b/src/constants.h deleted file mode 100644 index c75d92db..00000000 --- a/src/constants.h +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -#ifndef CONSTANTS_H -#define CONSTANTS_H - -// Macros -#define HV2RAY_CONFIG_DIR_NAME ".hv2ray" - - -namespace Hv2rayUtils { - static QDir ConfigDir; -} // namespace Hv2rayConsts - -#endif // CONSTANTS_H diff --git a/src/main.cpp b/src/main.cpp index a0e5892e..4aa79f0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,100 +1,112 @@ #include -#include -#include #include +#include #include -#include -#include -#include #include -#include +#include +#include #include +#include +#include #include "runguard.h" -#include "utils.h" -#include "w_MainWindow.h" +#include "HUtils.h" +#include "Hv2ConfigObject.h" #include "w_ConnectionEditWindow.h" -#include "constants.h" +#include "w_MainWindow.h" using namespace std; -using namespace Hv2rayUtils; +using namespace Hv2ray; +using namespace Hv2ray::HConfigModels; -void firstRunCheck() +bool firstRunCheck() { - ConfigDir = QDir(QDir::homePath() + HV2RAY_CONFIG_DIR_NAME); + /// Hv2ray Config Path. + QString configPath = ""; +#if defined(__WIN32) || defined(__APPLE__) + // For Windows and MacOS, there's no such 'installation' of a software + // package, So as what ShadowSocks and v2rayX does, save config files next to + // the executable. + configPath = HV2RAY_CONFIG_DIR_NAME; +#else + // However, for linux, this software can be and/or will be provided as a + // package and install to whatever /usr/bin or /usr/local/bin or even /opt/ + // Thus we save config files in the user's home directory. + configPath = QDir::homePath() + HV2RAY_CONFIG_DIR_NAME; +#endif + ConfigDir = QDir(configPath); - if(!ConfigDir.exists()) { - QDir(QDir::homePath()).mkdir(".hv2ray"); - qDebug() << "Config directory created."; + if (!ConfigDir.exists()) { + auto result = QDir().mkdir(configPath); + + if (result) { + qDebug() << "Created hv2ray config file path at: " + configPath; + } else { + // We cannot continue as it failed to create a dir. + qDebug() << "Failed to create config file folder under " + configPath; + return false; + } } - QFileInfo hvConfInfo("conf/Hv2ray.config.json"); + if (!Utils::hasFile(&ConfigDir, ".initialised")) { + // This is first run! + // These below genenrated very basic global config. + HInbondSetting inHttp = HInbondSetting(true, "127.0.0.1", 8080); + HInbondSetting inSocks = HInbondSetting(true, "127.0.0.1", 1080); + GlobalConfig = Hv2Config("zh-CN", false, "info", inHttp, inSocks); + QString jsonConfig = Utils::StructToJSON(GlobalConfig); + QFile configFile(configPath + "/hv2ray.conf"); - // First Run? - if(!hvConfInfo.exists()) { - QFile confFile("conf/Hv2ray.config.json"); - if(!confFile.open(QIODevice::ReadWrite)) { - qDebug() << "Can not open Hv2ray.conf.json for read and write."; + if (!configFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to create main config file."; + return false; } - QJsonObject settings; - settings.insert("auth", "noauth"); - settings.insert("udp", true); - settings.insert("ip", "127.0.0.1"); - - QJsonObject socks; - socks.insert("settings", QJsonValue(settings)); - socks.insert("tag", "socks-in"); - socks.insert("port", 1080); - socks.insert("listen", "127.0.0.1"); - socks.insert("protocol", "socks"); - - QJsonArray inbounds; - inbounds.append(socks); - - QJsonObject rootObj; - rootObj.insert("inbounds", QJsonValue(inbounds)); - rootObj.insert("v2suidEnabled", false); - - QJsonDocument defaultConf; - defaultConf.setObject(rootObj); - - QByteArray byteArray = defaultConf.toJson(QJsonDocument::Indented); - confFile.write(byteArray); - confFile.close(); + QTextStream stream(&configFile); + stream << jsonConfig; + stream.flush(); + configFile.close(); + // Create Placeholder for initialise indicator. + QFile initPlaceHolder(configPath + "/.initialised"); + initPlaceHolder.open(QFile::WriteOnly); + initPlaceHolder.close(); } + + return true; } int main(int argc, char *argv[]) { QApplication _qApp(argc, argv); - QTranslator translator; - if (translator.load(":/translations/zh-CN.qm", "translations")) - { - cout << "Loaded Chinese translations" << endl; - } - else if (translator.load(":/translations/en-US.qm", "translations")){ - cout << "Loaded English translations" << endl; + + // + if (translator.load(":/translations/zh-CN.qm", "translations")) { + cout << "Loaded zh-CN translations" << endl; + } else if (translator.load(":/translations/en-US.qm", "translations")) { + cout << "Loaded en-US translations" << endl; } else { - showWarnMessageBox(nullptr, "Failed to load translations", - "Failed to load translations, user experience may be downgraded. \r\n \ - 无法加载语言文件,用户体验可能会降级."); + Utils::showWarnMessageBox( + nullptr, "Failed to load translations 无法加载语言文件", + "Failed to load translations, user experience may be downgraded. \r\n" + "无法加载语言文件,用户体验可能会降级."); } _qApp.installTranslator(&translator); - RunGuard guard("Hv2ray-Instance-Identifier"); - if(!guard.isSingleInstance()) { - showWarnMessageBox(nullptr, QObject::tr("Hv2Ray"), QObject::tr("AnotherInstanceRunning")); + + if (!guard.isSingleInstance()) { + Utils::showWarnMessageBox(nullptr, QObject::tr("Hv2Ray"), QObject::tr("AnotherInstanceRunning")); return -1; } + // GlobalConfig = StructFromJSON(""); + // Set file startup path as Path + // WARNING: This may be changed in the future. QDir::setCurrent(QFileInfo(QCoreApplication::applicationFilePath()).path()); - firstRunCheck(); - MainWindow w; - + // Show MainWindow + Ui::MainWindow w; w.show(); return _qApp.exec(); } diff --git a/src/runguard.cpp b/src/runguard.cpp index 486941d1..08499903 100644 --- a/src/runguard.cpp +++ b/src/runguard.cpp @@ -1,77 +1,81 @@ #include #include "runguard.h" - -//from https://stackoverflow.com/a/28172162 -namespace +namespace Hv2ray { - QString generateKeyHash( const QString& key, const QString& salt ) + //from https://stackoverflow.com/a/28172162 + QString RunGuard::generateKeyHash(const QString &key, const QString &salt) { QByteArray data; - data.append( key.toUtf8() ); - data.append( salt.toUtf8() ); - data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); + data.append(key.toUtf8()); + data.append(salt.toUtf8()); + data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex(); return data; } - -} - - -RunGuard::RunGuard( const QString& key ) - : key( key ) - , memLockKey( generateKeyHash( key, "_memLockKey" ) ) - , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) - , sharedMem( sharedmemKey ) - , memLock( memLockKey, 1 ) -{ - memLock.acquire(); + RunGuard::RunGuard(const QString &key) + : key(key) + , memLockKey(generateKeyHash(key, "_memLockKey")) + , sharedmemKey(generateKeyHash(key, "_sharedmemKey")) + , sharedMem(sharedmemKey) + , memLock(memLockKey, 1) { - QSharedMemory fix( sharedmemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/ - fix.attach(); + memLock.acquire(); + { + QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/ + fix.attach(); + } + memLock.release(); } - memLock.release(); -} -RunGuard::~RunGuard() -{ - release(); -} - -bool RunGuard::isAnotherRunning() -{ - if ( sharedMem.isAttached() ) { - return false; - } - memLock.acquire(); - const bool isRunning = sharedMem.attach(); - if ( isRunning ) { - sharedMem.detach(); - } - memLock.release(); - return isRunning; -} - -bool RunGuard::isSingleInstance() -{ - if ( isAnotherRunning() ) { // Extra check - return false; - } - memLock.acquire(); - const bool result = sharedMem.create( sizeof( quint64 ) ); - memLock.release(); - if ( !result ) { + RunGuard::~RunGuard() + { release(); - return false; } - return true; -} -void RunGuard::release() -{ - memLock.acquire(); - if ( sharedMem.isAttached() ) { - sharedMem.detach(); + bool RunGuard::isAnotherRunning() + { + if (sharedMem.isAttached()) { + return false; + } + + memLock.acquire(); + const bool isRunning = sharedMem.attach(); + + if (isRunning) { + sharedMem.detach(); + } + + memLock.release(); + return isRunning; + } + + bool RunGuard::isSingleInstance() + { + if (isAnotherRunning()) { // Extra check + return false; + } + + memLock.acquire(); + const bool result = sharedMem.create(sizeof(quint64)); + memLock.release(); + + if (!result) { + release(); + return false; + } + + return true; + } + + void RunGuard::release() + { + memLock.acquire(); + + if (sharedMem.isAttached()) { + sharedMem.detach(); + } + + memLock.release(); } - memLock.release(); } diff --git a/src/runguard.h b/src/runguard.h index 45e7e3ba..3da1afb5 100644 --- a/src/runguard.h +++ b/src/runguard.h @@ -5,27 +5,29 @@ #include #include -// From https://stackoverflow.com/a/28172162 -class RunGuard +namespace Hv2ray { + // From https://stackoverflow.com/a/28172162 + class RunGuard + { + public: + explicit RunGuard(const QString &key); + ~RunGuard(); -public: - RunGuard( const QString& key ); - ~RunGuard(); + bool isAnotherRunning(); + bool isSingleInstance(); + void release(); - bool isAnotherRunning(); - bool isSingleInstance(); - void release(); + private: + QString generateKeyHash(const QString &key, const QString &salt); + const QString key; + const QString memLockKey; + const QString sharedmemKey; -private: - const QString key; - const QString memLockKey; - const QString sharedmemKey; - - QSharedMemory sharedMem; - QSystemSemaphore memLock; - - Q_DISABLE_COPY( RunGuard ) -}; + QSharedMemory sharedMem; + QSystemSemaphore memLock; + Q_DISABLE_COPY(RunGuard) + }; +} #endif // RUNGUARD_H diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 9b3adf2c..00000000 --- a/src/utils.h +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#ifndef UTILS_H -#define UTILS_H -#include - -QJsonObject switchJsonArrayObject(QJsonObject objest, QString value); -QJsonObject findValueFromJsonArray(QJsonArray arr, QString key, QString val); -QJsonObject loadRootObjFromConf(); -QJsonArray getInbounds(); -void showWarnMessageBox(QWidget* parent, QString title, QString text); -void overrideInbounds(QString path); -int getIndexByValue(QJsonArray array, QString key, QString val); - -#endif // UTILS_H diff --git a/src/vinteract.cpp b/src/vinteract.cpp index 407202dc..c6b0bd61 100644 --- a/src/vinteract.cpp +++ b/src/vinteract.cpp @@ -1,79 +1,87 @@ -#include #include -#include #include +#include -#include "utils.h" -#include "w_MainWindow.h" +#include "HUtils.h" #include "vinteract.h" +#include "w_MainWindow.h" -bool v2Instance::checkConfigFile(QString path) +namespace Hv2ray { - if(checkVCoreExes()) { - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("V2RAY_LOCATION_ASSET", QDir::currentPath()); + bool v2Instance::checkConfigFile(const QString path) + { + if (checkVCoreExes()) { + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("V2RAY_LOCATION_ASSET", QDir::currentPath()); + QProcess process; + process.setProcessEnvironment(env); + process.start("v2ray", QStringList() << "-test" + << "-config" << path, + QIODevice::ReadWrite | QIODevice::Text); - QProcess process; - process.setProcessEnvironment(env); - process.start("v2ray", QStringList() << "-test" << "-config" << path, QIODevice::ReadWrite | QIODevice::Text); + if (!process.waitForFinished()) { + qDebug() << "v2ray core failed with exit code " << process.exitCode(); + return false; + } - if(!process.waitForFinished()) { - qDebug() << "v2ray core failed with exit code " << process.exitCode(); + QString output = QString(process.readAllStandardOutput()); + + if (!output.contains("Configuration OK")) { + Utils::showWarnMessageBox(nullptr, QObject::tr("ConfigurationError"), output.mid(output.indexOf("anti-censorship.") + 17)); + return false; + } else + return true; + } else + return false; + } + + v2Instance::v2Instance(QWidget *parent) + { + QProcess *proc = new QProcess(); + this->vProcess = proc; + QObject::connect(vProcess, SIGNAL(readyReadStandardOutput()), parent, SLOT(updateLog())); + processStatus = STOPPED; + } + + bool v2Instance::checkVCoreExes() + { + if (QFileInfo("v2ray").exists() && QFileInfo("geoip.dat").exists() && QFileInfo("geosite.dat").exists() && QFileInfo("v2ctl").exists()) { + return true; + } else { + Utils::showWarnMessageBox(nullptr, QObject::tr("CoreNotFound"), QObject::tr("CoreFileNotFoundExplaination")); return false; } + } - QString output = QString(process.readAllStandardOutput()); - - if (!output.contains("Configuration OK")) { - showWarnMessageBox(nullptr, QObject::tr("ConfigurationError"), output.mid(output.indexOf("anti-censorship.") + 17)); - return false; + bool v2Instance::start() + { + if (this->vProcess->state() == QProcess::Running) { + this->stop(); } - else return true; - } - else return false; -} -v2Instance::v2Instance(QWidget *parent) -{ - this->vProcess = new QProcess(); - QObject::connect(vProcess, SIGNAL(readyReadStandardOutput()), parent, SLOT(updateLog())); -} - -bool v2Instance::checkVCoreExes() -{ - if (QFileInfo("v2ray").exists() && QFileInfo("geoip.dat").exists() && QFileInfo("geosite.dat").exists() && QFileInfo("v2ctl").exists()) { - return true; + if (checkVCoreExes()) { + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("V2RAY_LOCATION_ASSET", QDir::currentPath()); + this->vProcess->setProcessEnvironment(env); + this->vProcess->start("./v2ray", QStringList() << "-config" + << "config.json", + QIODevice::ReadWrite | QIODevice::Text); + this->vProcess->waitForStarted(); + processStatus = STARTED; + return true; + } else + return false; } - else { - showWarnMessageBox(nullptr, QObject::tr("CoreNotFound"), QObject::tr("CoreFileNotFoundExplaination")); - return false; - } -} -bool v2Instance::start() -{ - if(this->vProcess->state() == QProcess::Running) { + void v2Instance::stop() + { + this->vProcess->close(); + processStatus = STOPPED; + } + + v2Instance::~v2Instance() + { this->stop(); } - if (checkVCoreExes()) { - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("V2RAY_LOCATION_ASSET", QDir::currentPath()); - this->vProcess->setProcessEnvironment(env); - this->vProcess->start("./v2ray", QStringList() << "-config" << "config.json", QIODevice::ReadWrite | QIODevice::Text); - this->vProcess->waitForStarted(); - processStatus = STARTED; - return true; - } - else return false; -} -void v2Instance::stop() -{ - this->vProcess->close(); - processStatus = STOPPED; -} - -v2Instance::~v2Instance() -{ - this->stop(); } diff --git a/src/vinteract.h b/src/vinteract.h index 0170d063..ffd623c2 100644 --- a/src/vinteract.h +++ b/src/vinteract.h @@ -1,29 +1,33 @@ #ifndef VINTERACT_H #define VINTERACT_H -#include #include +#include -enum V2RAY_INSTANCE_STARTUP_STATUS { - STOPPED, - STARTING, - STARTED -}; - -class v2Instance +namespace Hv2ray { -public: - explicit v2Instance(QWidget *parent); + enum V2RAY_INSTANCE_STARTUP_STATUS { + STOPPED, + STARTING, + STARTED + }; - bool start(); - void stop(); - void restart(); + class v2Instance + { + public: + explicit v2Instance(QWidget *parent); - static bool checkVCoreExes(); - static bool checkConfigFile(QString path); - ~v2Instance(); - QProcess *vProcess; -private: - V2RAY_INSTANCE_STARTUP_STATUS processStatus; -}; + bool start(); + void stop(); + void restart(); + + static bool checkVCoreExes(); + static bool checkConfigFile(QString path); + ~v2Instance(); + QProcess *vProcess; + + private: + V2RAY_INSTANCE_STARTUP_STATUS processStatus; + }; +} #endif // VINTERACT_H diff --git a/src/w_ConnectionEditWindow.cpp b/src/w_ConnectionEditWindow.cpp index 6222ec64..98ffb8c6 100644 --- a/src/w_ConnectionEditWindow.cpp +++ b/src/w_ConnectionEditWindow.cpp @@ -1,36 +1,34 @@ #include "w_ConnectionEditWindow.h" -#include "ui_w_ConnectionEditWindow.h" -#include #include "w_MainWindow.h" #include #include #include +#include -ConnectionEditWindow::ConnectionEditWindow(QWidget *parent) : - QDialog(parent), - ui(new Ui::ConnectionEditWindow) +namespace Hv2ray::Ui { - ui->setupUi(this); - ui->portLineEdit->setValidator(new QIntValidator()); - ui->alterLineEdit->setValidator(new QIntValidator()); -} + ConnectionEditWindow::ConnectionEditWindow(QWidget *parent) + : QDialog(parent) + , ui(new Ui_ConnectionEditWindow) + { + ui->setupUi(this); + ui->portLineEdit->setValidator(new QIntValidator()); + ui->alterLineEdit->setValidator(new QIntValidator()); + } -ConnectionEditWindow::~ConnectionEditWindow() -{ - delete ui; -} -int Hv2Config::save() -{ - return -1; -} + ConnectionEditWindow::~ConnectionEditWindow() + { + delete ui; + } -void Hv2Config::getConfigFromDialog(Ui::ConnectionEditWindow *ui) -{ - this->host = ui->ipLineEdit->text(); - this->port = ui->portLineEdit->text(); - this->alias = ui->aliasLineEdit->text(); - this->uuid = ui->idLineEdit->text(); - this->alterid = ui->alterLineEdit->text(); - this->security = ui->securityCombo->currentText(); - this->isCustom = 0; + //void ConnectionEditWindow::getConfigFromDialog(Ui::ConnectionEditWindow *ui) + //{ + //this->host = ui->ipLineEdit->text(); + //this->port = ui->portLineEdit->text(); + //this->alias = ui->aliasLineEdit->text(); + //this->uuid = ui->idLineEdit->text(); + //this->alterid = ui->alterLineEdit->text(); + //this->security = ui->securityCombo->currentText(); + //this->isCustom = 0; + //} } diff --git a/src/w_ConnectionEditWindow.h b/src/w_ConnectionEditWindow.h index d6bce706..452fff5c 100644 --- a/src/w_ConnectionEditWindow.h +++ b/src/w_ConnectionEditWindow.h @@ -2,39 +2,20 @@ #define CONFEDIT_H #include +#include "ui_w_ConnectionEditWindow.h" -namespace Ui +namespace Hv2ray::Ui { - class ConnectionEditWindow; + class ConnectionEditWindow : public QDialog + { + Q_OBJECT + + public: + explicit ConnectionEditWindow(QWidget *parent = nullptr); + ~ConnectionEditWindow(); + + private: + Ui_ConnectionEditWindow *ui; + }; } - -class Hv2Config -{ -public: - QString host; - QString port; - QString alias; - QString uuid; - QString alterid; - QString security; - int isCustom; - int save(); - void getConfigFromDialog(Ui::ConnectionEditWindow *ui); -private: - -}; - -class ConnectionEditWindow : public QDialog -{ - Q_OBJECT - -public: - explicit ConnectionEditWindow(QWidget *parent = nullptr); - ~ConnectionEditWindow(); -private: - Ui::ConnectionEditWindow *ui; - -}; - - #endif // CONFEDIT_H diff --git a/src/w_ConnectionEditWindow.ui b/src/w_ConnectionEditWindow.ui index 0bbb1213..d40f5d05 100644 --- a/src/w_ConnectionEditWindow.ui +++ b/src/w_ConnectionEditWindow.ui @@ -1,7 +1,7 @@ - ConnectionEditWindow - + Hv2ray::Ui::ConnectionEditWindow + 0 @@ -864,7 +864,7 @@ buttonBox accepted() - ConnectionEditWindow + Hv2ray::Ui::ConnectionEditWindow accept() @@ -880,7 +880,7 @@ buttonBox rejected() - ConnectionEditWindow + Hv2ray::Ui::ConnectionEditWindow reject() diff --git a/src/w_ImportConfig.cpp b/src/w_ImportConfig.cpp index d3e8f381..2a19038e 100644 --- a/src/w_ImportConfig.cpp +++ b/src/w_ImportConfig.cpp @@ -1,131 +1,134 @@ -#include #include #include +#include +#include #include #include -#include #pragma push_macro("slots") #undef slots #include "Python.h" #pragma pop_macro("slots") -#include "w_ConnectionEditWindow.h" +#include "HUtils.h" #include "vinteract.h" -#include "utils.h" +#include "w_ConnectionEditWindow.h" #include "w_ImportConfig.h" -#include "ui_w_ImportConfig.h" - -ImportConfig::ImportConfig(QWidget *parent) : - QDialog(parent), - ui(new Ui::ImportConfig) +using namespace Hv2ray; +namespace Hv2ray::Ui { - ui->setupUi(this); - connect(this, SIGNAL(updateConfTable()), parentWidget(), SLOT(updateConfTable())); -} - -ImportConfig::~ImportConfig() -{ - delete ui; -} - -void ImportConfig::on_pushButton_clicked() -{ - QString dir = QFileDialog::getOpenFileName(this, tr("OpenConfigFile"), "~/"); - ui->fileLineTxt->setText(dir); -} - -void ImportConfig::savefromFile(QString path, QString alias) -{ - Hv2Config newConfig; - newConfig.alias = alias; - QFile configFile(path); - if(!configFile.open(QIODevice::ReadOnly)) { - showWarnMessageBox(this, tr("ImportConfig"), tr("CannotOpenFile")); - qDebug() << "ImportConfig::CannotOpenFile"; - return; - } - QByteArray allData = configFile.readAll(); - configFile.close(); - QJsonDocument v2conf(QJsonDocument::fromJson(allData)); - QJsonObject rootobj = v2conf.object(); - QJsonObject outbound; - if(rootobj.contains("outbounds")) { - outbound = rootobj.value("outbounds").toArray().first().toObject(); - } else { - outbound = rootobj.value("outbound").toObject(); - } - QJsonObject vnext = switchJsonArrayObject(outbound.value("settings").toObject(), "vnext"); - QJsonObject user = switchJsonArrayObject(vnext, "users"); - newConfig.host = vnext.value("address").toString(); - newConfig.port = QString::number(vnext.value("port").toInt()); - newConfig.alterid = QString::number(user.value("alterId").toInt()); - newConfig.uuid = user.value("id").toString(); - newConfig.security = user.value("security").toString(); - if (newConfig.security.isNull()) { - newConfig.security = "auto"; - } - newConfig.isCustom = 1; - int id = newConfig.save(); - if(id < 0) + ImportConfig::ImportConfig(QWidget *parent) + : QDialog(parent) + , ui(new Ui_ImportConfig) { - showWarnMessageBox(this, tr("ImportConfig"), tr("SaveFailed")); - qDebug() << "ImportConfig::SaveFailed"; - return; + ui->setupUi(this); + connect(this, SIGNAL(updateConfTable()), parentWidget(), SLOT(updateConfTable())); } - emit updateConfTable(); - QString newFile = "conf/" + QString::number(id) + ".conf"; - if(!QFile::copy(path, newFile)) { - showWarnMessageBox(this, tr("ImportConfig"), tr("CannotCopyCustomConfig")); - qDebug() << "ImportConfig::CannotCopyCustomConfig"; - } -} -void ImportConfig::on_buttonBox_accepted() -{ - QString alias = ui->nameTxt->text(); - if(ui->importSourceCombo->currentIndex() == 0) // From File... + ImportConfig::~ImportConfig() { - QString path = ui->fileLineTxt->text(); - bool isValid = v2Instance::checkConfigFile(path); - if(isValid) { - savefromFile(path, alias); - } + delete ui; } - else + + void ImportConfig::on_pushButton_clicked() { - QString vmess = ui->vmessConnectionStringTxt->toPlainText(); - Py_Initialize(); - assert(Py_IsInitialized()); - QString param = "--inbound socks:1080 " + vmess + " -o config.json.tmp"; - PyRun_SimpleString("import sys"); - PyRun_SimpleString("sys.path.append('./utils')"); - PyObject *pModule = PyImport_ImportModule("vmess2json"); - PyObject *pFunc = PyObject_GetAttrString(pModule, "main"); - PyObject *arg = PyTuple_New(1); - PyObject *arg1 = Py_BuildValue("s", param.toStdString().c_str()); - PyTuple_SetItem(arg, 0, arg1); - PyObject_CallObject(pFunc, arg); - Py_Finalize(); - if(QFile::exists(QCoreApplication::applicationDirPath() + "/config.json.tmp")) { - ImportConfig *im = new ImportConfig(this->parentWidget()); - if (v2Instance::checkConfigFile(QCoreApplication::applicationDirPath() + "/config.json.tmp")) { - im->savefromFile("config.json.tmp", alias); + QString dir = QFileDialog::getOpenFileName(this, tr("OpenConfigFile"), "~/"); + ui->fileLineTxt->setText(dir); + } + + void ImportConfig::savefromFile(QString path, QString alias) + { + Q_UNUSED(path) + Q_UNUSED(alias) + //Hv2Config newConfig; + //newConfig.alias = alias; + //QFile configFile(path); + //if(!configFile.open(QIODevice::ReadOnly)) { + // showWarnMessageBox(this, tr("ImportConfig"), tr("CannotOpenFile")); + // qDebug() << "ImportConfig::CannotOpenFile"; + // return; + //} + //QByteArray allData = configFile.readAll(); + //configFile.close(); + //QJsonDocument v2conf(QJsonDocument::fromJson(allData)); + //QJsonObject rootobj = v2conf.object(); + //QJsonObject outbound; + //if(rootobj.contains("outbounds")) { + // outbound = rootobj.value("outbounds").toArray().first().toObject(); + //} else { + // outbound = rootobj.value("outbound").toObject(); + //} + //QJsonObject vnext = switchJsonArrayObject(outbound.value("settings").toObject(), "vnext"); + //QJsonObject user = switchJsonArrayObject(vnext, "users"); + //newConfig.host = vnext.value("address").toString(); + //newConfig.port = QString::number(vnext.value("port").toInt()); + //newConfig.alterid = QString::number(user.value("alterId").toInt()); + //newConfig.uuid = user.value("id").toString(); + //newConfig.security = user.value("security").toString(); + //if (newConfig.security.isNull()) { + // newConfig.security = "auto"; + //} + //newConfig.isCustom = 1; + //int id = newConfig.save(); + //if(id < 0) + //{ + // showWarnMessageBox(this, tr("ImportConfig"), tr("SaveFailed")); + // qDebug() << "ImportConfig::SaveFailed"; + // return; + //} + //emit updateConfTable(); + //QString newFile = "conf/" + QString::number(id) + ".conf"; + //if(!QFile::copy(path, newFile)) { + // showWarnMessageBox(this, tr("ImportConfig"), tr("CannotCopyCustomConfig")); + // qDebug() << "ImportConfig::CannotCopyCustomConfig"; + //} + } + + void ImportConfig::on_buttonBox_accepted() + { + QString alias = ui->nameTxt->text(); + + if (ui->importSourceCombo->currentIndex() == 0) { // From File... + QString path = ui->fileLineTxt->text(); + bool isValid = v2Instance::checkConfigFile(path); + + if (isValid) { + savefromFile(path, alias); } - QFile::remove("config.json.tmp"); } else { - showWarnMessageBox(this, tr("ImportConfig"), tr("CannotGenerateConfig")); - qDebug() << "ImportConfig::CannotGenerateConfig"; + QString vmess = ui->vmessConnectionStringTxt->toPlainText(); + Py_Initialize(); + assert(Py_IsInitialized()); + QString param = "--inbound socks:1080 " + vmess + " -o config.json.tmp"; + PyRun_SimpleString("import sys"); + PyRun_SimpleString("sys.path.append('./utils')"); + PyObject *pModule = PyImport_ImportModule("vmess2json"); + PyObject *pFunc = PyObject_GetAttrString(pModule, "main"); + PyObject *arg = PyTuple_New(1); + PyObject *arg1 = Py_BuildValue("s", param.toStdString().c_str()); + PyTuple_SetItem(arg, 0, arg1); + PyObject_CallObject(pFunc, arg); + Py_Finalize(); + + if (QFile::exists(QCoreApplication::applicationDirPath() + "/config.json.tmp")) { + ImportConfig *im = new ImportConfig(this->parentWidget()); + + if (v2Instance::checkConfigFile(QCoreApplication::applicationDirPath() + "/config.json.tmp")) { + im->savefromFile("config.json.tmp", alias); + } + + QFile::remove("config.json.tmp"); + } else { + Utils::showWarnMessageBox(this, tr("ImportConfig"), tr("CannotGenerateConfig")); + qDebug() << "ImportConfig::CannotGenerateConfig"; + } + } + + if (ui->useCurrentSettingRidBtn->isChecked()) { + // TODO: Use Current Settings... + } else { + // TODO: Override Inbound.... } } - - if(ui->useCurrentSettingRidBtn->isChecked()) - { - // TODO: Use Current Settings... - } - else - { - // TODO: Override Inbound.... - } } diff --git a/src/w_ImportConfig.h b/src/w_ImportConfig.h index ea8a97cc..74f797e3 100644 --- a/src/w_ImportConfig.h +++ b/src/w_ImportConfig.h @@ -2,29 +2,31 @@ #define IMPORTCONF_H #include +#include "ui_w_ImportConfig.h" -namespace Ui +namespace Hv2ray { - class ImportConfig; + namespace Ui + { + class ImportConfig : public QDialog + { + Q_OBJECT + + public: + explicit ImportConfig(QWidget *parent = nullptr); + void savefromFile(QString path, QString alias); + ~ImportConfig(); + + private slots: + void on_pushButton_clicked(); + void on_buttonBox_accepted(); + signals: + void updateConfTable(); + + private: + Ui_ImportConfig *ui; + }; + } } -class ImportConfig : public QDialog -{ - Q_OBJECT - -public: - explicit ImportConfig(QWidget *parent = nullptr); - void savefromFile(QString path, QString alias); - ~ImportConfig(); - -private slots: - void on_pushButton_clicked(); - void on_buttonBox_accepted(); -signals: - void updateConfTable(); - -private: - Ui::ImportConfig *ui; -}; - #endif // IMPORTCONF_H diff --git a/src/w_ImportConfig.ui b/src/w_ImportConfig.ui index dc5f219f..bd473e73 100644 --- a/src/w_ImportConfig.ui +++ b/src/w_ImportConfig.ui @@ -1,7 +1,7 @@ - ImportConfig - + Hv2ray::Ui::ImportConfig + 0 @@ -162,7 +162,7 @@ buttonBox accepted() - ImportConfig + Hv2ray::Ui::ImportConfig accept() @@ -178,7 +178,7 @@ buttonBox rejected() - ImportConfig + Hv2ray::Ui::ImportConfig reject() diff --git a/src/w_MainWindow.cpp b/src/w_MainWindow.cpp index f2febf0f..98ea5ac2 100644 --- a/src/w_MainWindow.cpp +++ b/src/w_MainWindow.cpp @@ -1,274 +1,279 @@ -#include -#include -#include -#include #include -#include #include +#include +#include #include +#include #include +#include +#include -#include "ui_w_MainWindow.h" -#include "w_PrefrencesWindow.h" -#include "w_MainWindow.h" +#include "HUtils.h" +#include "vinteract.h" #include "w_ConnectionEditWindow.h" #include "w_ImportConfig.h" -#include "vinteract.h" -#include "utils.h" +#include "w_MainWindow.h" +#include "w_PrefrencesWindow.h" -void MainWindow::CreateTrayIcon() +namespace Hv2ray::Ui { - hTray = new QSystemTrayIcon(); - hTray->setToolTip(tr("Hv2ray")); - hTray->setIcon(this->windowIcon()); - connect(hTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_activatedTray(QSystemTrayIcon::ActivationReason))); - - QAction *actionShow = new QAction(this); - QAction *actionQuit = new QAction(this); - QAction *actionStart = new QAction(this); - QAction *actionRestart = new QAction(this); - QAction *actionStop = new QAction(this); - - actionShow->setText(tr("#Hide")); - actionQuit->setText(tr("#Quit")); - actionStart->setText(tr("#Start")); - actionStop->setText(tr("#Stop")); - actionRestart->setText(tr("#Restart")); - actionStart->setEnabled(true); - actionStop->setEnabled(false); - actionRestart->setEnabled(false); - - trayMenu->addAction(actionShow); - trayMenu->addSeparator(); - trayMenu->addAction(actionStart); - trayMenu->addAction(actionStop); - trayMenu->addAction(actionRestart); - trayMenu->addSeparator(); - trayMenu->addAction(actionQuit); - - connect(actionShow, SIGNAL(triggered()), this, SLOT(toggleMainWindowVisibility())); - connect(actionStart, SIGNAL(triggered()), this, SLOT(on_startButton_clicked())); - connect(actionStop, SIGNAL(triggered()), this, SLOT(on_stopButton_clicked())); - connect(actionRestart, SIGNAL(triggered()), this, SLOT(on_restartButton_clicked())); - connect(actionQuit, SIGNAL(triggered()), this, SLOT(quit())); - hTray->setContextMenu(trayMenu); - hTray->show(); -} - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow) -{ - this->setWindowIcon(QIcon(":/icons/Hv2ray.ico")); - ui->setupUi(this); - UpdateConfigTable(); -// ui->configTable->setContextMenuPolicy(Qt::CustomContextMenu); -// connect(ui->configTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); - this->vinstance = new v2Instance(this); - CreateTrayIcon(); - if(QFileInfo("config.json").exists()) { - vinstance->start(); + void MainWindow::CreateTrayIcon() + { + hTray = new QSystemTrayIcon(); + hTray->setToolTip(tr("Hv2ray")); + hTray->setIcon(this->windowIcon()); + connect(hTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_activatedTray(QSystemTrayIcon::ActivationReason))); + QAction *actionShow = new QAction(this); + QAction *actionQuit = new QAction(this); + QAction *actionStart = new QAction(this); + QAction *actionRestart = new QAction(this); + QAction *actionStop = new QAction(this); + actionShow->setText(tr("#Hide")); + actionQuit->setText(tr("#Quit")); + actionStart->setText(tr("#Start")); + actionStop->setText(tr("#Stop")); + actionRestart->setText(tr("#Restart")); + actionStart->setEnabled(true); + actionStop->setEnabled(false); + actionRestart->setEnabled(false); + trayMenu->addAction(actionShow); + trayMenu->addSeparator(); + trayMenu->addAction(actionStart); + trayMenu->addAction(actionStop); + trayMenu->addAction(actionRestart); + trayMenu->addSeparator(); + trayMenu->addAction(actionQuit); + connect(actionShow, SIGNAL(triggered()), this, SLOT(toggleMainWindowVisibility())); + connect(actionStart, SIGNAL(triggered()), this, SLOT(on_startButton_clicked())); + connect(actionStop, SIGNAL(triggered()), this, SLOT(on_stopButton_clicked())); + connect(actionRestart, SIGNAL(triggered()), this, SLOT(on_restartButton_clicked())); + connect(actionQuit, SIGNAL(triggered()), this, SLOT(quit())); + hTray->setContextMenu(trayMenu); + hTray->show(); } -// QAction *select = new QAction("Select", ui->configTable); -// QAction *del = new QAction("Delete", ui->configTable); -// QAction *rename = new QAction("Rename", ui->configTable); -// popMenu->addAction(select); -// popMenu->addAction(del); -// popMenu->addAction(rename); -// connect(select, SIGNAL(triggered()), this, SLOT(select_triggered())); -// connect(del, SIGNAL(triggered()), this, SLOT(delConf())); -// connect(rename, SIGNAL(triggered()), this, SLOT(renameRow())); -// connect(ui->logText, SIGNAL(textChanged()), this, SLOT(scrollToBottom())); -// bar = ui->logText->verticalScrollBar(); -} + MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui_MainWindow) + { + this->setWindowIcon(QIcon(":/icons/Hv2ray.ico")); + ui->setupUi(this); + UpdateConfigTable(); + // ui->configTable->setContextMenuPolicy(Qt::CustomContextMenu); + // connect(ui->configTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); + this->vinstance = new v2Instance(this); + CreateTrayIcon(); -MainWindow::~MainWindow() -{ - hTray->hide(); - delete this->hTray; - delete this->vinstance; - delete ui; -} - -void MainWindow::on_actionEdit_triggered() -{ - ConnectionEditWindow *e = new ConnectionEditWindow(this); - e->setAttribute(Qt::WA_DeleteOnClose); - e->show(); -} - -void MainWindow::on_actionExisting_config_triggered() -{ - ImportConfig *f = new ImportConfig(this); - f->setAttribute(Qt::WA_DeleteOnClose); - f->show(); -} - -void MainWindow::showMenu(QPoint pos) -{ - Q_UNUSED(pos) -// if(ui->configTable->indexAt(pos).column() != -1) { -// popMenu->move(cursor().pos()); -// popMenu->show(); -// } -} -void MainWindow::select_triggered() -{ -// int row = ui->configTable->selectionModel()->currentIndex().row(); -// int idIntable = ui->configTable->model()->data(ui->configTable->model()->index(row, 4)).toInt(); -// this->geneConf(idIntable); -// if(this->v2Inst->v2Process->state() == QProcess::Running) { -// this->on_restartButton_clicked(); -// } -} - -void MainWindow::DeleteConfig() -{ - -} -void MainWindow::UpdateConfigTable() -{ - -} -void MainWindow::GenerateConfig(int idIntable) -{ - Hv2Config tmpConf; - emit UpdateConfigTable(); - if (tmpConf.isCustom == 1) { - QString src = "conf/" + QString::number(idIntable) + ".conf"; - overrideInbounds(src); - if (QFile::exists("config.json")) { - QFile::remove("config.json"); + if (QFileInfo("config.json").exists()) { + vinstance->start(); } - QFile::copy(src, "config.json"); - } else { - // TODO: Config generator + + // QAction *select = new QAction("Select", ui->configTable); + // QAction *del = new QAction("Delete", ui->configTable); + // QAction *rename = new QAction("Rename", ui->configTable); + // popMenu->addAction(select); + // popMenu->addAction(del); + // popMenu->addAction(rename); + // connect(select, SIGNAL(triggered()), this, SLOT(select_triggered())); + // connect(del, SIGNAL(triggered()), this, SLOT(delConf())); + // connect(rename, SIGNAL(triggered()), this, SLOT(renameRow())); + // connect(ui->logText, SIGNAL(textChanged()), this, SLOT(scrollToBottom())); + // bar = ui->logText->verticalScrollBar(); } -} -void MainWindow::UpdateLog() -{ - ui->logText->insertPlainText(this->vinstance->vProcess->readAllStandardOutput()); -} -void MainWindow::on_startButton_clicked() -{ - ui->logText->clear(); - bool startFlag = this->vinstance->start(); - trayMenu->actions()[2]->setEnabled(!startFlag); - trayMenu->actions()[3]->setEnabled(startFlag); - trayMenu->actions()[4]->setEnabled(startFlag); -} - -void MainWindow::on_stopButton_clicked() -{ - this->vinstance->stop(); - ui->logText->clear(); - trayMenu->actions()[2]->setEnabled(true); - trayMenu->actions()[3]->setEnabled(false); - trayMenu->actions()[4]->setEnabled(false); -} - -void MainWindow::on_restartButton_clicked() -{ - on_stopButton_clicked(); - on_startButton_clicked(); -} - -void MainWindow::on_clbutton_clicked() -{ - ui->logText->clear(); -} - -void MainWindow::on_rtButton_clicked() -{ - emit UpdateConfigTable(); -} - -void MainWindow::closeEvent(QCloseEvent *event) -{ - this->hide(); - event->ignore(); -} - -void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason) -{ - switch (reason) { - case QSystemTrayIcon::Trigger: - // Toggle Show/Hide -#ifndef __APPLE__ - // Every single click will trigger the Show/Hide toggling. - // So, as a hobby on common MacOS Apps, we 'don't toggle visibility on click'. - toggleMainWindowVisibility(); -#endif - break; - case QSystemTrayIcon::DoubleClick: - if(this->isHidden()) { - this->show(); - } - break; - case QSystemTrayIcon::MiddleClick: - // TODO: Check if an alert message box is present. - // If so, do nothing but please wait for the message box to be closed. - if(this->vinstance->vProcess->state() == QProcess::ProcessState::Running) { - on_stopButton_clicked(); - } else { - on_startButton_clicked(); - } - break; - case QSystemTrayIcon::Unknown: - break; - case QSystemTrayIcon::Context: - break; + MainWindow::~MainWindow() + { + hTray->hide(); + delete this->hTray; + delete this->vinstance; + delete ui; } -} -void MainWindow::toggleMainWindowVisibility() -{ - if(this->isHidden()) { - this->show(); - trayMenu->actions()[0]->setText(tr("#Hide")); - } else { + void MainWindow::on_actionEdit_triggered() + { + ConnectionEditWindow *e = new ConnectionEditWindow(this); + e->setAttribute(Qt::WA_DeleteOnClose); + e->show(); + } + + void MainWindow::on_actionExisting_config_triggered() + { + ImportConfig *f = new ImportConfig(this); + f->setAttribute(Qt::WA_DeleteOnClose); + f->show(); + } + + void MainWindow::showMenu(QPoint pos) + { + Q_UNUSED(pos) + // if(ui->configTable->indexAt(pos).column() != -1) { + // popMenu->move(cursor().pos()); + // popMenu->show(); + // } + } + void MainWindow::select_triggered() + { + // int row = ui->configTable->selectionModel()->currentIndex().row(); + // int idIntable = ui->configTable->model()->data(ui->configTable->model()->index(row, 4)).toInt(); + // this->geneConf(idIntable); + // if(this->v2Inst->v2Process->state() == QProcess::Running) { + // this->on_restartButton_clicked(); + // } + } + + void MainWindow::DeleteConfig() + { + } + void MainWindow::UpdateConfigTable() + { + } + void MainWindow::GenerateConfig(int idIntable) + { + Q_UNUSED(idIntable) + //Hv2Config tmpConf; + //emit UpdateConfigTable(); + //if (tmpConf.isCustom == 1) { + // QString src = "conf/" + QString::number(idIntable) + ".conf"; + // overrideInbounds(src); + // if (QFile::exists("config.json")) { + // QFile::remove("config.json"); + // } + // QFile::copy(src, "config.json"); + //} else { + // // TODO: Config generator + //} + } + void MainWindow::UpdateLog() + { + ui->logText->insertPlainText(this->vinstance->vProcess->readAllStandardOutput()); + } + + void MainWindow::on_startButton_clicked() + { + ui->logText->clear(); + bool startFlag = this->vinstance->start(); + trayMenu->actions()[2]->setEnabled(!startFlag); + trayMenu->actions()[3]->setEnabled(startFlag); + trayMenu->actions()[4]->setEnabled(startFlag); + } + + void MainWindow::on_stopButton_clicked() + { + this->vinstance->stop(); + ui->logText->clear(); + trayMenu->actions()[2]->setEnabled(true); + trayMenu->actions()[3]->setEnabled(false); + trayMenu->actions()[4]->setEnabled(false); + } + + void MainWindow::on_restartButton_clicked() + { + on_stopButton_clicked(); + on_startButton_clicked(); + } + + void MainWindow::on_clbutton_clicked() + { + ui->logText->clear(); + } + + void MainWindow::on_rtButton_clicked() + { + emit UpdateConfigTable(); + } + + void MainWindow::closeEvent(QCloseEvent *event) + { this->hide(); - trayMenu->actions()[0]->setText(tr("#Show")); + event->ignore(); + } + + void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason) + { + switch (reason) { + case QSystemTrayIcon::Trigger: + // Toggle Show/Hide +#ifndef __APPLE__ + // Every single click will trigger the Show/Hide toggling. + // So, as a hobby on common MacOS Apps, we 'don't toggle visibility on click'. + toggleMainWindowVisibility(); +#endif + break; + + case QSystemTrayIcon::DoubleClick: + if (this->isHidden()) { + this->show(); + } + + break; + + case QSystemTrayIcon::MiddleClick: + + // TODO: Check if an alert message box is present. + // If so, do nothing but please wait for the message box to be closed. + if (this->vinstance->vProcess->state() == QProcess::ProcessState::Running) { + on_stopButton_clicked(); + } else { + on_startButton_clicked(); + } + + break; + + case QSystemTrayIcon::Unknown: + break; + + case QSystemTrayIcon::Context: + break; + } + } + + void MainWindow::toggleMainWindowVisibility() + { + if (this->isHidden()) { + this->show(); + trayMenu->actions()[0]->setText(tr("#Hide")); + } else { + this->hide(); + trayMenu->actions()[0]->setText(tr("#Show")); + } + } + + void MainWindow::quit() + { + QCoreApplication::quit(); + } + + void MainWindow::on_actionExit_triggered() + { + quit(); + } + + void MainWindow::renameRow() + { + // QString text = QInputDialog::getText(this, "Rename config", "New name:", QLineEdit::Normal); + // int row = ui->configTable->currentIndex().row(); + // int idIntable = ui->configTable->model()->data(ui->configTable->model()->index(row, 4)).toInt(); + // SQLiteDB mydb; + // QString updateString = "update confs set alias = '" + text + "' where id = " + QString::number(idIntable); + // mydb.DoQuery(updateString); + // emit updateConfTable(); + } + + void MainWindow::scrollToBottom() + { + bar->setValue(bar->maximum()); + } + + void MainWindow::on_actionPreferences_triggered() + { + PrefrencesWindow *v = new PrefrencesWindow(this); + v->setAttribute(Qt::WA_DeleteOnClose); + v->show(); + } + + void MainWindow::on_pushButton_clicked() + { + auto confedit = new ConnectionEditWindow(); + confedit->show(); } } - -void MainWindow::quit() -{ - QCoreApplication::quit(); -} - -void MainWindow::on_actionExit_triggered() -{ - quit(); -} - -void MainWindow::renameRow() -{ -// QString text = QInputDialog::getText(this, "Rename config", "New name:", QLineEdit::Normal); -// int row = ui->configTable->currentIndex().row(); -// int idIntable = ui->configTable->model()->data(ui->configTable->model()->index(row, 4)).toInt(); -// SQLiteDB mydb; -// QString updateString = "update confs set alias = '" + text + "' where id = " + QString::number(idIntable); -// mydb.DoQuery(updateString); -// emit updateConfTable(); -} - -void MainWindow::scrollToBottom() -{ - bar->setValue(bar->maximum()); -} - -void MainWindow::on_actionPreferences_triggered() -{ - PrefrencesWindow *v = new PrefrencesWindow(this); - v->setAttribute(Qt::WA_DeleteOnClose); - v->show(); -} - -void MainWindow::on_pushButton_clicked() -{ - auto confedit = new ConnectionEditWindow(); - confedit->show(); -} diff --git a/src/w_MainWindow.h b/src/w_MainWindow.h index ac29b0a6..ee46eb2b 100644 --- a/src/w_MainWindow.h +++ b/src/w_MainWindow.h @@ -1,60 +1,60 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include #include "w_ConnectionEditWindow.h" -#include +#include #include #include +#include +#include "ui_w_MainWindow.h" #include "vinteract.h" +#include "Hv2ConfigObject.h" -namespace Ui +namespace Hv2ray::Ui { - class MainWindow; + class MainWindow : public QMainWindow + { + Q_OBJECT + public: + explicit MainWindow(QWidget *parent = nullptr); + v2Instance *vinstance; + QSystemTrayIcon *hTray; + QMenu *trayMenu = new QMenu(this); + QMenu *popMenu = new QMenu(this); + QScrollBar *bar; + ~MainWindow(); + + private slots: + void on_restartButton_clicked(); + void on_actionEdit_triggered(); + void on_actionExisting_config_triggered(); + void UpdateConfigTable(); + void DeleteConfig(); + void showMenu(QPoint pos); + void UpdateLog(); + void on_startButton_clicked(); + void on_stopButton_clicked(); + void select_triggered(); + void on_clbutton_clicked(); + void on_rtButton_clicked(); + void GenerateConfig(int idIntable); + void on_activatedTray(QSystemTrayIcon::ActivationReason reason); + void toggleMainWindowVisibility(); + void quit(); + void on_actionExit_triggered(); + void renameRow(); + void scrollToBottom(); + void on_actionPreferences_triggered(); + + void on_pushButton_clicked(); + + private: + Ui_MainWindow *ui; + void closeEvent(QCloseEvent *); + void createTrayAction(); + void CreateTrayIcon(); + }; } -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = nullptr); - v2Instance *vinstance; - QSystemTrayIcon *hTray; - QMenu *trayMenu = new QMenu(this); - QMenu *popMenu = new QMenu(this); - QScrollBar *bar; - ~MainWindow(); - -private slots: - void on_restartButton_clicked(); - void on_actionEdit_triggered(); - void on_actionExisting_config_triggered(); - void UpdateConfigTable(); - void DeleteConfig(); - void showMenu(QPoint pos); - void UpdateLog(); - void on_startButton_clicked(); - void on_stopButton_clicked(); - void select_triggered(); - void on_clbutton_clicked(); - void on_rtButton_clicked(); - void GenerateConfig(int idIntable); - void on_activatedTray(QSystemTrayIcon::ActivationReason reason); - void toggleMainWindowVisibility(); - void quit(); - void on_actionExit_triggered(); - void renameRow(); - void scrollToBottom(); - void on_actionPreferences_triggered(); - - void on_pushButton_clicked(); - -private: - Ui::MainWindow *ui; - void closeEvent(QCloseEvent *); - void createTrayAction(); - void CreateTrayIcon(); -}; #endif // MAINWINDOW_H diff --git a/src/w_MainWindow.ui b/src/w_MainWindow.ui index e561718e..95bd3e9c 100644 --- a/src/w_MainWindow.ui +++ b/src/w_MainWindow.ui @@ -1,7 +1,7 @@ - MainWindow - + Hv2ray::Ui::MainWindow + 0 diff --git a/src/w_PrefrencesWindow.cpp b/src/w_PrefrencesWindow.cpp index 461b5cf2..ec17c128 100644 --- a/src/w_PrefrencesWindow.cpp +++ b/src/w_PrefrencesWindow.cpp @@ -1,159 +1,178 @@ +#include +#include +#include +#include +#include #include #include -#include -#include -#include #include -#include -#include #include -#include -#include -#include "utils.h" +#include "HUtils.h" #include "vinteract.h" #include "w_PrefrencesWindow.h" +#include -PrefrencesWindow::PrefrencesWindow(QWidget *parent) : - QDialog(parent), - ui(new Ui::PrefrencesWindow) -{ - ui->setupUi(this); - rootObj = loadRootObjFromConf(); - QJsonObject http = findValueFromJsonArray(rootObj.value("inbounds").toArray(), "tag", "http-in"); - QJsonObject socks = findValueFromJsonArray(rootObj.value("inbounds").toArray(), "tag", "socks-in"); - if(rootObj.value("v2suidEnabled").toBool()) { - ui->runAsRootCheckBox->setCheckState(Qt::Checked); - } - if(!http.isEmpty()) { - ui->httpPortLE->setText(http.value("port").toString()); - ui->httpCB->setCheckState(Qt::Checked); - } else { - ui->httpPortLE->setDisabled(true); - } - if(!socks.isEmpty()) { - ui->socksPortLE->setText(socks.value("port").toString()); - ui->socksCB->setCheckState(Qt::Checked); - } else { - ui->socksPortLE->setDisabled(true); - } - ui->httpPortLE->setValidator(new QIntValidator()); - ui->socksPortLE->setValidator(new QIntValidator()); - parentMW = parent; -} +using namespace Hv2ray; +using namespace Utils; -PrefrencesWindow::~PrefrencesWindow() +namespace Hv2ray::Ui { - delete ui; -} + PrefrencesWindow::PrefrencesWindow(QWidget *parent) + : QDialog(parent) + , ui(new Ui_PrefrencesWindow) + { + ui->setupUi(this); + rootObj = loadRootObjFromConf(); + QJsonObject http = findValueFromJsonArray(rootObj.value("inbounds").toArray(), "tag", "http-in"); + QJsonObject socks = findValueFromJsonArray(rootObj.value("inbounds").toArray(), "tag", "socks-in"); -void PrefrencesWindow::on_buttonBox_accepted() -{ - if(v2Instance::checkVCoreExes()) { - if(ui->httpPortLE->text().toInt() != ui->socksPortLE->text().toInt()) { - QJsonArray inbounds; - QJsonDocument modifiedDoc; - inbounds = rootObj.value("inbounds").toArray(); - int socksId = getIndexByValue(inbounds, "tag", "socks-in"); - if(socksId != -1) { - inbounds.removeAt(socksId); - } - int httpId = getIndexByValue(inbounds, "tag", "http-in"); - if(httpId != -1) { - inbounds.removeAt(httpId); - } - rootObj.remove("inbounds"); - rootObj.remove("v2suidEnabled"); - if(ui->socksCB->isChecked()) { - QJsonObject socks; - QJsonObject settings; - socks.insert("tag", "socks-in"); - socks.insert("port", ui->socksPortLE->text().toInt()); - socks.insert("listen", "127.0.0.1"); - socks.insert("protocol", "socks"); - settings.insert("auth", "noauth"); - settings.insert("udp", true); - settings.insert("ip", "127.0.0.1"); - socks.insert("settings", QJsonValue(settings)); - inbounds.append(socks); - } - if(ui->httpCB->isChecked()) { - QJsonObject http; - QJsonObject settings; - http.insert("tag", "http-in"); - http.insert("port", ui->httpPortLE->text().toInt()); - http.insert("listen", "127.0.0.1"); - http.insert("protocol", "http"); - settings.insert("auth", "noauth"); - settings.insert("udp", true); - settings.insert("ip", "127.0.0.1"); - http.insert("settings", QJsonValue(settings)); - inbounds.append(http); - } - rootObj.insert("inbounds", QJsonValue(inbounds)); -#ifndef _WIN32 - // Set UID and GID in *nix - QFileInfo v2rayCoreExeFile("v2ray"); - if(ui->runAsRootCheckBox->isChecked() && v2rayCoreExeFile.ownerId() != 0) { - QProcess::execute("pkexec", QStringList() << "bash" << "-c" << "chown root:root " + QCoreApplication::applicationDirPath() + "/v2ray" + ";chmod +s " + QCoreApplication::applicationDirPath() + "/v2ray"); - } else if (!ui->runAsRootCheckBox->isChecked() && v2rayCoreExeFile.ownerId() == 0) { - uid_t uid = getuid(); - gid_t gid = getgid(); - QProcess::execute("pkexec", QStringList() << "chown" << QString::number(uid) + ":" + QString::number(gid) << QCoreApplication::applicationDirPath() + "/v2ray"); - } - v2rayCoreExeFile.refresh(); - rootObj.insert("v2suidEnabled", v2rayCoreExeFile.ownerId() == 0); -#else - // No such uid gid thing on windows.... -#endif - modifiedDoc.setObject(rootObj); - QByteArray byteArray = modifiedDoc.toJson(QJsonDocument::Indented); - QFile confFile("conf/Hv2ray.config.json"); - if(!confFile.open(QIODevice::WriteOnly)) { - showWarnMessageBox(this, tr("#Prefrences"), tr("#CannotOpenConfigFile")); - qDebug() << "Cannot open Hv2ray.config.json for modifying"; - } - confFile.write(byteArray); - confFile.close(); + if (rootObj.value("v2suidEnabled").toBool()) { + ui->runAsRootCheckBox->setCheckState(Qt::Checked); + } + + if (!http.isEmpty()) { + ui->httpPortLE->setText(http.value("port").toString()); + ui->httpCB->setCheckState(Qt::Checked); } else { - showWarnMessageBox(this, tr("Prefrences"), tr("PortNumbersCannotBeSame")); + ui->httpPortLE->setDisabled(true); + } + + if (!socks.isEmpty()) { + ui->socksPortLE->setText(socks.value("port").toString()); + ui->socksCB->setCheckState(Qt::Checked); + } else { + ui->socksPortLE->setDisabled(true); + } + + ui->httpPortLE->setValidator(new QIntValidator()); + ui->socksPortLE->setValidator(new QIntValidator()); + parentMW = parent; + } + + PrefrencesWindow::~PrefrencesWindow() + { + delete ui; + } + + void PrefrencesWindow::on_buttonBox_accepted() + { + if (v2Instance::checkVCoreExes()) { + if (ui->httpPortLE->text().toInt() != ui->socksPortLE->text().toInt()) { + QJsonArray inbounds; + QJsonDocument modifiedDoc; + inbounds = rootObj.value("inbounds").toArray(); + int socksId = getIndexByValue(inbounds, "tag", "socks-in"); + + if (socksId != -1) { + inbounds.removeAt(socksId); + } + + int httpId = getIndexByValue(inbounds, "tag", "http-in"); + + if (httpId != -1) { + inbounds.removeAt(httpId); + } + + rootObj.remove("inbounds"); + rootObj.remove("v2suidEnabled"); + + if (ui->socksCB->isChecked()) { + QJsonObject socks; + QJsonObject settings; + socks.insert("tag", "socks-in"); + socks.insert("port", ui->socksPortLE->text().toInt()); + socks.insert("listen", "127.0.0.1"); + socks.insert("protocol", "socks"); + settings.insert("auth", "noauth"); + settings.insert("udp", true); + settings.insert("ip", "127.0.0.1"); + socks.insert("settings", QJsonValue(settings)); + inbounds.append(socks); + } + + if (ui->httpCB->isChecked()) { + QJsonObject http; + QJsonObject settings; + http.insert("tag", "http-in"); + http.insert("port", ui->httpPortLE->text().toInt()); + http.insert("listen", "127.0.0.1"); + http.insert("protocol", "http"); + settings.insert("auth", "noauth"); + settings.insert("udp", true); + settings.insert("ip", "127.0.0.1"); + http.insert("settings", QJsonValue(settings)); + inbounds.append(http); + } + + rootObj.insert("inbounds", QJsonValue(inbounds)); +#ifndef _WIN32 + // Set UID and GID in *nix + QFileInfo v2rayCoreExeFile("v2ray"); + + if (ui->runAsRootCheckBox->isChecked() && v2rayCoreExeFile.ownerId() != 0) { + QProcess::execute("pkexec", QStringList() << "bash" + << "-c" + << "chown root:root " + QCoreApplication::applicationDirPath() + "/v2ray" + ";chmod +s " + QCoreApplication::applicationDirPath() + "/v2ray"); + } else if (!ui->runAsRootCheckBox->isChecked() && v2rayCoreExeFile.ownerId() == 0) { + uid_t uid = getuid(); + gid_t gid = getgid(); + QProcess::execute("pkexec", QStringList() << "chown" << QString::number(uid) + ":" + QString::number(gid) << QCoreApplication::applicationDirPath() + "/v2ray"); + } + + v2rayCoreExeFile.refresh(); + rootObj.insert("v2suidEnabled", v2rayCoreExeFile.ownerId() == 0); +#else + // No such uid gid thing on windows.... +#endif + modifiedDoc.setObject(rootObj); + QByteArray byteArray = modifiedDoc.toJson(QJsonDocument::Indented); + QFile confFile("conf/Hv2ray.config.json"); + + if (!confFile.open(QIODevice::WriteOnly)) { + showWarnMessageBox(this, tr("#Prefrences"), tr("#CannotOpenConfigFile")); + qDebug() << "Cannot open Hv2ray.config.json for modifying"; + } + + confFile.write(byteArray); + confFile.close(); + } else { + showWarnMessageBox(this, tr("Prefrences"), tr("PortNumbersCannotBeSame")); + } } } -} - -void PrefrencesWindow::on_httpCB_stateChanged(int checked) -{ - if(checked != Qt::Checked) { - ui->httpPortLE->setDisabled(true); - } else { - ui->httpPortLE->setEnabled(true); - ui->httpPortLE->setText("6666"); - } -} - -void PrefrencesWindow::on_socksCB_stateChanged(int checked) -{ - if(checked != Qt::Checked) { - ui->socksPortLE->setDisabled(true); - } else { - ui->socksPortLE->setEnabled(true); - ui->socksPortLE->setText("1080"); - } -} - -void PrefrencesWindow::on_httpAuthCB_stateChanged(int checked) -{ - if(checked) + void PrefrencesWindow::on_httpCB_stateChanged(int checked) { + if (checked != Qt::Checked) { + ui->httpPortLE->setDisabled(true); + } else { + ui->httpPortLE->setEnabled(true); + ui->httpPortLE->setText("6666"); + } + } + void PrefrencesWindow::on_socksCB_stateChanged(int checked) + { + if (checked != Qt::Checked) { + ui->socksPortLE->setDisabled(true); + } else { + ui->socksPortLE->setEnabled(true); + ui->socksPortLE->setText("1080"); + } + } + + void PrefrencesWindow::on_httpAuthCB_stateChanged(int checked) + { + if (checked) { + } + } + + void PrefrencesWindow::on_runAsRootCheckBox_stateChanged(int arg1) + { + Q_UNUSED(arg1) +#ifdef _WIN32 + showWarnMessageBox(this, tr("Prefrences"), tr("RunAsRootNotOnWindows")); +#endif } } - -void PrefrencesWindow::on_runAsRootCheckBox_stateChanged(int arg1) -{ - Q_UNUSED(arg1); -#ifdef _WIN32 - showWarnMessageBox(this, tr("Prefrences"), tr("RunAsRootNotOnWindows")); -#endif -} diff --git a/src/w_PrefrencesWindow.h b/src/w_PrefrencesWindow.h index de856f08..2b4751be 100644 --- a/src/w_PrefrencesWindow.h +++ b/src/w_PrefrencesWindow.h @@ -2,34 +2,32 @@ #define HVCONF_H #include +#include #include -namespace Ui +namespace Hv2ray::Ui { - class PrefrencesWindow; + class PrefrencesWindow : public QDialog + { + Q_OBJECT + + public: + explicit PrefrencesWindow(QWidget *parent = nullptr); + ~PrefrencesWindow(); + QJsonObject rootObj; + QWidget *parentMW; + + private slots: + void on_buttonBox_accepted(); + void on_httpCB_stateChanged(int arg1); + void on_socksCB_stateChanged(int arg1); + + void on_httpAuthCB_stateChanged(int arg1); + + void on_runAsRootCheckBox_stateChanged(int arg1); + + private: + Ui_PrefrencesWindow *ui; + }; } - -class PrefrencesWindow : public QDialog -{ - Q_OBJECT - -public: - explicit PrefrencesWindow(QWidget *parent = nullptr); - ~PrefrencesWindow(); - QJsonObject rootObj; - QWidget *parentMW; - -private slots: - void on_buttonBox_accepted(); - void on_httpCB_stateChanged(int arg1); - void on_socksCB_stateChanged(int arg1); - - void on_httpAuthCB_stateChanged(int arg1); - - void on_runAsRootCheckBox_stateChanged(int arg1); - -private: - Ui::PrefrencesWindow *ui; -}; - #endif // HVCONF_H diff --git a/src/w_PrefrencesWindow.ui b/src/w_PrefrencesWindow.ui index 12586791..28f5cd5f 100644 --- a/src/w_PrefrencesWindow.ui +++ b/src/w_PrefrencesWindow.ui @@ -1,7 +1,7 @@ - PrefrencesWindow - + Hv2ray::Ui::PrefrencesWindow + 0 @@ -345,7 +345,7 @@ buttonBox accepted() - PrefrencesWindow + Hv2ray::Ui::PrefrencesWindow accept() @@ -361,7 +361,7 @@ buttonBox rejected() - PrefrencesWindow + Hv2ray::Ui::PrefrencesWindow reject() diff --git a/translations/en-US.ts b/translations/en-US.ts index f0cdb3e3..973f22be 100644 --- a/translations/en-US.ts +++ b/translations/en-US.ts @@ -4,655 +4,1093 @@ ConnectionEditWindow - #ConnectionSettings - Connection Settings + Connection Settings - - #Host - Host + Host - #Port - Port + Port - #Name - Name + Name - #UUID - UUID + UUID - #AlterID - Alter ID + Alter ID - - #Security - Security Settings + Security Settings - auto - Auto + Auto - - aes-128-gcm - aes-128-gcm + aes-128-gcm - - chacha20-poly1305 - chacha20-poly1305 + chacha20-poly1305 - - - - - + none + Do not use + + + #Transport + Transport Settings + + + tcp (TCP) + tcp (TCP) + + + http (HTTP) + http (HTTP) + + + ws (WebSocket) + ws (WebSocket) + + + kcp (mKCP) + kcp (mKCP) + + + domainsocket (Domain Socket) + domainsocket (Domain Socket) + + + quic (Quick UDP Internet Connection) + quic (Quick UDP Internet Connection) + + + #TransportSettings + Transport Settings + + + TCP + TCP + + + http + HTTP + + + #Type + Type + + + #Request + Request + + + #InsertDefaultContent + Insert Default Content + + + #Response + Response + + + HTTP + HTTP + + + #Path + Path + + + WebSocket + WebSocket + + + #Headers + Headers + + + mKCP + mKCP + + + #MTU + MTU + + + #TTI (ms) + TTI (ms) + + + #UplinkCapacity (MB/s) + Uplink Capacity (MB/s) + + + #Congestion + Congestion Control + + + #Enabled + Enabled + + + #DownlinkCapacity (MB/s) + Downlink Capacity (MB/s) + + + #ReadBufferSize (MB) + Read Buffer Size (MB) + + + #WriteBufferSize (MB) + Write Buffer Size (MB) + + + #Header + Headers + + + srtp (SRTP, FaceTime) + srtp (SRTP, FaceTime) + + + utp (BitTorrent) + utp (BitTorrent) + + + wechat-video (WeChat Video Message) + wechat-video (WeChat Video Message) + + + dtls (DTLS 1.2) + dtls (DTLS 1.2) + + + wireguard (WireGuard fake packets) + wireguard (WireGuard fake packets) + + + DomainSocket + DomainSocket + + + QUIC + QUIC + + + #Key + Key + + + + Hv2ray::Ui::ConnectionEditWindow + + + #ConnectionSettings + Connection Settings + + + + + #Host + Host + + + + #Port + Port + + + + #Name + Name + + + + #UUID + UUID + + + + #AlterID + Alter ID + + + + + #Security + Security Settings + + + + auto + Auto + + + + + aes-128-gcm + aes-128-gcm + + + + + chacha20-poly1305 + chacha20-poly1305 + + + + + + + + none + Do not use + + + + #Transport + Transport Settings + + + + tcp (TCP) + tcp (TCP) + + + + http (HTTP) + http (HTTP) + + + + ws (WebSocket) + ws (WebSocket) + + + + kcp (mKCP) + kcp (mKCP) + + + + domainsocket (Domain Socket) + domainsocket (Domain Socket) + + + + quic (Quick UDP Internet Connection) + quic (Quick UDP Internet Connection) + + + + #TransportSettings + Transport Settings + + + + TCP + TCP + + + + http + HTTP + + + + + + #Type + Type + + + + #Request + Request + + + + + #InsertDefaultContent + Insert Default Content + + + + #Response + Response + + + + HTTP + HTTP + + + + + + #Path + Path + + + + WebSocket + WebSocket + + + + + #Headers + Headers + + + + mKCP + mKCP + + + + #MTU + MTU + + + + #TTI (ms) + TTI (ms) + + + + #UplinkCapacity (MB/s) + Uplink Capacity (MB/s) + + + + #Congestion + Congestion Control + + + + #Enabled + Enabled + + + + #DownlinkCapacity (MB/s) + Downlink Capacity (MB/s) + + + + #ReadBufferSize (MB) + Read Buffer Size (MB) + + + + #WriteBufferSize (MB) + Write Buffer Size (MB) + + + + + #Header + Headers + + + + + srtp (SRTP, FaceTime) + srtp (SRTP, FaceTime) + + + + + utp (BitTorrent) + utp (BitTorrent) + + + + + wechat-video (WeChat Video Message) + wechat-video (WeChat Video Message) + + + + + dtls (DTLS 1.2) + dtls (DTLS 1.2) + + + + + wireguard (WireGuard fake packets) + wireguard (WireGuard fake packets) + + + + DomainSocket + DomainSocket + + + + QUIC + QUIC + + + + #Key + Key + + + + Hv2ray::Ui::ImportConfig + + + Import file + Import file + + + + #ImportFrom + Import From + + + + Existing File + Existing File + + + + VMess Connection String + VMess Connection String + + + + #FromFile + From file + + + + #Path + Path + + + + #SelectFile + Select File + + + + #Name + Name + + + + #Inbound + Inbound Settings + + + + #UseCurrent + Use Current Settings + + + + #UseImported + Use Imported Inbound Settings + + + + #From VMess Connection String + From VMess Connection String + + + + #VMess Connection String + VMess Connection String + + + + OpenConfigFile + Open Config File + + + + ImportConfig + Import Config + + + + CannotGenerateConfig + Failed to generate config file + + + + Hv2ray::Ui::MainWindow + + + + Hv2ray + Hv2ray + + + + + #Start + Start + + + + + #Stop + Stop + + + + + #Restart + Restart + + + + #ClearLog + Clear Log + + + + #HostList + Host List + + + + #ConfigDetail + Detailed Config Info + + + + #Host + Host + + + + #Port + Port + + + + #UUID + UUID + + + + #Transport + Transport Settings + + + + + #ConnectionSettings + Connection Settings + + + + #File + File + + + + #NewConnection + New Connection + + + + #ManuallyInput + Manually Input Config + + + + #ImportConnection + Import Config File + + + + #Exit + Exit + + + + #Preferences + Preferences + + + + + #Hide + Hide + + + + #Quit + Quit + + + + #Show + Show + + + + Hv2ray::Ui::PrefrencesWindow + + + + + Prefrences + Preferences + + + + #General + General + + + + #Language + Language + + + + zh-CN + + + + + en-US + + + + + #RunAsRoot + Run v2ray as root + + + + + + + + + + #Enabled + Enabled + + + + #LogLevel + Log Level + + + + debug + Debug + + + + info + Info + + + + warning + Warning + + + + error + Error + + + none Do not use - - #Transport - Transport Settings + + #MuxCool + Mux Settings - - tcp (TCP) - tcp (TCP) + + #Concurrency + Maximum Connections - - http (HTTP) - http (HTTP) + + #InboundSettings + Inbound Settings - - ws (WebSocket) - ws (WebSocket) - - - - kcp (mKCP) - kcp (mKCP) - - - - domainsocket (Domain Socket) - domainsocket (Domain Socket) - - - - quic (Quick UDP Internet Connection) - quic (Quick UDP Internet Connection) - - - - #TransportSettings - Transport Settings - - - - TCP - TCP - - - - http - HTTP - - - - - - #Type - Type - - - - #Request - Request - - - - - #InsertDefaultContent - Insert Default Content - - - - #Response - Response - - - + HTTP HTTP - - - - #Path - Path + + + #Port + Port - - WebSocket - WebSocket + + 8080 + - - - #Headers - Headers + + + #Username + Username - - mKCP - mKCP + + + #Auth + Authentication - - #MTU - MTU + + + #Password + Password - - #TTI (ms) - TTI (ms) + + SOCKS + SOCKS - - #UplinkCapacity (MB/s) - Uplink Capacity (MB/s) + + 9001 + - - #Congestion - Congestion Control + + #Prefrences + Preferences - - #Enabled - Enabled + + #CannotOpenConfigFile + Cannot open config file - - #DownlinkCapacity (MB/s) - Downlink Capacity (MB/s) + + PortNumbersCannotBeSame + Port numbers cannot be the same - - #ReadBufferSize (MB) - Read Buffer Size (MB) - - - - #WriteBufferSize (MB) - Write Buffer Size (MB) - - - - - #Header - Headers - - - - - srtp (SRTP, FaceTime) - srtp (SRTP, FaceTime) - - - - - utp (BitTorrent) - utp (BitTorrent) - - - - - wechat-video (WeChat Video Message) - wechat-video (WeChat Video Message) - - - - - dtls (DTLS 1.2) - dtls (DTLS 1.2) - - - - - wireguard (WireGuard fake packets) - wireguard (WireGuard fake packets) - - - - DomainSocket - DomainSocket - - - - QUIC - QUIC - - - - #Key - Key + + RunAsRootNotOnWindows + Run as root is not avaliable on Windows Platform ImportConfig - Import file - Import file + Import file - #ImportFrom - Import From + Import From - Existing File - Existing File + Existing File - VMess Connection String - VMess Connection String + VMess Connection String - #FromFile - From file + From file - #Path - Path + Path - #SelectFile - Select File + Select File - #Name - Name + Name - #Inbound - Inbound Settings + Inbound Settings - #UseCurrent - Use Current Settings + Use Current Settings - #UseImported - Use Imported Inbound Settings + Use Imported Inbound Settings - #From VMess Connection String - From VMess Connection String + From VMess Connection String - #VMess Connection String - VMess Connection String + VMess Connection String - OpenConfigFile - Open Config File + Open Config File - - - - ImportConfig - Import Config + Import Config - CannotOpenFile - Cannot open file + Cannot open file - SaveFailed - Failed to save + Failed to save - CannotCopyCustomConfig - Failed to copy config file + Failed to copy config file - CannotGenerateConfig - Failed to generate config file + Failed to generate config file MainWindow - - Hv2ray - Hv2ray + Hv2ray - - #Start - Start + Start - - #Stop - Stop + Stop - - #Restart - Restart + Restart - #ClearLog - Clear Log + Clear Log - #HostList - Host List + Host List - #ConfigDetail - Detailed Config Info + Detailed Config Info - #Host - Host + Host - #Port - Port + Port - #UUID - UUID + UUID - #Transport - Transport Settings + Transport Settings - - #ConnectionSettings - Connection Settings + Connection Settings - #File - File + File - #NewConnection - New Connection + New Connection - #ManuallyInput - Manually Input Config + Manually Input Config - #ImportConnection - Import Config File + Import Config File - #Exit - Exit + Exit - #Preferences - Preferences + Preferences - - #Hide - Hide + Hide - #Quit - Quit + Quit - #Show - Show + Show PrefrencesWindow - - - Prefrences - Preferences + Preferences - - zh-CN - - - - - en-US - - - - #General - General + General - #Language - Language + Language - #RunAsRoot - Run v2ray as root + Run v2ray as root - - - - - - - #Enabled - Enabled + Enabled - #LogLevel - Log Level + Log Level - debug - Debug + Debug - info - Info + Info - warning - Warning + Warning - error - Error + Error - none - Do not use + Do not use - #MuxCool - Mux Settings + Mux Settings - #Concurrency - Maximum Connections + Maximum Connections - #InboundSettings - Inbound Settings + Inbound Settings - - #Port - Port + Port - - #Username - Username + Username - - #Auth - Authentication + Authentication - - #Password - Password + Password - HTTP - HTTP + HTTP - - 8080 - - - - SOCKS - SOCKS + SOCKS - - 9001 - - - - #Prefrences - Preferences + Preferences - #CannotOpenConfigFile - Cannot open config file + Cannot open config file - PortNumbersCannotBeSame - Port numbers cannot be the same + Port numbers cannot be the same - RunAsRootNotOnWindows - Run as root is not avaliable on Windows Platform + Run as root is not avaliable on Windows Platform QObject - + Hv2Ray Hv2ray - + AnotherInstanceRunning Another instance is already running - + CoreNotFound Core files are not found - + CoreFileNotFoundExplaination Please go to the official website or Github to download the latest release of v2ray executable - + ConfigurationError Configuration Error diff --git a/translations/zh-CN.ts b/translations/zh-CN.ts index d38e304d..6596764b 100644 --- a/translations/zh-CN.ts +++ b/translations/zh-CN.ts @@ -4,655 +4,1093 @@ ConnectionEditWindow - #ConnectionSettings - 连接设置 + 连接设置 - - #Host - 域名 + 域名 - #Port - 端口 + 端口 - #Name - 名称 + 名称 - #UUID - UUID + UUID - #AlterID - Alter ID + Alter ID - - #Security - 安全设置 + 安全设置 - auto - 自动 + 自动 - - aes-128-gcm - aes-128-gcm + aes-128-gcm - - chacha20-poly1305 - chacha20-poly1305 + chacha20-poly1305 - - - - - + none + 不使用 + + + #Transport + 传输设置 + + + tcp (TCP) + tcp (TCP) + + + http (HTTP) + http (HTTP) + + + ws (WebSocket) + ws (WebSocket) + + + kcp (mKCP) + kcp (mKCP) + + + domainsocket (Domain Socket) + domainsocket (Domain Socket) + + + quic (Quick UDP Internet Connection) + quic (Quick UDP Internet Connection) + + + #TransportSettings + 传输设置 + + + TCP + TCP + + + http + HTTP + + + #Type + 类型 + + + #Request + 请求 + + + #InsertDefaultContent + 默认值 + + + #Response + 相应 + + + HTTP + HTTP + + + #Path + 路径 + + + WebSocket + WebSocket + + + #Headers + 头伪装 + + + mKCP + mKCP + + + #MTU + 最大传输单元 + + + #TTI (ms) + 传输时间间隔 + + + #UplinkCapacity (MB/s) + 上行链路容量 (MB/s) + + + #Congestion + 拥塞控制 + + + #Enabled + 启用 + + + #DownlinkCapacity (MB/s) + 下行链路容量 (MB/s) + + + #ReadBufferSize (MB) + 读取缓冲区大小 (MB) + + + #WriteBufferSize (MB) + 写入缓冲区大小 (MB) + + + #Header + 头伪装 + + + srtp (SRTP, FaceTime) + srtp (SRTP, FaceTime) + + + utp (BitTorrent) + utp (BitTorrent) + + + wechat-video (WeChat Video Message) + wechat-video (WeChat Video Message) + + + dtls (DTLS 1.2) + dtls (DTLS 1.2) + + + wireguard (WireGuard fake packets) + wireguard (WireGuard fake packets) + + + DomainSocket + DomainSocket + + + QUIC + QUIC + + + #Key + 密钥 + + + + Hv2ray::Ui::ConnectionEditWindow + + + #ConnectionSettings + 连接设置 + + + + + #Host + 域名 + + + + #Port + 端口 + + + + #Name + 名称 + + + + #UUID + UUID + + + + #AlterID + Alter ID + + + + + #Security + 安全设置 + + + + auto + 自动 + + + + + aes-128-gcm + aes-128-gcm + + + + + chacha20-poly1305 + chacha20-poly1305 + + + + + + + + none + 不使用 + + + + #Transport + 传输设置 + + + + tcp (TCP) + tcp (TCP) + + + + http (HTTP) + http (HTTP) + + + + ws (WebSocket) + ws (WebSocket) + + + + kcp (mKCP) + kcp (mKCP) + + + + domainsocket (Domain Socket) + domainsocket (Domain Socket) + + + + quic (Quick UDP Internet Connection) + quic (Quick UDP Internet Connection) + + + + #TransportSettings + 传输设置 + + + + TCP + TCP + + + + http + HTTP + + + + + + #Type + 类型 + + + + #Request + 请求 + + + + + #InsertDefaultContent + 默认值 + + + + #Response + 相应 + + + + HTTP + HTTP + + + + + + #Path + 路径 + + + + WebSocket + WebSocket + + + + + #Headers + 头伪装 + + + + mKCP + mKCP + + + + #MTU + 最大传输单元 + + + + #TTI (ms) + 传输时间间隔 + + + + #UplinkCapacity (MB/s) + 上行链路容量 (MB/s) + + + + #Congestion + 拥塞控制 + + + + #Enabled + 启用 + + + + #DownlinkCapacity (MB/s) + 下行链路容量 (MB/s) + + + + #ReadBufferSize (MB) + 读取缓冲区大小 (MB) + + + + #WriteBufferSize (MB) + 写入缓冲区大小 (MB) + + + + + #Header + 头伪装 + + + + + srtp (SRTP, FaceTime) + srtp (SRTP, FaceTime) + + + + + utp (BitTorrent) + utp (BitTorrent) + + + + + wechat-video (WeChat Video Message) + wechat-video (WeChat Video Message) + + + + + dtls (DTLS 1.2) + dtls (DTLS 1.2) + + + + + wireguard (WireGuard fake packets) + wireguard (WireGuard fake packets) + + + + DomainSocket + DomainSocket + + + + QUIC + QUIC + + + + #Key + 密钥 + + + + Hv2ray::Ui::ImportConfig + + + Import file + 导入文件 + + + + #ImportFrom + 导入源 + + + + Existing File + 现有文件 + + + + VMess Connection String + VMess 连接字符串 + + + + #FromFile + 从文件 + + + + #Path + 路径 + + + + #SelectFile + 选择文件 + + + + #Name + 名称 + + + + #Inbound + 入站设置 + + + + #UseCurrent + 使用现有设置 + + + + #UseImported + 使用导入的设置 + + + + #From VMess Connection String + 从 VMess 连接字符串 + + + + #VMess Connection String + VMess 连接字符串 + + + + OpenConfigFile + 打开配置文件 + + + + ImportConfig + 导入配置 + + + + CannotGenerateConfig + 无法生成配置文件 + + + + Hv2ray::Ui::MainWindow + + + + Hv2ray + Hv2ray + + + + + #Start + 启动 + + + + + #Stop + 停止 + + + + + #Restart + 重新启动 + + + + #ClearLog + 清除日志 + + + + #HostList + 服务器列表 + + + + #ConfigDetail + 配置详细信息 + + + + #Host + 域名 + + + + #Port + 端口 + + + + #UUID + UUID + + + + #Transport + 传输设置 + + + + + #ConnectionSettings + 连接设置 + + + + #File + 文件 + + + + #NewConnection + 新建连接 + + + + #ManuallyInput + 手动输入配置 + + + + #ImportConnection + 导入配置文件 + + + + #Exit + 退出 + + + + #Preferences + 首选项 + + + + + #Hide + 隐藏 + + + + #Quit + 退出 + + + + #Show + 显示 + + + + Hv2ray::Ui::PrefrencesWindow + + + + + Prefrences + 首选项 + + + + #General + 一般 + + + + #Language + 语言 + + + + zh-CN + + + + + en-US + + + + + #RunAsRoot + 使用 root 启动 + + + + + + + + + + #Enabled + 启用 + + + + #LogLevel + 日志等级 + + + + debug + 调试 + + + + info + 信息 + + + + warning + 警告 + + + + error + 错误 + + + none 不使用 - - #Transport - 传输设置 + + #MuxCool + Mux 设置 - - tcp (TCP) - tcp (TCP) + + #Concurrency + 最大并发连接数 - - http (HTTP) - http (HTTP) + + #InboundSettings + 入站设置 - - ws (WebSocket) - ws (WebSocket) - - - - kcp (mKCP) - kcp (mKCP) - - - - domainsocket (Domain Socket) - domainsocket (Domain Socket) - - - - quic (Quick UDP Internet Connection) - quic (Quick UDP Internet Connection) - - - - #TransportSettings - 传输设置 - - - - TCP - TCP - - - - http - HTTP - - - - - - #Type - 类型 - - - - #Request - 请求 - - - - - #InsertDefaultContent - 默认值 - - - - #Response - 相应 - - - + HTTP HTTP - - - - #Path - 路径 + + + #Port + 端口 - - WebSocket - WebSocket + + 8080 + - - - #Headers - 头伪装 + + + #Username + 用户名 - - mKCP - mKCP + + + #Auth + 鉴权 - - #MTU - 最大传输单元 + + + #Password + 密码 - - #TTI (ms) - 传输时间间隔 + + SOCKS + SOCKS - - #UplinkCapacity (MB/s) - 上行链路容量 (MB/s) + + 9001 + - - #Congestion - 拥塞控制 + + #Prefrences + 首选项 - - #Enabled - 启用 + + #CannotOpenConfigFile + 无法打开配置文件 - - #DownlinkCapacity (MB/s) - 下行链路容量 (MB/s) + + PortNumbersCannotBeSame + 端口号不能相同 - - #ReadBufferSize (MB) - 读取缓冲区大小 (MB) - - - - #WriteBufferSize (MB) - 写入缓冲区大小 (MB) - - - - - #Header - 头伪装 - - - - - srtp (SRTP, FaceTime) - srtp (SRTP, FaceTime) - - - - - utp (BitTorrent) - utp (BitTorrent) - - - - - wechat-video (WeChat Video Message) - wechat-video (WeChat Video Message) - - - - - dtls (DTLS 1.2) - dtls (DTLS 1.2) - - - - - wireguard (WireGuard fake packets) - wireguard (WireGuard fake packets) - - - - DomainSocket - DomainSocket - - - - QUIC - QUIC - - - - #Key - 密钥 + + RunAsRootNotOnWindows + Windows 平台不支持这个选项 ImportConfig - Import file - 导入文件 + 导入文件 - #ImportFrom - 导入源 + 导入源 - Existing File - 现有文件 + 现有文件 - VMess Connection String - VMess 连接字符串 + VMess 连接字符串 - #FromFile - 从文件 + 从文件 - #Path - 路径 + 路径 - #SelectFile - 选择文件 + 选择文件 - #Name - 名称 + 名称 - #Inbound - 入站设置 + 入站设置 - #UseCurrent - 使用现有设置 + 使用现有设置 - #UseImported - 使用导入的设置 + 使用导入的设置 - #From VMess Connection String - 从 VMess 连接字符串 + 从 VMess 连接字符串 - #VMess Connection String - VMess 连接字符串 + VMess 连接字符串 - OpenConfigFile - 打开配置文件 + 打开配置文件 - - - - ImportConfig - 导入配置 + 导入配置 - CannotOpenFile - 无法打开文件 + 无法打开文件 - SaveFailed - 保存失败 + 保存失败 - CannotCopyCustomConfig - 复制配置文件失败 + 复制配置文件失败 - CannotGenerateConfig - 无法生成配置文件 + 无法生成配置文件 MainWindow - - Hv2ray - Hv2ray + Hv2ray - - #Start - 启动 + 启动 - - #Stop - 停止 + 停止 - - #Restart - 重新启动 + 重新启动 - #ClearLog - 清除日志 + 清除日志 - #HostList - 服务器列表 + 服务器列表 - #ConfigDetail - 配置详细信息 + 配置详细信息 - #Host - 域名 + 域名 - #Port - 端口 + 端口 - #UUID - UUID + UUID - #Transport - 传输设置 + 传输设置 - - #ConnectionSettings - 连接设置 + 连接设置 - #File - 文件 + 文件 - #NewConnection - 新建连接 + 新建连接 - #ManuallyInput - 手动输入配置 + 手动输入配置 - #ImportConnection - 导入配置文件 + 导入配置文件 - #Exit - 退出 + 退出 - #Preferences - 首选项 + 首选项 - - #Hide - 隐藏 + 隐藏 - #Quit - 退出 + 退出 - #Show - 显示 + 显示 PrefrencesWindow - - - Prefrences - 首选项 + 首选项 - - zh-CN - - - - - en-US - - - - #General - 一般 + 一般 - #Language - 语言 + 语言 - #RunAsRoot - 使用 root 启动 + 使用 root 启动 - - - - - - - #Enabled - 启用 + 启用 - #LogLevel - 日志等级 + 日志等级 - debug - 调试 + 调试 - info - 信息 + 信息 - warning - 警告 + 警告 - error - 错误 + 错误 - none - 不使用 + 不使用 - #MuxCool - Mux 设置 + Mux 设置 - #Concurrency - 最大并发连接数 + 最大并发连接数 - #InboundSettings - 入站设置 + 入站设置 - - #Port - 端口 + 端口 - - #Username - 用户名 + 用户名 - - #Auth - 鉴权 + 鉴权 - - #Password - 密码 + 密码 - HTTP - HTTP + HTTP - - 8080 - - - - SOCKS - SOCKS + SOCKS - - 9001 - - - - #Prefrences - 首选项 + 首选项 - #CannotOpenConfigFile - 无法打开配置文件 + 无法打开配置文件 - PortNumbersCannotBeSame - 端口号不能相同 + 端口号不能相同 - RunAsRootNotOnWindows - Windows 平台不支持这个选项 + Windows 平台不支持这个选项 QObject - + Hv2Ray Hv2ray - + AnotherInstanceRunning 另一个实例正在运行 - + CoreNotFound 核心文件未找到 - + CoreFileNotFoundExplaination 请到官网或 GitHub 下载最新版本的 v2ray 主程序 - + ConfigurationError 配置出错