mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-19 18:30:34 +08:00
refactor: stage 3.5 class separation
This commit is contained in:
parent
a2d5920959
commit
36dc29bd9c
@ -1 +1 @@
|
||||
3403
|
||||
3423
|
||||
|
@ -120,9 +120,9 @@ Qv2rayAddSource(components, proxy, QvProxyConfigurator, cpp, hpp)
|
||||
Qv2rayAddSource(components, tcping, QvTCPing, cpp, hpp)
|
||||
Qv2rayAddSource(core, config, ConfigBackend, cpp, hpp)
|
||||
Qv2rayAddSource(core, config, ConfigUpgrade, cpp)
|
||||
Qv2rayAddSource(core, connection, ConnectionConfig_Convertion, cpp)
|
||||
Qv2rayAddSource(core, connection, ConnectionConfig_Generation, cpp)
|
||||
Qv2rayAddSource(core, connection, ConnectionConfigOperations, cpp, hpp)
|
||||
Qv2rayAddSource(core, connection, ConnectionIO, cpp, hpp)
|
||||
Qv2rayAddSource(core, connection, Generation, cpp, hpp)
|
||||
Qv2rayAddSource(core, connection, Serialization, cpp, hpp)
|
||||
Qv2rayAddSource(core, _, CoreUtils, cpp, hpp)
|
||||
Qv2rayAddSource(core, kernel, QvKernelInteractions, cpp, hpp)
|
||||
Qv2rayAddSource(ui, editors, w_InboundEditor, cpp, hpp, ui)
|
||||
|
@ -93,6 +93,18 @@ extern const bool isDebugBuild;
|
||||
|
||||
#define QSTRN(num) QString::number(num)
|
||||
|
||||
|
||||
#define OUTBOUND_TAG_DIRECT "outBound_DIRECT"
|
||||
#define OUTBOUND_TAG_PROXY "outBound_PROXY"
|
||||
#define OUTBOUND_TAG_FORWARD_PROXY "_QV2RAY_FORWARD_PROXY_"
|
||||
|
||||
#define API_TAG_DEFAULT "_QV2RAY_API_"
|
||||
#define API_TAG_INBOUND "_QV2RAY_API_INBOUND_"
|
||||
|
||||
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
|
||||
|
||||
#define JSON_ROOT_TRY_REMOVE(obj) if (root.contains(obj)) { root.remove(obj); }
|
||||
|
||||
namespace Qv2ray
|
||||
{
|
||||
// Extra header for QvConfigUpgrade.cpp
|
||||
|
@ -53,5 +53,13 @@ namespace Qv2ray::core
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckIsComplexConfig(CONFIGROOT root)
|
||||
{
|
||||
bool cRouting = root.contains("routing");
|
||||
bool cRule = cRouting && root["routing"].toObject().contains("rules");
|
||||
bool cRules = cRule && root["routing"].toObject()["rules"].toArray().count() > 0;
|
||||
return cRules;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ namespace Qv2ray::core
|
||||
|
||||
tuple<QString, int, QString> GetConnectionInfo(const CONFIGROOT &alias);
|
||||
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol);
|
||||
bool CheckIsComplexConfig(CONFIGROOT root);
|
||||
}
|
||||
|
||||
using namespace Qv2ray::core;
|
||||
|
@ -1,72 +0,0 @@
|
||||
#include "ConnectionConfigOperations.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
CONFIGROOT _ReadConnection(const QString &connection)
|
||||
{
|
||||
QString jsonString = StringFromFile(new QFile(connection));
|
||||
auto conf = CONFIGROOT(JsonFromString(jsonString));
|
||||
|
||||
if (conf.count() == 0) {
|
||||
LOG(MODULE_CONFIG, "WARN: Possible file corruption, failed to load file: " + connection + " --> File might be empty.")
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
QMap<QString, CONFIGROOT> GetRegularConnections(QStringList connectionNames)
|
||||
{
|
||||
QMap<QString, CONFIGROOT> list;
|
||||
|
||||
for (auto conn : connectionNames) {
|
||||
list.insert(conn, _ReadConnection(QV2RAY_CONFIG_DIR + conn + QV2RAY_CONFIG_FILE_EXTENSION));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QMap<QString, CONFIGROOT> GetSubscriptionConnection(QString subscription)
|
||||
{
|
||||
auto _files = GetFileList(QV2RAY_SUBSCRIPTION_DIR + subscription);
|
||||
QMap<QString, CONFIGROOT> _config;
|
||||
|
||||
for (auto _file : _files) {
|
||||
// check if is proper connection file.
|
||||
if (_file.endsWith(QV2RAY_CONFIG_FILE_EXTENSION)) {
|
||||
auto confName = _file;
|
||||
// Remove the extension
|
||||
confName.chop(sizeof(QV2RAY_CONFIG_FILE_EXTENSION) - 1);
|
||||
_config[confName] = _ReadConnection(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + _file);
|
||||
} else {
|
||||
LOG(MODULE_SUBSCRIPTION, "Found a file in subscription folder but without proper suffix: " + _file)
|
||||
}
|
||||
}
|
||||
|
||||
if (_config.isEmpty()) {
|
||||
LOG(MODULE_SUBSCRIPTION, "WARN: Maybe loading an empty subscrption: " + subscription)
|
||||
}
|
||||
|
||||
return _config;
|
||||
}
|
||||
|
||||
QMap<QString, QMap<QString, CONFIGROOT>> GetSubscriptionConnections(QStringList subscriptions)
|
||||
{
|
||||
// SUB-NAME CONN-NAME CONN-ROOT
|
||||
QMap<QString, QMap<QString, CONFIGROOT>> list;
|
||||
|
||||
for (auto singleSub : subscriptions) {
|
||||
LOG(MODULE_SUBSCRIPTION, "Processing subscription: " + singleSub)
|
||||
list[singleSub] = GetSubscriptionConnection(singleSub);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
bool CheckIsComplexConfig(CONFIGROOT root)
|
||||
{
|
||||
bool cRouting = root.contains("routing");
|
||||
bool cRule = cRouting && root["routing"].toObject().contains("rules");
|
||||
bool cRules = cRule && root["routing"].toObject()["rules"].toArray().count() > 0;
|
||||
return cRules;
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
#define OUTBOUND_TAG_DIRECT "outBound_DIRECT"
|
||||
#define OUTBOUND_TAG_PROXY "outBound_PROXY"
|
||||
#define OUTBOUND_TAG_FORWARD_PROXY "_QV2RAY_FORWARD_PROXY_"
|
||||
|
||||
#define API_TAG_DEFAULT "_QV2RAY_API_"
|
||||
#define API_TAG_INBOUND "_QV2RAY_API_INBOUND_"
|
||||
|
||||
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
|
||||
|
||||
#define JSON_ROOT_TRY_REMOVE(obj) if (root.contains(obj)) { root.remove(obj); }
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
// -------------------------- BEGIN GENERAL FUNCTIONS ----------------------------------------------
|
||||
|
||||
QMap<QString, CONFIGROOT> GetRegularConnections(QStringList connections);
|
||||
QMap<QString, CONFIGROOT> GetSubscriptionConnection(QString subscription);
|
||||
QMap<QString, QMap<QString, CONFIGROOT>> GetSubscriptionConnections(QStringList subscriptions);
|
||||
bool CheckIsComplexConfig(CONFIGROOT root);
|
||||
|
||||
//
|
||||
// -------------------------- BEGIN CONFIG CONVERSIONS --------------------------
|
||||
inline namespace Convertion
|
||||
{
|
||||
//int VerifyVMessProtocolString(QString vmess);
|
||||
QString DecodeSubscriptionString(QByteArray arr);
|
||||
//
|
||||
// Save Connection Config
|
||||
bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool canOverrideExisting);
|
||||
bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name);
|
||||
bool RemoveConnection(const QString &alias);
|
||||
bool RemoveSubscriptionConnection(const QString &subsName, const QString &name);
|
||||
bool RenameConnection(const QString &originalName, const QString &newName);
|
||||
bool RenameSubscription(const QString &originalName, const QString &newName);
|
||||
|
||||
// VMess URI Protocol
|
||||
CONFIGROOT ConvertConfigFromVMessString(const QString &vmess, QString *alias, QString *errMessage);
|
||||
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool keepInbounds);
|
||||
QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias);
|
||||
}
|
||||
|
||||
//
|
||||
// -------------------------- BEGIN CONFIG GENERATIONS ---------------------------------------------
|
||||
inline namespace Generation
|
||||
{
|
||||
ROUTING GenerateRoutes(bool enableProxy, bool cnProxy);
|
||||
ROUTERULE GenerateSingleRouteRule(QStringList list, bool isDomain, QString outboundTag, QString type = "field");
|
||||
QJsonObject GenerateDNS(bool withLocalhost, QStringList dnsServers);
|
||||
QJsonObject GenerateAPIEntry(QString tag, bool withHandler = true, bool withLogger = true, bool withStats = true);
|
||||
//
|
||||
// Outbound Protocols
|
||||
OUTBOUNDSETTING GenerateFreedomOUT(QString domainStrategy, QString redirect, int userLevel);
|
||||
OUTBOUNDSETTING GenerateBlackHoleOUT(bool useHTTP);
|
||||
OUTBOUNDSETTING GenerateShadowSocksServerOUT(QString email, QString address, int port, QString method, QString password, bool ota, int level);
|
||||
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<QJsonObject> servers);
|
||||
OUTBOUNDSETTING GenerateHTTPSOCKSOut(QString address, int port, bool useAuth, QString username, QString password);
|
||||
//
|
||||
// Inbounds Protocols
|
||||
INBOUNDSETTING GenerateDokodemoIN(QString address, int port, QString network, int timeout, bool followRedirect, int userLevel);
|
||||
INBOUNDSETTING GenerateHTTPIN(QList<AccountObject> accounts, int timeout = 300, bool allowTransparent = true, int userLevel = 0);
|
||||
INBOUNDSETTING GenerateSocksIN(QString auth, QList<AccountObject> _accounts, bool udp = false, QString ip = "127.0.0.1", int userLevel = 0);
|
||||
//
|
||||
// Generate FINAL Configs
|
||||
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root);
|
||||
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux = QJsonObject(), QString sendThrough = "0.0.0.0", QString tag = "");
|
||||
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing = QJsonObject(), QJsonObject allocate = QJsonObject());
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Qv2ray::core;
|
||||
using namespace Qv2ray::core::connection;
|
172
src/core/connection/ConnectionIO.cpp
Normal file
172
src/core/connection/ConnectionIO.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include "ConnectionIO.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
namespace ConnectionIO
|
||||
{
|
||||
CONFIGROOT _ReadConnection(const QString &connection)
|
||||
{
|
||||
QString jsonString = StringFromFile(new QFile(connection));
|
||||
auto conf = CONFIGROOT(JsonFromString(jsonString));
|
||||
|
||||
if (conf.count() == 0) {
|
||||
LOG(MODULE_CONFIG, "WARN: Possible file corruption, failed to load file: " + connection + " --> File might be empty.")
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
QMap<QString, CONFIGROOT> GetRegularConnections(QStringList connectionNames)
|
||||
{
|
||||
QMap<QString, CONFIGROOT> list;
|
||||
|
||||
for (auto conn : connectionNames) {
|
||||
list.insert(conn, _ReadConnection(QV2RAY_CONFIG_DIR + conn + QV2RAY_CONFIG_FILE_EXTENSION));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QMap<QString, CONFIGROOT> GetSubscriptionConnection(QString subscription)
|
||||
{
|
||||
auto _files = GetFileList(QV2RAY_SUBSCRIPTION_DIR + subscription);
|
||||
QMap<QString, CONFIGROOT> _config;
|
||||
|
||||
for (auto _file : _files) {
|
||||
// check if is proper connection file.
|
||||
if (_file.endsWith(QV2RAY_CONFIG_FILE_EXTENSION)) {
|
||||
auto confName = _file;
|
||||
// Remove the extension
|
||||
confName.chop(sizeof(QV2RAY_CONFIG_FILE_EXTENSION) - 1);
|
||||
_config[confName] = _ReadConnection(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + _file);
|
||||
} else {
|
||||
LOG(MODULE_SUBSCRIPTION, "Found a file in subscription folder but without proper suffix: " + _file)
|
||||
}
|
||||
}
|
||||
|
||||
if (_config.isEmpty()) {
|
||||
LOG(MODULE_SUBSCRIPTION, "WARN: Maybe loading an empty subscrption: " + subscription)
|
||||
}
|
||||
|
||||
return _config;
|
||||
}
|
||||
|
||||
QMap<QString, QMap<QString, CONFIGROOT>> GetSubscriptionConnections(QStringList subscriptions)
|
||||
{
|
||||
// SUB-NAME CONN-NAME CONN-ROOT
|
||||
QMap<QString, QMap<QString, CONFIGROOT>> list;
|
||||
|
||||
for (auto singleSub : subscriptions) {
|
||||
LOG(MODULE_SUBSCRIPTION, "Processing subscription: " + singleSub)
|
||||
list[singleSub] = GetSubscriptionConnection(singleSub);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
//
|
||||
// Save Connection to a place, with checking if there's existing file.
|
||||
// If so, append "_N" to the name.
|
||||
bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool canOverrideExisting)
|
||||
{
|
||||
auto str = JsonToString(obj);
|
||||
QFile *config = new QFile(QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
// If there's already a file AND we CANNOT override existing file.
|
||||
if (config->exists() && !canOverrideExisting) {
|
||||
// Alias is a pointer to a QString.
|
||||
DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias, QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
config = new QFile(QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
LOG(MODULE_CONFIG, "Saving a config named: " + *alias)
|
||||
return StringToFile(&str, config);
|
||||
}
|
||||
|
||||
bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name)
|
||||
{
|
||||
auto str = JsonToString(obj);
|
||||
auto fName = *name;
|
||||
|
||||
if (!IsValidFileName(fName)) {
|
||||
fName = RemoveInvalidFileName(fName);
|
||||
}
|
||||
|
||||
QFile *config = new QFile(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + fName + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
// If there's already a file. THIS IS EXTREMELY RARE
|
||||
if (config->exists()) {
|
||||
LOG(MODULE_FILE, "Trying to overrwrite an existing subscription config file. THIS IS RARE")
|
||||
}
|
||||
|
||||
LOG(MODULE_CONFIG, "Saving a subscription named: " + fName)
|
||||
bool result = StringToFile(&str, config);
|
||||
|
||||
if (!result) {
|
||||
LOG(MODULE_FILE, "Failed to save a connection config from subscription: " + subscription + ", name: " + fName)
|
||||
}
|
||||
|
||||
*name = fName;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RemoveConnection(const QString &alias)
|
||||
{
|
||||
QFile config(QV2RAY_CONFIG_DIR + alias + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
if (!config.exists()) {
|
||||
LOG(MODULE_FILE, "Trying to remove a non-existing file?")
|
||||
return false;
|
||||
} else {
|
||||
return config.remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoveSubscriptionConnection(const QString &subsName, const QString &name)
|
||||
{
|
||||
QFile config(QV2RAY_SUBSCRIPTION_DIR + subsName + "/" + name + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
if (!config.exists()) {
|
||||
LOG(MODULE_FILE, "Trying to remove a non-existing file?")
|
||||
return false;
|
||||
} else {
|
||||
return config.remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenameConnection(const QString &originalName, const QString &newName)
|
||||
{
|
||||
LOG(MODULE_CONFIG, "[RENAME] --> ORIGINAL: " + originalName + ", NEW: " + newName)
|
||||
return QFile::rename(QV2RAY_CONFIG_DIR + originalName + QV2RAY_CONFIG_FILE_EXTENSION, QV2RAY_CONFIG_DIR + newName + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
bool RenameSubscription(const QString &originalName, const QString &newName)
|
||||
{
|
||||
LOG(MODULE_SUBSCRIPTION, "[RENAME] --> ORIGINAL: " + originalName + ", NEW: " + newName)
|
||||
return QDir().rename(QV2RAY_SUBSCRIPTION_DIR + originalName, QV2RAY_SUBSCRIPTION_DIR + newName);
|
||||
}
|
||||
|
||||
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool keepInbounds)
|
||||
{
|
||||
QFile source(sourceFilePath);
|
||||
|
||||
if (!source.exists()) {
|
||||
LOG(MODULE_FILE, "Trying to import from an non-existing file.")
|
||||
return CONFIGROOT();
|
||||
}
|
||||
|
||||
auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
|
||||
|
||||
if (!keepInbounds) {
|
||||
JSON_ROOT_TRY_REMOVE("inbounds")
|
||||
}
|
||||
|
||||
JSON_ROOT_TRY_REMOVE("log")
|
||||
JSON_ROOT_TRY_REMOVE("api")
|
||||
JSON_ROOT_TRY_REMOVE("stats")
|
||||
JSON_ROOT_TRY_REMOVE("dns")
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
28
src/core/connection/ConnectionIO.hpp
Normal file
28
src/core/connection/ConnectionIO.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
namespace ConnectionIO
|
||||
{
|
||||
QMap<QString, CONFIGROOT> GetRegularConnections(QStringList connections);
|
||||
QMap<QString, CONFIGROOT> GetSubscriptionConnection(QString subscription);
|
||||
QMap<QString, QMap<QString, CONFIGROOT>> GetSubscriptionConnections(QStringList subscriptions);
|
||||
//
|
||||
// Save Connection Config
|
||||
bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool canOverrideExisting);
|
||||
bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name);
|
||||
//
|
||||
bool RemoveConnection(const QString &alias);
|
||||
bool RemoveSubscriptionConnection(const QString &subsName, const QString &name);
|
||||
//
|
||||
bool RenameConnection(const QString &originalName, const QString &newName);
|
||||
bool RenameSubscription(const QString &originalName, const QString &newName);
|
||||
|
||||
// File Protocol
|
||||
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool keepInbounds);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Qv2ray::core;
|
||||
using namespace Qv2ray::core::connection;
|
||||
using namespace Qv2ray::core::connection::ConnectionIO;
|
@ -1,12 +1,11 @@
|
||||
#include "ConnectionConfigOperations.hpp"
|
||||
#include "Generation.hpp"
|
||||
#include "core/CoreUtils.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
inline namespace Generation
|
||||
namespace Generation
|
||||
{
|
||||
// Important config generation algorithms.
|
||||
static const QStringList vLogLevels = {"none", "debug", "info", "warning", "error"};
|
||||
// -------------------------- BEGIN CONFIG GENERATIONS ----------------------------------------------------------------------------
|
||||
ROUTING GenerateRoutes(bool enableProxy, bool proxyCN)
|
||||
{
|
||||
@ -57,13 +56,13 @@ namespace Qv2ray::core::connection
|
||||
RROOT
|
||||
}
|
||||
|
||||
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<QJsonObject> servers)
|
||||
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers)
|
||||
{
|
||||
OUTBOUNDSETTING root;
|
||||
QJsonArray x;
|
||||
|
||||
foreach (auto server, servers) {
|
||||
x.append(server);
|
||||
x.append(GenerateShadowSocksServerOUT(server.email, server.address, server.port, server.method, server.password, server.ota, server.level));
|
||||
}
|
||||
|
||||
root.insert("servers", x);
|
35
src/core/connection/Generation.hpp
Normal file
35
src/core/connection/Generation.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
namespace Generation
|
||||
{
|
||||
// Important config generation algorithms.
|
||||
const QStringList vLogLevels = {"none", "debug", "info", "warning", "error"};
|
||||
ROUTING GenerateRoutes(bool enableProxy, bool cnProxy);
|
||||
ROUTERULE GenerateSingleRouteRule(QStringList list, bool isDomain, QString outboundTag, QString type = "field");
|
||||
QJsonObject GenerateDNS(bool withLocalhost, QStringList dnsServers);
|
||||
QJsonObject GenerateAPIEntry(QString tag, bool withHandler = true, bool withLogger = true, bool withStats = true);
|
||||
//
|
||||
// Outbound Protocols
|
||||
OUTBOUNDSETTING GenerateFreedomOUT(QString domainStrategy, QString redirect, int userLevel);
|
||||
OUTBOUNDSETTING GenerateBlackHoleOUT(bool useHTTP);
|
||||
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers);
|
||||
OUTBOUNDSETTING GenerateShadowSocksServerOUT(QString email, QString address, int port, QString method, QString password, bool ota, int level);
|
||||
OUTBOUNDSETTING GenerateHTTPSOCKSOut(QString address, int port, bool useAuth, QString username, QString password);
|
||||
//
|
||||
// Inbounds Protocols
|
||||
INBOUNDSETTING GenerateDokodemoIN(QString address, int port, QString network, int timeout, bool followRedirect, int userLevel);
|
||||
INBOUNDSETTING GenerateHTTPIN(QList<AccountObject> accounts, int timeout = 300, bool allowTransparent = true, int userLevel = 0);
|
||||
INBOUNDSETTING GenerateSocksIN(QString auth, QList<AccountObject> _accounts, bool udp = false, QString ip = "127.0.0.1", int userLevel = 0);
|
||||
//
|
||||
// Generate FINAL Configs
|
||||
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root);
|
||||
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux = QJsonObject(), QString sendThrough = "0.0.0.0", QString tag = OUTBOUND_TAG_PROXY);
|
||||
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing = QJsonObject(), QJsonObject allocate = QJsonObject());
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Qv2ray::core;
|
||||
using namespace Qv2ray::core::connection;
|
||||
using namespace Qv2ray::core::connection::Generation;
|
@ -1,9 +1,10 @@
|
||||
#include "ConnectionConfigOperations.hpp"
|
||||
#include "Serialization.hpp"
|
||||
#include "Generation.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
inline namespace Convertion
|
||||
namespace Serialization
|
||||
{
|
||||
// From https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
|
||||
QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias)
|
||||
@ -44,6 +45,7 @@ namespace Qv2ray::core::connection
|
||||
auto vmessPart = Base64Encode(JsonToString(vmessUriRoot, QJsonDocument::JsonFormat::Compact));
|
||||
return "vmess://" + vmessPart;
|
||||
}
|
||||
|
||||
QString DecodeSubscriptionString(QByteArray arr)
|
||||
{
|
||||
// Some subscription providers may use plain vmess:// saperated by lines
|
||||
@ -51,76 +53,118 @@ namespace Qv2ray::core::connection
|
||||
auto result = QString::fromUtf8(arr).trimmed();
|
||||
return result.startsWith("vmess://") ? result : Base64Decode(result);
|
||||
}
|
||||
|
||||
CONFIGROOT fromUri(const QString &ssUri, QString *alias, QString *errMessage)
|
||||
{
|
||||
ShadowSocksServerObject server;
|
||||
QString d_name;
|
||||
|
||||
//auto ssUri = _ssUri.toStdString();
|
||||
if (ssUri.length() < 5) {
|
||||
LOG(MODULE_CONNECTION, "ss:// string too short")
|
||||
*errMessage = QObject::tr("SS URI is too short");
|
||||
}
|
||||
|
||||
auto uri = ssUri.mid(5);
|
||||
auto hashPos = uri.lastIndexOf("#");
|
||||
DEBUG(MODULE_CONNECTION, "Hash sign position: " + QSTRN(hashPos))
|
||||
|
||||
if (hashPos >= 0) {
|
||||
// Get the name/remark
|
||||
d_name = uri.mid(uri.lastIndexOf("#") + 1);
|
||||
uri.truncate(hashPos);
|
||||
}
|
||||
|
||||
// No plugins for Qv2ray so disable those lnes.i
|
||||
//size_t pluginPos = uri.find_first_of('/');
|
||||
//
|
||||
//if (pluginPos != std::string::npos) {
|
||||
// // TODO: support plugins. For now, just ignore them
|
||||
// uri.erase(pluginPos);
|
||||
//}
|
||||
auto atPos = uri.indexOf('@');
|
||||
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
|
||||
|
||||
if (atPos < 0) {
|
||||
// Old URI scheme
|
||||
QString decoded = QByteArray::fromBase64(uri.toUtf8(), QByteArray::Base64Option::OmitTrailingEquals);
|
||||
auto colonPos = decoded.indexOf(':');
|
||||
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
|
||||
|
||||
if (colonPos < 0) {
|
||||
*errMessage = QObject::tr("Can't find the colon separator between method and password");
|
||||
}
|
||||
|
||||
server.method = decoded.left(colonPos);
|
||||
decoded.remove(0, colonPos + 1);
|
||||
atPos = decoded.lastIndexOf('@');
|
||||
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
|
||||
|
||||
if (atPos < 0) {
|
||||
*errMessage = QObject::tr("Can't find the at separator between password and hostname");
|
||||
}
|
||||
|
||||
server.password = decoded.mid(0, atPos);
|
||||
decoded.remove(0, atPos + 1);
|
||||
colonPos = decoded.lastIndexOf(':');
|
||||
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
|
||||
|
||||
if (colonPos < 0) {
|
||||
*errMessage = QObject::tr("Can't find the colon separator between hostname and port");
|
||||
}
|
||||
|
||||
server.address = decoded.mid(0, colonPos);
|
||||
server.port = decoded.mid(colonPos + 1).toInt();
|
||||
} else {
|
||||
// SIP002 URI scheme
|
||||
QString userInfo(QByteArray::fromBase64(QByteArray(uri.mid(0, atPos).toUtf8(), QByteArray::Base64Option::Base64UrlEncoding)));
|
||||
auto userInfoSp = userInfo.indexOf(':');
|
||||
DEBUG(MODULE_CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
|
||||
|
||||
if (userInfoSp < 0) {
|
||||
*errMessage = QObject::tr("Can't find the colon separator between method and password");
|
||||
}
|
||||
|
||||
QString method = userInfo.mid(0, userInfoSp);
|
||||
server.method = method;
|
||||
server.password = userInfo.mid(userInfoSp + 1);
|
||||
uri.remove(0, atPos + 1);
|
||||
auto hostSpPos = uri.lastIndexOf(':');
|
||||
DEBUG(MODULE_CONNECTION, "Host splitter position: " + QSTRN(hostSpPos))
|
||||
|
||||
if (hostSpPos < 0) {
|
||||
*errMessage = QObject::tr("Can't find the colon separator between hostname and port");
|
||||
}
|
||||
|
||||
server.address = uri.mid(0, hostSpPos);
|
||||
server.port = uri.mid(hostSpPos + 1).toInt();
|
||||
}
|
||||
|
||||
CONFIGROOT root;
|
||||
OUTBOUNDS outbounds;
|
||||
outbounds.append(GenerateOutboundEntry("shadowsocks", GenerateShadowSocksOUT(QList<ShadowSocksServerObject>() << server), QJsonObject()));
|
||||
JADD(outbounds)
|
||||
*alias = alias->isEmpty() ? d_name : *alias + "_" + d_name;
|
||||
LOG(MODULE_CONNECTION, "Deduced alias: " + *alias)
|
||||
return root;
|
||||
}
|
||||
|
||||
QString toUri(const ShadowSocksServerObject &server, const QString &alias)
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Converting an ss-server config to old ss:// string format")
|
||||
QString ssUri = server.method + ":" + server.password + "@" + server.address + ":" + QSTRN(server.port);
|
||||
return "ss://" + ssUri.toUtf8().toBase64(QByteArray::Base64Option::OmitTrailingEquals) + "#" + alias;
|
||||
}
|
||||
|
||||
QString toUriSip002(const ShadowSocksServerObject &server, const QString &alias)
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Converting an ss-server config to Sip002 ss:// format")
|
||||
QString plainUserInfo = server.method + ":" + server.password;
|
||||
QString userinfo(plainUserInfo.toUtf8().toBase64(QByteArray::Base64Option::Base64UrlEncoding).data());
|
||||
return "ss://" + userinfo + "@" + server.address + ":" + QSTRN(server.port) + "#" + alias;
|
||||
}
|
||||
|
||||
//
|
||||
// Save Connection to a place, with checking if there's existing file.
|
||||
// If so, append "_N" to the name.
|
||||
bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool canOverrideExisting)
|
||||
{
|
||||
auto str = JsonToString(obj);
|
||||
QFile *config = new QFile(QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
// If there's already a file AND we CANNOT override existing file.
|
||||
if (config->exists() && !canOverrideExisting) {
|
||||
// Alias is a pointer to a QString.
|
||||
DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias, QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
config = new QFile(QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
LOG(MODULE_CONFIG, "Saving a config named: " + *alias)
|
||||
return StringToFile(&str, config);
|
||||
}
|
||||
|
||||
bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name)
|
||||
{
|
||||
auto str = JsonToString(obj);
|
||||
auto fName = *name;
|
||||
|
||||
if (!IsValidFileName(fName)) {
|
||||
fName = RemoveInvalidFileName(fName);
|
||||
}
|
||||
|
||||
QFile *config = new QFile(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + fName + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
// If there's already a file. THIS IS EXTREMELY RARE
|
||||
if (config->exists()) {
|
||||
LOG(MODULE_FILE, "Trying to overrwrite an existing subscription config file. THIS IS RARE")
|
||||
}
|
||||
|
||||
LOG(MODULE_CONFIG, "Saving a subscription named: " + fName)
|
||||
bool result = StringToFile(&str, config);
|
||||
|
||||
if (!result) {
|
||||
LOG(MODULE_FILE, "Failed to save a connection config from subscription: " + subscription + ", name: " + fName)
|
||||
}
|
||||
|
||||
*name = fName;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RemoveConnection(const QString &alias)
|
||||
{
|
||||
QFile config(QV2RAY_CONFIG_DIR + alias + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
if (!config.exists()) {
|
||||
LOG(MODULE_FILE, "Trying to remove a non-existing file?")
|
||||
return false;
|
||||
} else {
|
||||
return config.remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoveSubscriptionConnection(const QString &subsName, const QString &name)
|
||||
{
|
||||
QFile config(QV2RAY_SUBSCRIPTION_DIR + subsName + "/" + name + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
|
||||
if (!config.exists()) {
|
||||
LOG(MODULE_FILE, "Trying to remove a non-existing file?")
|
||||
return false;
|
||||
} else {
|
||||
return config.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// This generates global config containing only one outbound....
|
||||
CONFIGROOT ConvertConfigFromVMessString(const QString &vmessStr, QString *alias, QString *errMessage)
|
||||
{
|
||||
@ -294,39 +338,5 @@ namespace Qv2ray::core::connection
|
||||
#undef default
|
||||
return root;
|
||||
}
|
||||
|
||||
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool keepInbounds)
|
||||
{
|
||||
QFile source(sourceFilePath);
|
||||
|
||||
if (!source.exists()) {
|
||||
LOG(MODULE_FILE, "Trying to import from an non-existing file.")
|
||||
return CONFIGROOT();
|
||||
}
|
||||
|
||||
auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
|
||||
|
||||
if (!keepInbounds) {
|
||||
JSON_ROOT_TRY_REMOVE("inbounds")
|
||||
}
|
||||
|
||||
JSON_ROOT_TRY_REMOVE("log")
|
||||
JSON_ROOT_TRY_REMOVE("api")
|
||||
JSON_ROOT_TRY_REMOVE("stats")
|
||||
JSON_ROOT_TRY_REMOVE("dns")
|
||||
return root;
|
||||
}
|
||||
|
||||
bool RenameConnection(const QString &originalName, const QString &newName)
|
||||
{
|
||||
LOG(MODULE_CONFIG, "[RENAME] --> ORIGINAL: " + originalName + ", NEW: " + newName)
|
||||
return QFile::rename(QV2RAY_CONFIG_DIR + originalName + QV2RAY_CONFIG_FILE_EXTENSION, QV2RAY_CONFIG_DIR + newName + QV2RAY_CONFIG_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
bool RenameSubscription(const QString &originalName, const QString &newName)
|
||||
{
|
||||
LOG(MODULE_SUBSCRIPTION, "[RENAME] --> ORIGINAL: " + originalName + ", NEW: " + newName)
|
||||
return QDir().rename(QV2RAY_SUBSCRIPTION_DIR + originalName, QV2RAY_SUBSCRIPTION_DIR + newName);
|
||||
}
|
||||
}
|
||||
}
|
22
src/core/connection/Serialization.hpp
Normal file
22
src/core/connection/Serialization.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
namespace Qv2ray::core::connection
|
||||
{
|
||||
namespace Serialization
|
||||
{
|
||||
//int VerifyVMessProtocolString(QString vmess);
|
||||
QString DecodeSubscriptionString(QByteArray arr);
|
||||
|
||||
// VMess URI Protocol
|
||||
CONFIGROOT ConvertConfigFromVMessString(const QString &vmess, QString *alias, QString *errMessage);
|
||||
QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias);
|
||||
|
||||
// SS URI Protocol
|
||||
CONFIGROOT ConvertConfigFromSSString(const QString &ss, QString *alias, QString *errMessage);
|
||||
QString ConvertConfigToSSString(const ShadowSocksServerObject &serverConfig, const QString &alias);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Qv2ray::core;
|
||||
using namespace Qv2ray::core::connection;
|
||||
using namespace Qv2ray::core::connection::Serialization;
|
@ -3,7 +3,7 @@
|
||||
#include <QDesktopServices>
|
||||
#include "common/QvHelpers.hpp"
|
||||
#include "QvKernelInteractions.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
|
||||
#ifdef WITH_LIB_GRPCPP
|
||||
using namespace v2ray::core::app::stats::command;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "w_InboundEditor.hpp"
|
||||
#include "core/CoreUtils.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
|
||||
static bool isLoading = false;
|
||||
#define CHECKLOADING if(isLoading) return;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "ui/w_MainWindow.hpp"
|
||||
#include "ui/editors/w_JsonEditor.hpp"
|
||||
#include "ui/editors/w_RoutesEditor.hpp"
|
||||
#include "core/connection/Generation.hpp"
|
||||
|
||||
OutboundEditor::OutboundEditor(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
|
@ -4,7 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "w_RoutesEditor.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
#include "core/connection/Generation.hpp"
|
||||
#include "w_OutboundEditor.hpp"
|
||||
#include "w_JsonEditor.hpp"
|
||||
#include "w_InboundEditor.hpp"
|
||||
|
@ -16,19 +16,22 @@ ConfigExporter::~ConfigExporter()
|
||||
UNREGISTER_WINDOW
|
||||
}
|
||||
|
||||
ConfigExporter::ConfigExporter(const QImage &img, QWidget *parent): ConfigExporter(parent)
|
||||
ConfigExporter::ConfigExporter(const CONFIGROOT &root, QWidget *parent)
|
||||
{
|
||||
image = img;
|
||||
message = tr("Empty");
|
||||
}
|
||||
ConfigExporter::ConfigExporter(const QString &data, QWidget *parent): ConfigExporter(parent)
|
||||
{
|
||||
QZXingEncoderConfig conf;
|
||||
conf.border = true;
|
||||
conf.imageSize = QSize(400, 400);
|
||||
auto img = qzxing.encodeData(data, conf);
|
||||
image = img.copy();
|
||||
message = data;
|
||||
//
|
||||
//auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject()));
|
||||
//auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outBoundRoot["streamSettings"].toObject()));
|
||||
//auto vmess = ConvertConfigToVMessString(transport, vmessServer, _identifier.connectionName);
|
||||
//
|
||||
//image = img;
|
||||
//message = tr("Empty");
|
||||
////
|
||||
//QZXingEncoderConfig conf;
|
||||
//conf.border = true;
|
||||
//conf.imageSize = QSize(400, 400);
|
||||
//auto img = qzxing.encodeData(data, conf);
|
||||
//image = img.copy();
|
||||
//message = data;
|
||||
}
|
||||
|
||||
void ConfigExporter::OpenExport()
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui_w_ExportConfig.h"
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
#include "3rdparty/qzxing/src/QZXing.h"
|
||||
|
||||
class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
|
||||
@ -8,8 +9,7 @@ class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigExporter(const QImage &img, QWidget *parent = nullptr);
|
||||
explicit ConfigExporter(const QString &data, QWidget *parent = nullptr);
|
||||
explicit ConfigExporter(const CONFIGROOT &root, QWidget *parent = nullptr);
|
||||
~ConfigExporter();
|
||||
void OpenExport();
|
||||
protected:
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
#include "core/CoreUtils.hpp"
|
||||
#include "core/kernel/QvKernelInteractions.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
#include "core/connection/Serialization.hpp"
|
||||
|
||||
#include "w_ScreenShot_Core.hpp"
|
||||
#include "ui/editors/w_OutboundEditor.hpp"
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
||||
#include "components/pac/QvPACHandler.hpp"
|
||||
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
|
||||
// MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related operations.
|
||||
|
||||
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
|
||||
@ -1004,17 +1006,13 @@ void MainWindow::on_shareBtn_clicked()
|
||||
|
||||
auto _identifier = ItemConnectionIdentifier(connectionListWidget->currentItem());
|
||||
auto root = connections[_identifier].config;
|
||||
auto outBoundRoot = root["outbounds"].toArray().first().toObject();
|
||||
auto outboundType = outBoundRoot["protocol"].toString();
|
||||
auto type = get<2>(GetConnectionInfo(root));
|
||||
|
||||
if (!CheckIsComplexConfig(root) && outboundType == "vmess") {
|
||||
auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject()));
|
||||
auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outBoundRoot["streamSettings"].toObject()));
|
||||
auto vmess = ConvertConfigToVMessString(transport, vmessServer, _identifier.connectionName);
|
||||
ConfigExporter v(vmess, this);
|
||||
if (!CheckIsComplexConfig(root) && (type == "vmess" || type == "shadowsocks")) {
|
||||
ConfigExporter v(root, this);
|
||||
v.OpenExport();
|
||||
} else {
|
||||
QvMessageBoxWarn(this, tr("Share Connection"), tr("There're no support of sharing configs other than vmess"));
|
||||
QvMessageBoxWarn(this, tr("Share Connection"), tr("There're no support of sharing configs other than vmess and shadowsocks"));
|
||||
}
|
||||
}
|
||||
void MainWindow::on_action_RCM_ShareQR_triggered()
|
||||
@ -1086,11 +1084,12 @@ void MainWindow::on_duplicateBtn_clicked()
|
||||
CONFIGROOT conf;
|
||||
// Alias may change.
|
||||
QString alias = _identifier.connectionName;
|
||||
bool isComplex = CheckIsComplexConfig(connections[_identifier].config);
|
||||
|
||||
if (connections[_identifier].configType == CONNECTION_REGULAR) {
|
||||
conf = ConvertConfigFromFile(QV2RAY_CONFIG_DIR + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, false);
|
||||
conf = ConvertConfigFromFile(QV2RAY_CONFIG_DIR + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
|
||||
} else {
|
||||
conf = ConvertConfigFromFile(QV2RAY_SUBSCRIPTION_DIR + _identifier.subscriptionName + "/" + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, false);
|
||||
conf = ConvertConfigFromFile(QV2RAY_SUBSCRIPTION_DIR + _identifier.subscriptionName + "/" + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
|
||||
alias = _identifier.subscriptionName + "_" + _identifier.connectionName;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "core/CoreUtils.hpp"
|
||||
#include "core/kernel/QvKernelInteractions.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
|
||||
#include "components/pac/QvPACHandler.hpp"
|
||||
#include "common/LogHighlighter.hpp"
|
||||
|
@ -3,6 +3,7 @@
|
||||
// We NEED to include the cpp file to define the macros.
|
||||
#include "w_MainWindow.cpp"
|
||||
#include "components/proxy/QvProxyConfigurator.hpp"
|
||||
#include "core/connection/Generation.hpp"
|
||||
|
||||
QTreeWidgetItem *MainWindow::FindItemByIdentifier(QvConfigIdentifier identifier)
|
||||
{
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include "common/QvHelpers.hpp"
|
||||
#include "common/HTTPRequestHelper.hpp"
|
||||
#include "core/config/ConfigBackend.hpp"
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
#include "core/kernel/QvKernelInteractions.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
||||
#include "components/autolaunch/QvAutoLaunch.hpp"
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "w_SubscriptionManager.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
#include "core/CoreUtils.hpp"
|
||||
#include "core/connection/ConnectionConfigOperations.hpp"
|
||||
|
||||
#include "core/connection/ConnectionIO.hpp"
|
||||
#include "core/connection/Serialization.hpp"
|
||||
|
||||
SubscribeEditor::SubscribeEditor(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
|
Loading…
Reference in New Issue
Block a user