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(components, tcping, QvTCPing, cpp, hpp)
Qv2rayAddSource(core, config, ConfigBackend, cpp, hpp) Qv2rayAddSource(core, config, ConfigBackend, cpp, hpp)
Qv2rayAddSource(core, config, ConfigUpgrade, cpp) Qv2rayAddSource(core, config, ConfigUpgrade, cpp)
Qv2rayAddSource(core, connection, ConnectionConfig_Convertion, cpp) Qv2rayAddSource(core, connection, ConnectionIO, cpp, hpp)
Qv2rayAddSource(core, connection, ConnectionConfig_Generation, cpp) Qv2rayAddSource(core, connection, Generation, cpp, hpp)
Qv2rayAddSource(core, connection, ConnectionConfigOperations, cpp, hpp) Qv2rayAddSource(core, connection, Serialization, cpp, hpp)
Qv2rayAddSource(core, _, CoreUtils, cpp, hpp) Qv2rayAddSource(core, _, CoreUtils, cpp, hpp)
Qv2rayAddSource(core, kernel, QvKernelInteractions, cpp, hpp) Qv2rayAddSource(core, kernel, QvKernelInteractions, cpp, hpp)
Qv2rayAddSource(ui, editors, w_InboundEditor, cpp, hpp, ui) 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 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 namespace Qv2ray
{ {
// Extra header for QvConfigUpgrade.cpp // Extra header for QvConfigUpgrade.cpp

View File

@ -53,5 +53,13 @@ namespace Qv2ray::core
return false; 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); tuple<QString, int, QString> GetConnectionInfo(const CONFIGROOT &alias);
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol); bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol);
bool CheckIsComplexConfig(CONFIGROOT root);
} }
using namespace Qv2ray::core; 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" #include "common/QvHelpers.hpp"
namespace Qv2ray::core::connection 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 ---------------------------------------------------------------------------- // -------------------------- BEGIN CONFIG GENERATIONS ----------------------------------------------------------------------------
ROUTING GenerateRoutes(bool enableProxy, bool proxyCN) ROUTING GenerateRoutes(bool enableProxy, bool proxyCN)
{ {
@ -57,13 +56,13 @@ namespace Qv2ray::core::connection
RROOT RROOT
} }
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<QJsonObject> servers) OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers)
{ {
OUTBOUNDSETTING root; OUTBOUNDSETTING root;
QJsonArray x; QJsonArray x;
foreach (auto server, servers) { 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); 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" #include "common/QvHelpers.hpp"
namespace Qv2ray::core::connection 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) // 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) 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)); auto vmessPart = Base64Encode(JsonToString(vmessUriRoot, QJsonDocument::JsonFormat::Compact));
return "vmess://" + vmessPart; return "vmess://" + vmessPart;
} }
QString DecodeSubscriptionString(QByteArray arr) QString DecodeSubscriptionString(QByteArray arr)
{ {
// Some subscription providers may use plain vmess:// saperated by lines // Some subscription providers may use plain vmess:// saperated by lines
@ -51,76 +53,118 @@ namespace Qv2ray::core::connection
auto result = QString::fromUtf8(arr).trimmed(); auto result = QString::fromUtf8(arr).trimmed();
return result.startsWith("vmess://") ? result : Base64Decode(result); 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 (pluginPos != std::string::npos) {
// If so, append "_N" to the name. // // TODO: support plugins. For now, just ignore them
bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool canOverrideExisting) // uri.erase(pluginPos);
{ //}
auto str = JsonToString(obj); auto atPos = uri.indexOf('@');
QFile *config = new QFile(QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION); DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
// If there's already a file AND we CANNOT override existing file. if (atPos < 0) {
if (config->exists() && !canOverrideExisting) { // Old URI scheme
// Alias is a pointer to a QString. QString decoded = QByteArray::fromBase64(uri.toUtf8(), QByteArray::Base64Option::OmitTrailingEquals);
DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias, QV2RAY_CONFIG_FILE_EXTENSION); auto colonPos = decoded.indexOf(':');
config = new QFile(QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION); 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) server.method = decoded.left(colonPos);
return StringToFile(&str, config); 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) server.password = decoded.mid(0, atPos);
{ decoded.remove(0, atPos + 1);
auto str = JsonToString(obj); colonPos = decoded.lastIndexOf(':');
auto fName = *name; DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
if (!IsValidFileName(fName)) { if (colonPos < 0) {
fName = RemoveInvalidFileName(fName); *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); server.address = decoded.mid(0, colonPos);
server.port = decoded.mid(colonPos + 1).toInt();
// 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 { } 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); LOG(MODULE_CONNECTION, "Converting an ss-server config to old ss:// string format")
QString ssUri = server.method + ":" + server.password + "@" + server.address + ":" + QSTRN(server.port);
if (!config.exists()) { return "ss://" + ssUri.toUtf8().toBase64(QByteArray::Base64Option::OmitTrailingEquals) + "#" + alias;
LOG(MODULE_FILE, "Trying to remove a non-existing file?")
return false;
} else {
return config.remove();
}
} }
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.... // This generates global config containing only one outbound....
CONFIGROOT ConvertConfigFromVMessString(const QString &vmessStr, QString *alias, QString *errMessage) CONFIGROOT ConvertConfigFromVMessString(const QString &vmessStr, QString *alias, QString *errMessage)
{ {
@ -294,39 +338,5 @@ namespace Qv2ray::core::connection
#undef default #undef default
return root; 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 <QDesktopServices>
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "QvKernelInteractions.hpp" #include "QvKernelInteractions.hpp"
#include "core/connection/ConnectionConfigOperations.hpp" #include "core/connection/ConnectionIO.hpp"
#ifdef WITH_LIB_GRPCPP #ifdef WITH_LIB_GRPCPP
using namespace v2ray::core::app::stats::command; using namespace v2ray::core::app::stats::command;

View File

@ -1,7 +1,7 @@
#include "w_InboundEditor.hpp" #include "w_InboundEditor.hpp"
#include "core/CoreUtils.hpp" #include "core/CoreUtils.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "core/connection/ConnectionConfigOperations.hpp" #include "core/connection/ConnectionIO.hpp"
static bool isLoading = false; static bool isLoading = false;
#define CHECKLOADING if(isLoading) return; #define CHECKLOADING if(isLoading) return;

View File

@ -7,6 +7,7 @@
#include "ui/w_MainWindow.hpp" #include "ui/w_MainWindow.hpp"
#include "ui/editors/w_JsonEditor.hpp" #include "ui/editors/w_JsonEditor.hpp"
#include "ui/editors/w_RoutesEditor.hpp" #include "ui/editors/w_RoutesEditor.hpp"
#include "core/connection/Generation.hpp"
OutboundEditor::OutboundEditor(QWidget *parent) OutboundEditor::OutboundEditor(QWidget *parent)
: QDialog(parent), : QDialog(parent),

View File

@ -4,7 +4,8 @@
#pragma once #pragma once
#include "w_RoutesEditor.hpp" #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_OutboundEditor.hpp"
#include "w_JsonEditor.hpp" #include "w_JsonEditor.hpp"
#include "w_InboundEditor.hpp" #include "w_InboundEditor.hpp"

View File

@ -16,19 +16,22 @@ ConfigExporter::~ConfigExporter()
UNREGISTER_WINDOW UNREGISTER_WINDOW
} }
ConfigExporter::ConfigExporter(const QImage &img, QWidget *parent): ConfigExporter(parent) ConfigExporter::ConfigExporter(const CONFIGROOT &root, QWidget *parent)
{ {
image = img; //
message = tr("Empty"); //auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject()));
} //auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outBoundRoot["streamSettings"].toObject()));
ConfigExporter::ConfigExporter(const QString &data, QWidget *parent): ConfigExporter(parent) //auto vmess = ConvertConfigToVMessString(transport, vmessServer, _identifier.connectionName);
{ //
QZXingEncoderConfig conf; //image = img;
conf.border = true; //message = tr("Empty");
conf.imageSize = QSize(400, 400); ////
auto img = qzxing.encodeData(data, conf); //QZXingEncoderConfig conf;
image = img.copy(); //conf.border = true;
message = data; //conf.imageSize = QSize(400, 400);
//auto img = qzxing.encodeData(data, conf);
//image = img.copy();
//message = data;
} }
void ConfigExporter::OpenExport() void ConfigExporter::OpenExport()

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "ui_w_ExportConfig.h" #include "ui_w_ExportConfig.h"
#include "base/Qv2rayBase.hpp"
#include "3rdparty/qzxing/src/QZXing.h" #include "3rdparty/qzxing/src/QZXing.h"
class ConfigExporter : public QDialog, private Ui::ExportConfigWindow class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
@ -8,8 +9,7 @@ class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
Q_OBJECT Q_OBJECT
public: public:
explicit ConfigExporter(const QImage &img, QWidget *parent = nullptr); explicit ConfigExporter(const CONFIGROOT &root, QWidget *parent = nullptr);
explicit ConfigExporter(const QString &data, QWidget *parent = nullptr);
~ConfigExporter(); ~ConfigExporter();
void OpenExport(); void OpenExport();
protected: protected:

View File

@ -9,7 +9,8 @@
#include "core/CoreUtils.hpp" #include "core/CoreUtils.hpp"
#include "core/kernel/QvKernelInteractions.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 "w_ScreenShot_Core.hpp"
#include "ui/editors/w_OutboundEditor.hpp" #include "ui/editors/w_OutboundEditor.hpp"

View File

@ -26,6 +26,8 @@
#include "components/plugins/toolbar/QvToolbar.hpp" #include "components/plugins/toolbar/QvToolbar.hpp"
#include "components/pac/QvPACHandler.hpp" #include "components/pac/QvPACHandler.hpp"
#include "core/connection/ConnectionIO.hpp"
// MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related operations. // MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related operations.
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING #define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
@ -1004,17 +1006,13 @@ void MainWindow::on_shareBtn_clicked()
auto _identifier = ItemConnectionIdentifier(connectionListWidget->currentItem()); auto _identifier = ItemConnectionIdentifier(connectionListWidget->currentItem());
auto root = connections[_identifier].config; auto root = connections[_identifier].config;
auto outBoundRoot = root["outbounds"].toArray().first().toObject(); auto type = get<2>(GetConnectionInfo(root));
auto outboundType = outBoundRoot["protocol"].toString();
if (!CheckIsComplexConfig(root) && outboundType == "vmess") { if (!CheckIsComplexConfig(root) && (type == "vmess" || type == "shadowsocks")) {
auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); ConfigExporter v(root, this);
auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outBoundRoot["streamSettings"].toObject()));
auto vmess = ConvertConfigToVMessString(transport, vmessServer, _identifier.connectionName);
ConfigExporter v(vmess, this);
v.OpenExport(); v.OpenExport();
} else { } 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() void MainWindow::on_action_RCM_ShareQR_triggered()
@ -1086,11 +1084,12 @@ void MainWindow::on_duplicateBtn_clicked()
CONFIGROOT conf; CONFIGROOT conf;
// Alias may change. // Alias may change.
QString alias = _identifier.connectionName; QString alias = _identifier.connectionName;
bool isComplex = CheckIsComplexConfig(connections[_identifier].config);
if (connections[_identifier].configType == CONNECTION_REGULAR) { 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 { } 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; alias = _identifier.subscriptionName + "_" + _identifier.connectionName;
} }

