refactor: stage 3.5 class separation

This commit is contained in:
Qv2ray-Bot 2020-01-31 16:57:35 +08:00
parent a2d5920959
commit 36dc29bd9c
25 changed files with 441 additions and 293 deletions

View File

@ -1 +1 @@
3403
3423

View File

@ -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)

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View 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;
}
}
}

View 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;

View File

@ -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);

View 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;

View File

@ -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('/');
//
// 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 (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 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);
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");
}
LOG(MODULE_CONFIG, "Saving a config named: " + *alias)
return StringToFile(&str, config);
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");
}
bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name)
{
auto str = JsonToString(obj);
auto fName = *name;
server.password = decoded.mid(0, atPos);
decoded.remove(0, atPos + 1);
colonPos = decoded.lastIndexOf(':');
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
if (!IsValidFileName(fName)) {
fName = RemoveInvalidFileName(fName);
if (colonPos < 0) {
*errMessage = QObject::tr("Can't find the colon separator between hostname and port");
}
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;
server.address = decoded.mid(0, colonPos);
server.port = decoded.mid(colonPos + 1).toInt();
} else {
return config.remove();
}
// 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");
}
bool RemoveSubscriptionConnection(const QString &subsName, const QString &name)
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)
{
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();
}
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;
}
//
// 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);
}
}
}

View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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),

View File

@ -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"

View File

@ -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()

View File

@ -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:

View File

@ -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"

View File

@ -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;
}

View File

@ -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"

View File

@ -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)
{

View File

@ -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"

View File

@ -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)