mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 02:40:20 +08:00
[Added][Fixed] Added JSON parse libraries, and fixed namespace structure.
Signed-off-by: Leroy.H.Y <lhy20010403@hotmail.com>
Former-commit-id: 7aaff60ff4
This commit is contained in:
parent
a0fb909d10
commit
d3e3f14ae2
@ -2,6 +2,7 @@ install:
|
|||||||
- set QTDIR=C:\Qt\5.10\mingw53_32
|
- set QTDIR=C:\Qt\5.10\mingw53_32
|
||||||
- choco install -y InnoSetup
|
- choco install -y InnoSetup
|
||||||
- set PATH=%QTDIR%\bin;C:\Qt\Tools\mingw730_32\bin;%PATH%;"C:\Program Files (x86)\Inno Setup 5"
|
- set PATH=%QTDIR%\bin;C:\Qt\Tools\mingw730_32\bin;%PATH%;"C:\Program Files (x86)\Inno Setup 5"
|
||||||
|
- git submodule update --init
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- mkdir python37 && xcopy C:\Python37 python37 /E /H /Q
|
- mkdir python37 && xcopy C:\Python37 python37 /E /H /Q
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "3rdparty/jsoncons"]
|
||||||
|
path = 3rdparty/jsoncons
|
||||||
|
url = https://github.com/danielaparker/jsoncons
|
@ -21,6 +21,7 @@ before_script:
|
|||||||
- if [ "$BADGE" = "osx" ]; then export PATH="/usr/local/opt/qt/bin:$PATH"; fi
|
- if [ "$BADGE" = "osx" ]; then export PATH="/usr/local/opt/qt/bin:$PATH"; fi
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
- git submodule update --init
|
||||||
- lrelease ./Hv2ray.pro
|
- lrelease ./Hv2ray.pro
|
||||||
- mkdir build && cd ./build
|
- mkdir build && cd ./build
|
||||||
- QT_SELECT=5 QTDIR=/usr/share/qt5 qmake ../
|
- QT_SELECT=5 QTDIR=/usr/share/qt5 qmake ../
|
||||||
|
1
3rdparty/jsoncons
vendored
Submodule
1
3rdparty/jsoncons
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 11d0da64cf9e8725aa9963c307c8df4957359eef
|
53
Hv2ray.pro
53
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.
|
# 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
|
#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 += \
|
SOURCES += \
|
||||||
./src/w_MainWindow.cpp \
|
src/Hutils.cpp \
|
||||||
./src/w_ConnectionEditWindow.cpp \
|
src/w_MainWindow.cpp \
|
||||||
./src/w_ImportConfig.cpp \
|
src/w_ConnectionEditWindow.cpp \
|
||||||
./src/w_PrefrencesWindow.cpp \
|
src/w_ImportConfig.cpp \
|
||||||
./src/main.cpp \
|
src/w_PrefrencesWindow.cpp \
|
||||||
./src/vinteract.cpp \
|
src/main.cpp \
|
||||||
./src/utils.cpp \
|
src/vinteract.cpp \
|
||||||
./src/runguard.cpp
|
src/runguard.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
./src/w_MainWindow.h \
|
src/HUtils.h \
|
||||||
./src/w_ConnectionEditWindow.h \
|
src/Hv2ConfigObject.h \
|
||||||
./src/w_ImportConfig.h \
|
src/w_MainWindow.h \
|
||||||
./src/w_PrefrencesWindow.h \
|
src/w_ConnectionEditWindow.h \
|
||||||
./src/constants.h \
|
src/w_ImportConfig.h \
|
||||||
./src/vinteract.h \
|
src/w_PrefrencesWindow.h \
|
||||||
./src/utils.h \
|
src/vinteract.h \
|
||||||
./src/runguard.h
|
src/runguard.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
./src/w_MainWindow.ui \
|
src/w_MainWindow.ui \
|
||||||
./src/w_ConnectionEditWindow.ui \
|
src/w_ConnectionEditWindow.ui \
|
||||||
./src/w_ImportConfig.ui \
|
src/w_ImportConfig.ui \
|
||||||
./src/w_PrefrencesWindow.ui
|
src/w_PrefrencesWindow.ui
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
./resources.qrc
|
resources.qrc
|
||||||
|
|
||||||
|
|
||||||
TRANSLATIONS += \
|
TRANSLATIONS += \
|
||||||
./translations/zh-CN.ts \
|
translations/zh-CN.ts \
|
||||||
./translations/en-US.ts
|
translations/en-US.ts
|
||||||
|
|
||||||
RC_ICONS += ./icons/Hv2ray.ico
|
RC_ICONS += ./icons/Hv2ray.ico
|
||||||
|
|
||||||
|
INCLUDEPATH += 3rdparty/\
|
||||||
|
3rdparty/jsoncons/include
|
||||||
|
|
||||||
|
|
||||||
# Default rules for deployment.
|
# Default rules for deployment.
|
||||||
qnx: target.path = /tmp/$${TARGET}/bin
|
qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
|
46
src/HUtils.h
Normal file
46
src/HUtils.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#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 <typename TYPE>
|
||||||
|
QString StructToJSON(const TYPE &t)
|
||||||
|
{
|
||||||
|
string s;
|
||||||
|
encode_json<TYPE>(t, s, indenting::indent);
|
||||||
|
return QString::fromStdString(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TYPE>
|
||||||
|
TYPE StructFromJSON(const std::string &str)
|
||||||
|
{
|
||||||
|
TYPE v = decode_json<TYPE>(str);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UTILS_H
|
@ -1,31 +1,27 @@
|
|||||||
#include <QJsonArray>
|
#include "HUtils.h"
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#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()
|
QJsonObject returnObj = obj.value(value).isNull()
|
||||||
? obj.value(value).toObject()
|
? obj.value(value).toObject()
|
||||||
: obj.value(value).toArray().first().toObject();
|
: obj.value(value).toArray().first().toObject();
|
||||||
return returnObj;
|
return returnObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject findValueFromJsonArray(QJsonArray arr, QString key, QString val)
|
QJsonObject Utils::findValueFromJsonArray(QJsonArray arr, QString key, QString val)
|
||||||
{
|
{
|
||||||
for (const auto obj : arr) {
|
for (const auto obj : arr) {
|
||||||
if (obj.toObject().value(key).toString() == val) {
|
if (obj.toObject().value(key).toString() == val) {
|
||||||
return obj.toObject();
|
return obj.toObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject loadRootObjFromConf()
|
QJsonObject Utils::loadRootObjFromConf()
|
||||||
{
|
{
|
||||||
QFile globalConfigFile("Hv2ray.conf");
|
QFile globalConfigFile("Hv2ray.conf");
|
||||||
globalConfigFile.open(QIODevice::ReadOnly);
|
globalConfigFile.open(QIODevice::ReadOnly);
|
||||||
@ -36,25 +32,19 @@ QJsonObject loadRootObjFromConf()
|
|||||||
return rootObj;
|
return rootObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray getInbounds()
|
QJsonArray Utils::getInbounds()
|
||||||
{
|
{
|
||||||
QJsonArray inbounds;
|
QJsonArray inbounds;
|
||||||
inbounds = loadRootObjFromConf().value("inbounds").toArray();
|
inbounds = loadRootObjFromConf().value("inbounds").toArray();
|
||||||
return inbounds;
|
return inbounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getRootEnabled()
|
void Utils::showWarnMessageBox(QWidget *parent, QString title, QString text)
|
||||||
{
|
|
||||||
return loadRootObjFromConf().value("v2suidEnabled").toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void showWarnMessageBox(QWidget* parent, QString title, QString text)
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void overrideInbounds(QString path)
|
void Utils::overrideInbounds(QString path)
|
||||||
{
|
{
|
||||||
QFile confFile(path);
|
QFile confFile(path);
|
||||||
confFile.open(QIODevice::ReadOnly);
|
confFile.open(QIODevice::ReadOnly);
|
||||||
@ -74,15 +64,29 @@ void overrideInbounds(QString path)
|
|||||||
confFile.close();
|
confFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getIndexByValue(QJsonArray array, QString key, QString val)
|
int Utils::getIndexByValue(QJsonArray array, QString key, QString val)
|
||||||
{
|
{
|
||||||
QJsonArray::iterator it;
|
QJsonArray::iterator it;
|
||||||
int index = 0;
|
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;
|
return index;
|
||||||
}
|
}
|
||||||
index ++;
|
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
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;
|
||||||
|
}
|
387
src/Hv2ConfigObject.h
Normal file
387
src/Hv2ConfigObject.h
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <jsoncons/json.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define USE_JSON_CONS
|
||||||
|
#ifdef USE_JSON_CONS
|
||||||
|
#include <jsoncons/json.hpp>
|
||||||
|
#else
|
||||||
|
#include <x2struct/x2struct.hpp>
|
||||||
|
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<string> services;
|
||||||
|
ApiObject() : tag(), services() {}
|
||||||
|
//XTOSTRUCT(O(tag, services))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ServerObject {
|
||||||
|
string address;
|
||||||
|
int port;
|
||||||
|
list<string> domains;
|
||||||
|
ServerObject(): address(), port(), domains() {}
|
||||||
|
//XTOSTRUCT(O(address, port, domains))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DnsObject {
|
||||||
|
map<string, string> hosts;
|
||||||
|
tuple<string, string, list<ServerObject>> servers;
|
||||||
|
DnsObject(): hosts(), servers() {}
|
||||||
|
//XTOSTRUCT(O(hosts, servers))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RuleObject {
|
||||||
|
string type = "field";
|
||||||
|
list<string> domain;
|
||||||
|
list<string> ip;
|
||||||
|
string port;
|
||||||
|
string network;
|
||||||
|
list<string> source;
|
||||||
|
list<string> 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<string> selector;
|
||||||
|
BalancerObject() : tag(), selector() {}
|
||||||
|
//XTOSTRUCT(O(tag, selector))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RoutingObject {
|
||||||
|
string domainStrategy;
|
||||||
|
list<RuleObject> rules;
|
||||||
|
list<BalancerObject> 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<int, LevelPolicyObject> level;
|
||||||
|
list<SystemPolicyObject> system;
|
||||||
|
PolicyObject(): level(), system() {}
|
||||||
|
//XTOSTRUCT(O(level, system))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HTTPRequestObject {
|
||||||
|
string version;
|
||||||
|
string method;
|
||||||
|
list<string> path;
|
||||||
|
map<string, list<string>> headers;
|
||||||
|
HTTPRequestObject(): version(), method(), path(), headers() {}
|
||||||
|
//XTOSTRUCT(O(version, method, path, headers))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HTTPResponseObject {
|
||||||
|
string version;
|
||||||
|
string status;
|
||||||
|
string reason;
|
||||||
|
map<string, list<string>> 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<string, string> headers;
|
||||||
|
WebSocketObject(): path(), headers() {}
|
||||||
|
//XTOSTRUCT(O(path, headers))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HttpObject {
|
||||||
|
list<string> 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<BridgeObject> bridges;
|
||||||
|
list<PortalObject> portals;
|
||||||
|
ReverseObject() : bridges(), portals() {}
|
||||||
|
//XTOSTRUCT(O(bridges, portals))
|
||||||
|
};
|
||||||
|
struct RootObject {
|
||||||
|
LogObject log;
|
||||||
|
ApiObject api;
|
||||||
|
DnsObject dns;
|
||||||
|
RoutingObject routing;
|
||||||
|
list<InboundObject> inbounds;
|
||||||
|
list<OutboundObject> 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
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
#include <QString>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#ifndef CONSTANTS_H
|
|
||||||
#define CONSTANTS_H
|
|
||||||
|
|
||||||
// Macros
|
|
||||||
#define HV2RAY_CONFIG_DIR_NAME ".hv2ray"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Hv2rayUtils {
|
|
||||||
static QDir ConfigDir;
|
|
||||||
} // namespace Hv2rayConsts
|
|
||||||
|
|
||||||
#endif // CONSTANTS_H
|
|
136
src/main.cpp
136
src/main.cpp
@ -1,100 +1,112 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
|
||||||
#include <iostream>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonValue>
|
#include <QJsonDocument>
|
||||||
|
#include <QStandardPaths>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <iostream>
|
||||||
|
#include <jsoncons/json.hpp>
|
||||||
|
|
||||||
#include "runguard.h"
|
#include "runguard.h"
|
||||||
#include "utils.h"
|
#include "HUtils.h"
|
||||||
#include "w_MainWindow.h"
|
#include "Hv2ConfigObject.h"
|
||||||
#include "w_ConnectionEditWindow.h"
|
#include "w_ConnectionEditWindow.h"
|
||||||
#include "constants.h"
|
#include "w_MainWindow.h"
|
||||||
|
|
||||||
using namespace std;
|
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()) {
|
if (!ConfigDir.exists()) {
|
||||||
QDir(QDir::homePath()).mkdir(".hv2ray");
|
auto result = QDir().mkdir(configPath);
|
||||||
qDebug() << "Config directory created.";
|
|
||||||
|
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 (!configFile.open(QIODevice::WriteOnly)) {
|
||||||
if(!hvConfInfo.exists()) {
|
qDebug() << "Failed to create main config file.";
|
||||||
QFile confFile("conf/Hv2ray.config.json");
|
return false;
|
||||||
if(!confFile.open(QIODevice::ReadWrite)) {
|
|
||||||
qDebug() << "Can not open Hv2ray.conf.json for read and write.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject settings;
|
QTextStream stream(&configFile);
|
||||||
settings.insert("auth", "noauth");
|
stream << jsonConfig;
|
||||||
settings.insert("udp", true);
|
stream.flush();
|
||||||
settings.insert("ip", "127.0.0.1");
|
configFile.close();
|
||||||
|
// Create Placeholder for initialise indicator.
|
||||||
QJsonObject socks;
|
QFile initPlaceHolder(configPath + "/.initialised");
|
||||||
socks.insert("settings", QJsonValue(settings));
|
initPlaceHolder.open(QFile::WriteOnly);
|
||||||
socks.insert("tag", "socks-in");
|
initPlaceHolder.close();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication _qApp(argc, argv);
|
QApplication _qApp(argc, argv);
|
||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
if (translator.load(":/translations/zh-CN.qm", "translations"))
|
|
||||||
{
|
//
|
||||||
cout << "Loaded Chinese 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")){
|
} else if (translator.load(":/translations/en-US.qm", "translations")) {
|
||||||
cout << "Loaded English translations" << endl;
|
cout << "Loaded en-US translations" << endl;
|
||||||
} else {
|
} else {
|
||||||
showWarnMessageBox(nullptr, "Failed to load translations",
|
Utils::showWarnMessageBox(
|
||||||
"Failed to load translations, user experience may be downgraded. \r\n \
|
nullptr, "Failed to load translations 无法加载语言文件",
|
||||||
无法加载语言文件,用户体验可能会降级.");
|
"Failed to load translations, user experience may be downgraded. \r\n"
|
||||||
|
"无法加载语言文件,用户体验可能会降级.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_qApp.installTranslator(&translator);
|
_qApp.installTranslator(&translator);
|
||||||
|
|
||||||
RunGuard guard("Hv2ray-Instance-Identifier");
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GlobalConfig = StructFromJSON("");
|
||||||
|
// Set file startup path as Path
|
||||||
|
// WARNING: This may be changed in the future.
|
||||||
QDir::setCurrent(QFileInfo(QCoreApplication::applicationFilePath()).path());
|
QDir::setCurrent(QFileInfo(QCoreApplication::applicationFilePath()).path());
|
||||||
|
|
||||||
firstRunCheck();
|
firstRunCheck();
|
||||||
MainWindow w;
|
// Show MainWindow
|
||||||
|
Ui::MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
return _qApp.exec();
|
return _qApp.exec();
|
||||||
}
|
}
|
||||||
|
124
src/runguard.cpp
124
src/runguard.cpp
@ -1,77 +1,81 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
#include "runguard.h"
|
#include "runguard.h"
|
||||||
|
namespace Hv2ray
|
||||||
//from https://stackoverflow.com/a/28172162
|
|
||||||
namespace
|
|
||||||
{
|
{
|
||||||
|
|
||||||
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;
|
QByteArray data;
|
||||||
data.append( key.toUtf8() );
|
data.append(key.toUtf8());
|
||||||
data.append( salt.toUtf8() );
|
data.append(salt.toUtf8());
|
||||||
data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex();
|
data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
RunGuard::RunGuard(const QString &key)
|
||||||
}
|
: key(key)
|
||||||
|
, memLockKey(generateKeyHash(key, "_memLockKey"))
|
||||||
|
, sharedmemKey(generateKeyHash(key, "_sharedmemKey"))
|
||||||
RunGuard::RunGuard( const QString& key )
|
, sharedMem(sharedmemKey)
|
||||||
: key( key )
|
, memLock(memLockKey, 1)
|
||||||
, memLockKey( generateKeyHash( key, "_memLockKey" ) )
|
|
||||||
, sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) )
|
|
||||||
, sharedMem( sharedmemKey )
|
|
||||||
, memLock( memLockKey, 1 )
|
|
||||||
{
|
|
||||||
memLock.acquire();
|
|
||||||
{
|
{
|
||||||
QSharedMemory fix( sharedmemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/
|
memLock.acquire();
|
||||||
fix.attach();
|
{
|
||||||
|
QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/
|
||||||
|
fix.attach();
|
||||||
|
}
|
||||||
|
memLock.release();
|
||||||
}
|
}
|
||||||
memLock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
RunGuard::~RunGuard()
|
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 ) {
|
|
||||||
release();
|
release();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunGuard::release()
|
bool RunGuard::isAnotherRunning()
|
||||||
{
|
{
|
||||||
memLock.acquire();
|
if (sharedMem.isAttached()) {
|
||||||
if ( sharedMem.isAttached() ) {
|
return false;
|
||||||
sharedMem.detach();
|
}
|
||||||
|
|
||||||
|
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();
|
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,29 @@
|
|||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
#include <QSystemSemaphore>
|
#include <QSystemSemaphore>
|
||||||
|
|
||||||
// From https://stackoverflow.com/a/28172162
|
namespace Hv2ray
|
||||||
class RunGuard
|
|
||||||
{
|
{
|
||||||
|
// From https://stackoverflow.com/a/28172162
|
||||||
|
class RunGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RunGuard(const QString &key);
|
||||||
|
~RunGuard();
|
||||||
|
|
||||||
public:
|
bool isAnotherRunning();
|
||||||
RunGuard( const QString& key );
|
bool isSingleInstance();
|
||||||
~RunGuard();
|
void release();
|
||||||
|
|
||||||
bool isAnotherRunning();
|
private:
|
||||||
bool isSingleInstance();
|
QString generateKeyHash(const QString &key, const QString &salt);
|
||||||
void release();
|
const QString key;
|
||||||
|
const QString memLockKey;
|
||||||
|
const QString sharedmemKey;
|
||||||
|
|
||||||
private:
|
QSharedMemory sharedMem;
|
||||||
const QString key;
|
QSystemSemaphore memLock;
|
||||||
const QString memLockKey;
|
|
||||||
const QString sharedmemKey;
|
|
||||||
|
|
||||||
QSharedMemory sharedMem;
|
|
||||||
QSystemSemaphore memLock;
|
|
||||||
|
|
||||||
Q_DISABLE_COPY( RunGuard )
|
|
||||||
};
|
|
||||||
|
|
||||||
|
Q_DISABLE_COPY(RunGuard)
|
||||||
|
};
|
||||||
|
}
|
||||||
#endif // RUNGUARD_H
|
#endif // RUNGUARD_H
|
||||||
|
15
src/utils.h
15
src/utils.h
@ -1,15 +0,0 @@
|
|||||||
#include <QWidget>
|
|
||||||
|
|
||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
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
|
|
@ -1,79 +1,87 @@
|
|||||||
#include <QProcess>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QProcess>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "HUtils.h"
|
||||||
#include "w_MainWindow.h"
|
|
||||||
#include "vinteract.h"
|
#include "vinteract.h"
|
||||||
|
#include "w_MainWindow.h"
|
||||||
|
|
||||||
bool v2Instance::checkConfigFile(QString path)
|
namespace Hv2ray
|
||||||
{
|
{
|
||||||
if(checkVCoreExes()) {
|
bool v2Instance::checkConfigFile(const QString path)
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
{
|
||||||
env.insert("V2RAY_LOCATION_ASSET", QDir::currentPath());
|
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;
|
if (!process.waitForFinished()) {
|
||||||
process.setProcessEnvironment(env);
|
qDebug() << "v2ray core failed with exit code " << process.exitCode();
|
||||||
process.start("v2ray", QStringList() << "-test" << "-config" << path, QIODevice::ReadWrite | QIODevice::Text);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(!process.waitForFinished()) {
|
QString output = QString(process.readAllStandardOutput());
|
||||||
qDebug() << "v2ray core failed with exit code " << process.exitCode();
|
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString output = QString(process.readAllStandardOutput());
|
bool v2Instance::start()
|
||||||
|
{
|
||||||
if (!output.contains("Configuration OK")) {
|
if (this->vProcess->state() == QProcess::Running) {
|
||||||
showWarnMessageBox(nullptr, QObject::tr("ConfigurationError"), output.mid(output.indexOf("anti-censorship.") + 17));
|
this->stop();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else return true;
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
v2Instance::v2Instance(QWidget *parent)
|
if (checkVCoreExes()) {
|
||||||
{
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
this->vProcess = new QProcess();
|
env.insert("V2RAY_LOCATION_ASSET", QDir::currentPath());
|
||||||
QObject::connect(vProcess, SIGNAL(readyReadStandardOutput()), parent, SLOT(updateLog()));
|
this->vProcess->setProcessEnvironment(env);
|
||||||
}
|
this->vProcess->start("./v2ray", QStringList() << "-config"
|
||||||
|
<< "config.json",
|
||||||
bool v2Instance::checkVCoreExes()
|
QIODevice::ReadWrite | QIODevice::Text);
|
||||||
{
|
this->vProcess->waitForStarted();
|
||||||
if (QFileInfo("v2ray").exists() && QFileInfo("geoip.dat").exists() && QFileInfo("geosite.dat").exists() && QFileInfo("v2ctl").exists()) {
|
processStatus = STARTED;
|
||||||
return true;
|
return true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
showWarnMessageBox(nullptr, QObject::tr("CoreNotFound"), QObject::tr("CoreFileNotFoundExplaination"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool v2Instance::start()
|
void v2Instance::stop()
|
||||||
{
|
{
|
||||||
if(this->vProcess->state() == QProcess::Running) {
|
this->vProcess->close();
|
||||||
|
processStatus = STOPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
v2Instance::~v2Instance()
|
||||||
|
{
|
||||||
this->stop();
|
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();
|
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,33 @@
|
|||||||
#ifndef VINTERACT_H
|
#ifndef VINTERACT_H
|
||||||
#define VINTERACT_H
|
#define VINTERACT_H
|
||||||
#include <QString>
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
enum V2RAY_INSTANCE_STARTUP_STATUS {
|
namespace Hv2ray
|
||||||
STOPPED,
|
|
||||||
STARTING,
|
|
||||||
STARTED
|
|
||||||
};
|
|
||||||
|
|
||||||
class v2Instance
|
|
||||||
{
|
{
|
||||||
public:
|
enum V2RAY_INSTANCE_STARTUP_STATUS {
|
||||||
explicit v2Instance(QWidget *parent);
|
STOPPED,
|
||||||
|
STARTING,
|
||||||
|
STARTED
|
||||||
|
};
|
||||||
|
|
||||||
bool start();
|
class v2Instance
|
||||||
void stop();
|
{
|
||||||
void restart();
|
public:
|
||||||
|
explicit v2Instance(QWidget *parent);
|
||||||
|
|
||||||
static bool checkVCoreExes();
|
bool start();
|
||||||
static bool checkConfigFile(QString path);
|
void stop();
|
||||||
~v2Instance();
|
void restart();
|
||||||
QProcess *vProcess;
|
|
||||||
private:
|
static bool checkVCoreExes();
|
||||||
V2RAY_INSTANCE_STARTUP_STATUS processStatus;
|
static bool checkConfigFile(QString path);
|
||||||
};
|
~v2Instance();
|
||||||
|
QProcess *vProcess;
|
||||||
|
|
||||||
|
private:
|
||||||
|
V2RAY_INSTANCE_STARTUP_STATUS processStatus;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VINTERACT_H
|
#endif // VINTERACT_H
|
||||||
|
@ -1,36 +1,34 @@
|
|||||||
#include "w_ConnectionEditWindow.h"
|
#include "w_ConnectionEditWindow.h"
|
||||||
#include "ui_w_ConnectionEditWindow.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include "w_MainWindow.h"
|
#include "w_MainWindow.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QIntValidator>
|
#include <QIntValidator>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
ConnectionEditWindow::ConnectionEditWindow(QWidget *parent) :
|
namespace Hv2ray::Ui
|
||||||
QDialog(parent),
|
|
||||||
ui(new Ui::ConnectionEditWindow)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ConnectionEditWindow::ConnectionEditWindow(QWidget *parent)
|
||||||
ui->portLineEdit->setValidator(new QIntValidator());
|
: QDialog(parent)
|
||||||
ui->alterLineEdit->setValidator(new QIntValidator());
|
, ui(new Ui_ConnectionEditWindow)
|
||||||
}
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->portLineEdit->setValidator(new QIntValidator());
|
||||||
|
ui->alterLineEdit->setValidator(new QIntValidator());
|
||||||
|
}
|
||||||
|
|
||||||
ConnectionEditWindow::~ConnectionEditWindow()
|
ConnectionEditWindow::~ConnectionEditWindow()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
int Hv2Config::save()
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hv2Config::getConfigFromDialog(Ui::ConnectionEditWindow *ui)
|
//void ConnectionEditWindow::getConfigFromDialog(Ui::ConnectionEditWindow *ui)
|
||||||
{
|
//{
|
||||||
this->host = ui->ipLineEdit->text();
|
//this->host = ui->ipLineEdit->text();
|
||||||
this->port = ui->portLineEdit->text();
|
//this->port = ui->portLineEdit->text();
|
||||||
this->alias = ui->aliasLineEdit->text();
|
//this->alias = ui->aliasLineEdit->text();
|
||||||
this->uuid = ui->idLineEdit->text();
|
//this->uuid = ui->idLineEdit->text();
|
||||||
this->alterid = ui->alterLineEdit->text();
|
//this->alterid = ui->alterLineEdit->text();
|
||||||
this->security = ui->securityCombo->currentText();
|
//this->security = ui->securityCombo->currentText();
|
||||||
this->isCustom = 0;
|
//this->isCustom = 0;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
@ -2,39 +2,20 @@
|
|||||||
#define CONFEDIT_H
|
#define CONFEDIT_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#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
|
#endif // CONFEDIT_H
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ConnectionEditWindow</class>
|
<class>Hv2ray::Ui::ConnectionEditWindow</class>
|
||||||
<widget class="QDialog" name="ConnectionEditWindow">
|
<widget class="QDialog" name="Hv2ray::Ui::ConnectionEditWindow">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@ -864,7 +864,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>accepted()</signal>
|
<signal>accepted()</signal>
|
||||||
<receiver>ConnectionEditWindow</receiver>
|
<receiver>Hv2ray::Ui::ConnectionEditWindow</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
@ -880,7 +880,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>rejected()</signal>
|
<signal>rejected()</signal>
|
||||||
<receiver>ConnectionEditWindow</receiver>
|
<receiver>Hv2ray::Ui::ConnectionEditWindow</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
|
@ -1,131 +1,134 @@
|
|||||||
#include <QFileDialog>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
|
||||||
|
|
||||||
#pragma push_macro("slots")
|
#pragma push_macro("slots")
|
||||||
#undef slots
|
#undef slots
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#pragma pop_macro("slots")
|
#pragma pop_macro("slots")
|
||||||
|
|
||||||
#include "w_ConnectionEditWindow.h"
|
#include "HUtils.h"
|
||||||
#include "vinteract.h"
|
#include "vinteract.h"
|
||||||
#include "utils.h"
|
#include "w_ConnectionEditWindow.h"
|
||||||
#include "w_ImportConfig.h"
|
#include "w_ImportConfig.h"
|
||||||
#include "ui_w_ImportConfig.h"
|
|
||||||
|
|
||||||
|
using namespace Hv2ray;
|
||||||
ImportConfig::ImportConfig(QWidget *parent) :
|
namespace Hv2ray::Ui
|
||||||
QDialog(parent),
|
|
||||||
ui(new Ui::ImportConfig)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ImportConfig::ImportConfig(QWidget *parent)
|
||||||
connect(this, SIGNAL(updateConfTable()), parentWidget(), SLOT(updateConfTable()));
|
: QDialog(parent)
|
||||||
}
|
, ui(new Ui_ImportConfig)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
showWarnMessageBox(this, tr("ImportConfig"), tr("SaveFailed"));
|
ui->setupUi(this);
|
||||||
qDebug() << "ImportConfig::SaveFailed";
|
connect(this, SIGNAL(updateConfTable()), parentWidget(), SLOT(updateConfTable()));
|
||||||
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()
|
ImportConfig::~ImportConfig()
|
||||||
{
|
|
||||||
QString alias = ui->nameTxt->text();
|
|
||||||
if(ui->importSourceCombo->currentIndex() == 0) // From File...
|
|
||||||
{
|
{
|
||||||
QString path = ui->fileLineTxt->text();
|
delete ui;
|
||||||
bool isValid = v2Instance::checkConfigFile(path);
|
|
||||||
if(isValid) {
|
|
||||||
savefromFile(path, alias);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
void ImportConfig::on_pushButton_clicked()
|
||||||
{
|
{
|
||||||
QString vmess = ui->vmessConnectionStringTxt->toPlainText();
|
QString dir = QFileDialog::getOpenFileName(this, tr("OpenConfigFile"), "~/");
|
||||||
Py_Initialize();
|
ui->fileLineTxt->setText(dir);
|
||||||
assert(Py_IsInitialized());
|
}
|
||||||
QString param = "--inbound socks:1080 " + vmess + " -o config.json.tmp";
|
|
||||||
PyRun_SimpleString("import sys");
|
void ImportConfig::savefromFile(QString path, QString alias)
|
||||||
PyRun_SimpleString("sys.path.append('./utils')");
|
{
|
||||||
PyObject *pModule = PyImport_ImportModule("vmess2json");
|
Q_UNUSED(path)
|
||||||
PyObject *pFunc = PyObject_GetAttrString(pModule, "main");
|
Q_UNUSED(alias)
|
||||||
PyObject *arg = PyTuple_New(1);
|
//Hv2Config newConfig;
|
||||||
PyObject *arg1 = Py_BuildValue("s", param.toStdString().c_str());
|
//newConfig.alias = alias;
|
||||||
PyTuple_SetItem(arg, 0, arg1);
|
//QFile configFile(path);
|
||||||
PyObject_CallObject(pFunc, arg);
|
//if(!configFile.open(QIODevice::ReadOnly)) {
|
||||||
Py_Finalize();
|
// showWarnMessageBox(this, tr("ImportConfig"), tr("CannotOpenFile"));
|
||||||
if(QFile::exists(QCoreApplication::applicationDirPath() + "/config.json.tmp")) {
|
// qDebug() << "ImportConfig::CannotOpenFile";
|
||||||
ImportConfig *im = new ImportConfig(this->parentWidget());
|
// return;
|
||||||
if (v2Instance::checkConfigFile(QCoreApplication::applicationDirPath() + "/config.json.tmp")) {
|
//}
|
||||||
im->savefromFile("config.json.tmp", alias);
|
//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 {
|
} else {
|
||||||
showWarnMessageBox(this, tr("ImportConfig"), tr("CannotGenerateConfig"));
|
QString vmess = ui->vmessConnectionStringTxt->toPlainText();
|
||||||
qDebug() << "ImportConfig::CannotGenerateConfig";
|
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....
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,31 @@
|
|||||||
#define IMPORTCONF_H
|
#define IMPORTCONF_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#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
|
#endif // IMPORTCONF_H
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ImportConfig</class>
|
<class>Hv2ray::Ui::ImportConfig</class>
|
||||||
<widget class="QDialog" name="ImportConfig">
|
<widget class="QDialog" name="Hv2ray::Ui::ImportConfig">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@ -162,7 +162,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>accepted()</signal>
|
<signal>accepted()</signal>
|
||||||
<receiver>ImportConfig</receiver>
|
<receiver>Hv2ray::Ui::ImportConfig</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
@ -178,7 +178,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>rejected()</signal>
|
<signal>rejected()</signal>
|
||||||
<receiver>ImportConfig</receiver>
|
<receiver>Hv2ray::Ui::ImportConfig</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
|
@ -1,274 +1,279 @@
|
|||||||
#include <QHeaderView>
|
|
||||||
#include <QStandardItemModel>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QFile>
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QHeaderView>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
#include "ui_w_MainWindow.h"
|
#include "HUtils.h"
|
||||||
#include "w_PrefrencesWindow.h"
|
#include "vinteract.h"
|
||||||
#include "w_MainWindow.h"
|
|
||||||
#include "w_ConnectionEditWindow.h"
|
#include "w_ConnectionEditWindow.h"
|
||||||
#include "w_ImportConfig.h"
|
#include "w_ImportConfig.h"
|
||||||
#include "vinteract.h"
|
#include "w_MainWindow.h"
|
||||||
#include "utils.h"
|
#include "w_PrefrencesWindow.h"
|
||||||
|
|
||||||
void MainWindow::CreateTrayIcon()
|
namespace Hv2ray::Ui
|
||||||
{
|
{
|
||||||
hTray = new QSystemTrayIcon();
|
void MainWindow::CreateTrayIcon()
|
||||||
hTray->setToolTip(tr("Hv2ray"));
|
{
|
||||||
hTray->setIcon(this->windowIcon());
|
hTray = new QSystemTrayIcon();
|
||||||
connect(hTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_activatedTray(QSystemTrayIcon::ActivationReason)));
|
hTray->setToolTip(tr("Hv2ray"));
|
||||||
|
hTray->setIcon(this->windowIcon());
|
||||||
QAction *actionShow = new QAction(this);
|
connect(hTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_activatedTray(QSystemTrayIcon::ActivationReason)));
|
||||||
QAction *actionQuit = new QAction(this);
|
QAction *actionShow = new QAction(this);
|
||||||
QAction *actionStart = new QAction(this);
|
QAction *actionQuit = new QAction(this);
|
||||||
QAction *actionRestart = new QAction(this);
|
QAction *actionStart = new QAction(this);
|
||||||
QAction *actionStop = new QAction(this);
|
QAction *actionRestart = new QAction(this);
|
||||||
|
QAction *actionStop = new QAction(this);
|
||||||
actionShow->setText(tr("#Hide"));
|
actionShow->setText(tr("#Hide"));
|
||||||
actionQuit->setText(tr("#Quit"));
|
actionQuit->setText(tr("#Quit"));
|
||||||
actionStart->setText(tr("#Start"));
|
actionStart->setText(tr("#Start"));
|
||||||
actionStop->setText(tr("#Stop"));
|
actionStop->setText(tr("#Stop"));
|
||||||
actionRestart->setText(tr("#Restart"));
|
actionRestart->setText(tr("#Restart"));
|
||||||
actionStart->setEnabled(true);
|
actionStart->setEnabled(true);
|
||||||
actionStop->setEnabled(false);
|
actionStop->setEnabled(false);
|
||||||
actionRestart->setEnabled(false);
|
actionRestart->setEnabled(false);
|
||||||
|
trayMenu->addAction(actionShow);
|
||||||
trayMenu->addAction(actionShow);
|
trayMenu->addSeparator();
|
||||||
trayMenu->addSeparator();
|
trayMenu->addAction(actionStart);
|
||||||
trayMenu->addAction(actionStart);
|
trayMenu->addAction(actionStop);
|
||||||
trayMenu->addAction(actionStop);
|
trayMenu->addAction(actionRestart);
|
||||||
trayMenu->addAction(actionRestart);
|
trayMenu->addSeparator();
|
||||||
trayMenu->addSeparator();
|
trayMenu->addAction(actionQuit);
|
||||||
trayMenu->addAction(actionQuit);
|
connect(actionShow, SIGNAL(triggered()), this, SLOT(toggleMainWindowVisibility()));
|
||||||
|
connect(actionStart, SIGNAL(triggered()), this, SLOT(on_startButton_clicked()));
|
||||||
connect(actionShow, SIGNAL(triggered()), this, SLOT(toggleMainWindowVisibility()));
|
connect(actionStop, SIGNAL(triggered()), this, SLOT(on_stopButton_clicked()));
|
||||||
connect(actionStart, SIGNAL(triggered()), this, SLOT(on_startButton_clicked()));
|
connect(actionRestart, SIGNAL(triggered()), this, SLOT(on_restartButton_clicked()));
|
||||||
connect(actionStop, SIGNAL(triggered()), this, SLOT(on_stopButton_clicked()));
|
connect(actionQuit, SIGNAL(triggered()), this, SLOT(quit()));
|
||||||
connect(actionRestart, SIGNAL(triggered()), this, SLOT(on_restartButton_clicked()));
|
hTray->setContextMenu(trayMenu);
|
||||||
connect(actionQuit, SIGNAL(triggered()), this, SLOT(quit()));
|
hTray->show();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QAction *select = new QAction("Select", ui->configTable);
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
// QAction *del = new QAction("Delete", ui->configTable);
|
: QMainWindow(parent)
|
||||||
// QAction *rename = new QAction("Rename", ui->configTable);
|
, ui(new Ui_MainWindow)
|
||||||
// popMenu->addAction(select);
|
{
|
||||||
// popMenu->addAction(del);
|
this->setWindowIcon(QIcon(":/icons/Hv2ray.ico"));
|
||||||
// popMenu->addAction(rename);
|
ui->setupUi(this);
|
||||||
// connect(select, SIGNAL(triggered()), this, SLOT(select_triggered()));
|
UpdateConfigTable();
|
||||||
// connect(del, SIGNAL(triggered()), this, SLOT(delConf()));
|
// ui->configTable->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
// connect(rename, SIGNAL(triggered()), this, SLOT(renameRow()));
|
// connect(ui->configTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
|
||||||
// connect(ui->logText, SIGNAL(textChanged()), this, SLOT(scrollToBottom()));
|
this->vinstance = new v2Instance(this);
|
||||||
// bar = ui->logText->verticalScrollBar();
|
CreateTrayIcon();
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
if (QFileInfo("config.json").exists()) {
|
||||||
{
|
vinstance->start();
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
QFile::copy(src, "config.json");
|
|
||||||
} else {
|
// QAction *select = new QAction("Select", ui->configTable);
|
||||||
// TODO: Config generator
|
// 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()
|
MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
ui->logText->clear();
|
hTray->hide();
|
||||||
bool startFlag = this->vinstance->start();
|
delete this->hTray;
|
||||||
trayMenu->actions()[2]->setEnabled(!startFlag);
|
delete this->vinstance;
|
||||||
trayMenu->actions()[3]->setEnabled(startFlag);
|
delete ui;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::toggleMainWindowVisibility()
|
void MainWindow::on_actionEdit_triggered()
|
||||||
{
|
{
|
||||||
if(this->isHidden()) {
|
ConnectionEditWindow *e = new ConnectionEditWindow(this);
|
||||||
this->show();
|
e->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
trayMenu->actions()[0]->setText(tr("#Hide"));
|
e->show();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
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();
|
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();
|
|
||||||
}
|
|
||||||
|
@ -1,60 +1,60 @@
|
|||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
#include <QMainWindow>
|
|
||||||
#include "w_ConnectionEditWindow.h"
|
#include "w_ConnectionEditWindow.h"
|
||||||
#include <QSystemTrayIcon>
|
#include <QMainWindow>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
|
#include "ui_w_MainWindow.h"
|
||||||
#include "vinteract.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
|
#endif // MAINWINDOW_H
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>MainWindow</class>
|
<class>Hv2ray::Ui::MainWindow</class>
|
||||||
<widget class="QMainWindow" name="MainWindow">
|
<widget class="QMainWindow" name="Hv2ray::Ui::MainWindow">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
|
@ -1,159 +1,178 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QFile>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
#include <QIntValidator>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <unistd.h>
|
|
||||||
#include <ui_w_PrefrencesWindow.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
#include "HUtils.h"
|
||||||
#include "vinteract.h"
|
#include "vinteract.h"
|
||||||
#include "w_PrefrencesWindow.h"
|
#include "w_PrefrencesWindow.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
PrefrencesWindow::PrefrencesWindow(QWidget *parent) :
|
using namespace Hv2ray;
|
||||||
QDialog(parent),
|
using namespace Utils;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (rootObj.value("v2suidEnabled").toBool()) {
|
||||||
{
|
ui->runAsRootCheckBox->setCheckState(Qt::Checked);
|
||||||
if(v2Instance::checkVCoreExes()) {
|
}
|
||||||
if(ui->httpPortLE->text().toInt() != ui->socksPortLE->text().toInt()) {
|
|
||||||
QJsonArray inbounds;
|
if (!http.isEmpty()) {
|
||||||
QJsonDocument modifiedDoc;
|
ui->httpPortLE->setText(http.value("port").toString());
|
||||||
inbounds = rootObj.value("inbounds").toArray();
|
ui->httpCB->setCheckState(Qt::Checked);
|
||||||
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 {
|
} 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)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
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
|
|
||||||
}
|
|
||||||
|
@ -2,34 +2,32 @@
|
|||||||
#define HVCONF_H
|
#define HVCONF_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <ui_w_PrefrencesWindow.h>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
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
|
#endif // HVCONF_H
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>PrefrencesWindow</class>
|
<class>Hv2ray::Ui::PrefrencesWindow</class>
|
||||||
<widget class="QDialog" name="PrefrencesWindow">
|
<widget class="QDialog" name="Hv2ray::Ui::PrefrencesWindow">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@ -345,7 +345,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>accepted()</signal>
|
<signal>accepted()</signal>
|
||||||
<receiver>PrefrencesWindow</receiver>
|
<receiver>Hv2ray::Ui::PrefrencesWindow</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
@ -361,7 +361,7 @@
|
|||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
<signal>rejected()</signal>
|
<signal>rejected()</signal>
|
||||||
<receiver>PrefrencesWindow</receiver>
|
<receiver>Hv2ray::Ui::PrefrencesWindow</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user