View File

@ -10,7 +10,7 @@
#include "core/CoreUtils.hpp" #include "core/CoreUtils.hpp"
#include "core/kernel/QvKernelInteractions.hpp" #include "core/kernel/QvKernelInteractions.hpp"
#include "core/connection/ConnectionConfigOperations.hpp" #include "core/connection/ConnectionIO.hpp"
#include "components/pac/QvPACHandler.hpp" #include "components/pac/QvPACHandler.hpp"
#include "common/LogHighlighter.hpp" #include "common/LogHighlighter.hpp"

View File

@ -3,6 +3,7 @@
// We NEED to include the cpp file to define the macros. // We NEED to include the cpp file to define the macros.
#include "w_MainWindow.cpp" #include "w_MainWindow.cpp"
#include "components/proxy/QvProxyConfigurator.hpp" #include "components/proxy/QvProxyConfigurator.hpp"
#include "core/connection/Generation.hpp"
QTreeWidgetItem *MainWindow::FindItemByIdentifier(QvConfigIdentifier identifier) QTreeWidgetItem *MainWindow::FindItemByIdentifier(QvConfigIdentifier identifier)
{ {

View File

@ -8,8 +8,8 @@
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "common/HTTPRequestHelper.hpp" #include "common/HTTPRequestHelper.hpp"
#include "core/config/ConfigBackend.hpp" #include "core/config/ConfigBackend.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/kernel/QvKernelInteractions.hpp" #include "core/kernel/QvKernelInteractions.hpp"
#include "core/connection/ConnectionConfigOperations.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp" #include "components/plugins/toolbar/QvToolbar.hpp"
#include "components/autolaunch/QvAutoLaunch.hpp" #include "components/autolaunch/QvAutoLaunch.hpp"

View File

@ -1,7 +1,9 @@
#include "w_SubscriptionManager.hpp" #include "w_SubscriptionManager.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "core/CoreUtils.hpp" #include "core/CoreUtils.hpp"
#include "core/connection/ConnectionConfigOperations.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/connection/Serialization.hpp"
SubscribeEditor::SubscribeEditor(QWidget *parent) : SubscribeEditor::SubscribeEditor(QWidget *parent) :
QDialog(parent) QDialog(parent)