Merge branch 'dev-mainwindow-refactor' into dev-streamsettingswidget-refactor

This commit is contained in:
Qv2ray-dev 2020-02-18 10:12:42 +08:00 committed by GitHub
commit c9661d89aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 7550 additions and 2179 deletions

View File

@ -45,7 +45,7 @@ include($$PWD/makespec/00-deps.pri)
# lrelease will not work when adding BEFORE 00-deps.pri
CONFIG += lrelease embed_translations
DEFINES += QT_DEPRECATED_WARNINGS QV2RAY_VERSION_STRING=\"\\\"v$${VERSION}\\\"\" QAPPLICATION_CLASS=QApplication
DEFINES += QT_DEPRECATED_WARNINGS QV2RAY_VERSION_STRING=\"\\\"v$${VERSION}\\\"\" QAPPLICATION_CLASS=QApplication XTOSTRUCT_QT
# Source file parser
include($$PWD/makespec/01-sourcesparser.pri)
@ -84,18 +84,23 @@ Qv2rayAddSource(core, config, ConfigUpgrade, cpp)
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, KernelInteractions, cpp, hpp)
Qv2rayAddSource(core, kernel, APIBackend, cpp, hpp)
Qv2rayAddSource(core, handler, ConnectionHandler, cpp, hpp)
Qv2rayAddSource(core, handler, SubscriptionHandler, cpp)
Qv2rayAddSource(core, handler, V2rayInstanceHandler, cpp, hpp)
Qv2rayAddSource(core, _, CoreUtils, cpp, hpp)
Qv2rayAddSource(core, _, CoreSafeTypes, hpp)
Qv2rayAddSource(ui, editors, w_InboundEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_JsonEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_OutboundEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_RoutesEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_RoutesEditor_extra, cpp)
Qv2rayAddSource(ui, nodemodels, InboundNodeModel, cpp, hpp)
Qv2rayAddSource(ui, nodemodels, OutboundNodeModel, cpp, hpp)
Qv2rayAddSource(ui, nodemodels, RuleNodeModel, cpp, hpp)
Qv2rayAddSource(ui, nodemodels, NodeModelsBase, hpp)
Qv2rayAddSource(ui, models, InboundNodeModel, cpp, hpp)
Qv2rayAddSource(ui, models, OutboundNodeModel, cpp, hpp)
Qv2rayAddSource(ui, models, RuleNodeModel, cpp, hpp)
Qv2rayAddSource(ui, models, NodeModelsBase, hpp)
Qv2rayAddSource(ui, models, ConnectionTreeModel, cpp, hpp)
Qv2rayAddSource(ui, messaging, QvMessageBus, cpp, hpp)
Qv2rayAddSource(ui, _, w_ExportConfig, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_ImportConfig, cpp, hpp, ui)
@ -104,6 +109,7 @@ Qv2rayAddSource(ui, _, w_MainWindow_extra, cpp)
Qv2rayAddSource(ui, _, w_PreferencesWindow, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_ScreenShot_Core, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_SubscriptionManager, cpp, hpp, ui)
Qv2rayAddSource(ui, widgets, ConnectionWidget, cpp, hpp, ui)
Qv2rayAddSource(ui, widgets, StreamSettingsWidget, cpp, hpp, ui)
SOURCES += $$PWD/src/main.cpp

View File

@ -1 +1 @@
3862
3885

294
qv2ray-config-models.qmodel Normal file
View File

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<qmt>
<project>
<uid>{e33c4c89-9b5b-44c4-9790-17cef05732d8}</uid>
<root-package>
<instance>
<MPackage>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{6035e8ea-cf65-4a95-b11b-59d640802d5e}</uid>
</MElement>
</base-MElement>
<name>Qv2ray-config-models</name>
<children>
<handles>
<handles>
<qlist>
<item>
<handle>
<uid>{0a303cb9-6681-4f79-9779-e61a34ac44ea}</uid>
<target>
<instance type="MCanvasDiagram">
<MCanvasDiagram>
<base-MDiagram>
<MDiagram>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{0a303cb9-6681-4f79-9779-e61a34ac44ea}</uid>
</MElement>
</base-MElement>
<name>Qv2ray-config-models</name>
</MObject>
</base-MObject>
<elements>
<qlist>
<item>
<instance type="DItem">
<DItem>
<base-DObject>
<DObject>
<base-DElement>
<DElement>
<uid>{89aa1d96-388b-49c0-a4e6-bf55bb570889}</uid>
</DElement>
</base-DElement>
<object>{314756b5-bc93-49b8-ae97-957fe8b30d44}</object>
<name>BaseGroupObject</name>
<pos>x:410;y:235</pos>
<rect>x:-75;y:-50;w:150;h:100</rect>
<auto-sized>false</auto-sized>
<visual-role>0</visual-role>
</DObject>
</base-DObject>
<shape-editable>false</shape-editable>
</DItem>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{7dd68311-11eb-43d0-9e64-91daeae12d97}</uid>
</DElement>
</base-DElement>
<text>Display Name</text>
<pos>x:350;y:215</pos>
<rect>x:0;y:0;w:84.2031;h:30</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DBoundary">
<DBoundary>
<base-DElement>
<DElement>
<uid>{e51a8692-6ecb-4052-8e09-f1b1ee3a2b92}</uid>
</DElement>
</base-DElement>
<text>Connection Groups</text>
<pos>x:260;y:230</pos>
<rect>x:-235;y:-75;w:470;h:150</rect>
</DBoundary>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{b4dc36e8-31f6-4637-9f8f-c27ee155e301}</uid>
</DElement>
</base-DElement>
<text>List&lt;ConnectionId&gt;</text>
<pos>x:350;y:235</pos>
<rect>x:0;y:0;w:111.391;h:30</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DBoundary">
<DBoundary>
<base-DElement>
<DElement>
<uid>{ffc9dfd5-2441-4b3b-b814-3ac76fb03c7e}</uid>
</DElement>
</base-DElement>
<text>Subscriptions</text>
<pos>x:565;y:230</pos>
<rect>x:-240;y:-75;w:480;h:150</rect>
</DBoundary>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{3634dcd7-fac8-4993-b3e7-c10450dae1de}</uid>
</DElement>
</base-DElement>
<text>Nothing here since the base group
is enough</text>
<pos>x:85;y:215</pos>
<rect>x:0;y:0;w:186.047;h:44</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{41e1ca4e-8395-472f-8470-912cf2c7b9d1}</uid>
</DElement>
</base-DElement>
<text>Some other metadata of subscription</text>
<pos>x:535;y:220</pos>
<rect>x:0;y:0;w:199.766;h:30</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DItem">
<DItem>
<base-DObject>
<DObject>
<base-DElement>
<DElement>
<uid>{d27ab510-0eda-4d06-ac71-cd8b1d68571f}</uid>
</DElement>
</base-DElement>
<object>{48b1692c-e2da-49cb-b1da-dd1030084013}</object>
<name>Address, last-renewed......</name>
<pos>x:610;y:205</pos>
<rect>x:-75;y:-15;w:150;h:30</rect>
<visual-role>0</visual-role>
</DObject>
</base-DObject>
<shape-editable>false</shape-editable>
</DItem>
</instance>
</item>
</qlist>
</elements>
<last-modified>1581683831371</last-modified>
<toolbarid>General</toolbarid>
</MDiagram>
</base-MDiagram>
</MCanvasDiagram>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{314756b5-bc93-49b8-ae97-957fe8b30d44}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{314756b5-bc93-49b8-ae97-957fe8b30d44}</uid>
</MElement>
</base-MElement>
<name>BaseGroupObject</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{e2922977-d357-43f0-822a-624245d6b470}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{e2922977-d357-43f0-822a-624245d6b470}</uid>
</MElement>
</base-MElement>
<name>New Item</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{8a788e13-b40c-4a33-8121-f0a4817428b1}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{8a788e13-b40c-4a33-8121-f0a4817428b1}</uid>
</MElement>
</base-MElement>
<name>Address</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{ec54fd48-400e-4e7d-9e74-b6333d2101c1}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{ec54fd48-400e-4e7d-9e74-b6333d2101c1}</uid>
</MElement>
</base-MElement>
<name>Some other metadata of subscription</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{48b1692c-e2da-49cb-b1da-dd1030084013}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{48b1692c-e2da-49cb-b1da-dd1030084013}</uid>
</MElement>
</base-MElement>
<name>Address, last-renewed......</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
</qlist>
</handles>
</handles>
</children>
</MObject>
</base-MObject>
</MPackage>
</instance>
</root-package>
</project>
</qmt>

2321
qv2ray-new.qmodel Normal file

File diff suppressed because it is too large Load Diff

2187
qv2ray.qmodel Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,11 +7,6 @@
#include <QTranslator>
// Instantiation for Qv2ray global objects.
#ifdef QT_DEBUG
const bool isDebugBuild = true;
#else
const bool isDebugBuild = false;
#endif
namespace Qv2ray
{

View File

@ -44,7 +44,12 @@ using namespace Qv2ray::base::objects::transfer;
#define QV2RAY_BUILD_INFO QString(_QV2RAY_BUILD_INFO_STR_)
#define QV2RAY_BUILD_EXTRA_INFO QString(_QV2RAY_BUILD_EXTRA_INFO_STR_)
extern const bool isDebugBuild;
#ifdef QT_DEBUG
inline const bool isDebugBuild = true;
#else
inline const bool isDebugBuild = false;
#endif
// Base folder suffix.
#ifdef QT_DEBUG
# define QV2RAY_CONFIG_DIR_SUFFIX "_debug/"
@ -55,6 +60,7 @@ extern const bool isDebugBuild;
// Get Configured Config Dir Path
#define QV2RAY_CONFIG_DIR (Qv2ray::Qv2rayConfigPath)
#define QV2RAY_CONFIG_FILE (QV2RAY_CONFIG_DIR + "Qv2ray.conf")
#define QV2RAY_CONNECTIONS_DIR (QV2RAY_CONFIG_DIR + "connections/")
#define QV2RAY_SUBSCRIPTION_DIR (QV2RAY_CONFIG_DIR + "subscriptions/")
// Get GFWList and PAC file path.
@ -76,7 +82,7 @@ extern const bool isDebugBuild;
#elif defined (QV2RAY_DEFAULT_VCORE_PATH) && defined (QV2RAY_DEFAULT_VASSETS_PATH)
// ---- Using user-specified VCore and VAssets path
#else
# error Both QV2RAY_DEFAULT_VCORE_PATH and QV2RAY_DEFAULT_VASSETS_PATH need to present when specifying the paths.
# error Both QV2RAY_DEFAULT_VCORE_PATH and QV2RAY_DEFAULT_VASSETS_PATH need to be presented when using manually specify the paths.
#endif
#ifdef Q_OS_WIN
@ -106,7 +112,6 @@ 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_"

View File

@ -1,5 +1,5 @@
#include "Qv2rayLog.hpp"
#include "GlobalInstances.hpp"
#include "Qv2rayBase.hpp"
namespace Qv2ray::base
{

View File

@ -31,21 +31,23 @@ namespace Qv2ray::base
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
// Log modules used by Qv2ray
const inline QString INIT = "INIT" ;
const inline QString MESSAGING = "BASE-MESSAGING" ;
const inline QString UI = "CORE-UI" ;
const inline QString GRAPH = "CORE-UI-GRAPH" ;
const inline QString SETTINGS = "CORE-SETTINGS" ;
const inline QString VCORE = "CORE-VCORE" ;
const inline QString MODULE_INIT = "INIT" ;
const inline QString MODULE_MESSAGING = "BASE-MESSAGING" ;
const inline QString MODULE_UI = "CORE-UI" ;
const inline QString MODULE_GRAPH = "CORE-UI-GRAPH" ;
const inline QString MODULE_SETTINGS = "CORE-SETTINGS" ;
const inline QString MODULE_VCORE = "CORE-VCORE" ;
//
const inline QString CONNECTION = "CORE-CONNECTION" ;
const inline QString SUBSCRIPTION = "CORE-SUBSCRIPTION" ;
const inline QString IMPORT = "CORE-IMPORT" ;
const inline QString EXPORT = "CORE-EXPORT" ;
const inline QString MODULE_CONNECTION = "CORE-CONNECTION" ;
const inline QString MODULE_SUBSCRIPTION = "CORE-SUBSCRIPTION" ;
const inline QString MODULE_IMPORT = "CORE-IMPORT" ;
const inline QString MODULE_EXPORT = "CORE-EXPORT" ;
//
const inline QString NETWORK = "COMMON-NETWORK" ;
const inline QString FILEIO = "COMMON-FILEIO" ;
const inline QString MODULE_NETWORK = "COMMON-NETWORK" ;
const inline QString MODULE_FILEIO = "COMMON-FILEIO" ;
//
const inline QString PROXY = "COMPONENT-PROXY" ;
const inline QString UPDATE = "COMPONENT-UPDATE" ;
const inline QString PLUGIN = "COMPONENT-PLUGIN" ;
const inline QString MODULE_PROXY = "COMPONENT-PROXY" ;
const inline QString MODULE_UPDATE = "COMPONENT-UPDATE" ;
const inline QString MODULE_PLUGIN = "COMPONENT-PLUGIN" ;
// ================================================================
const inline QString MODULE_CORE_HANDLER = "libQv2ray: ConnectionHandler";

View File

@ -4,53 +4,35 @@
#include "3rdparty/x2struct/x2struct.hpp"
namespace Qv2ray::base
{
struct ConnectionIdentifier {
QString subscriptionName;
QString connectionName;
ConnectionIdentifier() { };
bool isEmpty()
{
return connectionName.isEmpty();
}
ConnectionIdentifier(QString connectionName)
{
this->connectionName = connectionName;
}
ConnectionIdentifier(QString connectionName, QString subscriptionName)
{
this->connectionName = connectionName;
this->subscriptionName = subscriptionName;
}
const QString IdentifierString() const
{
return connectionName + (subscriptionName.isEmpty() ? "" : " (" + subscriptionName + ")");
}
friend bool operator==(ConnectionIdentifier &left, ConnectionIdentifier &right)
{
return left.subscriptionName == right.subscriptionName && left.connectionName == right.connectionName;
}
friend bool operator!=(ConnectionIdentifier &left, ConnectionIdentifier &right)
{
return !(left == right);
}
friend bool operator==(ConnectionIdentifier &left, QString &right)
{
return left.IdentifierString() == right;
}
friend bool operator!=(ConnectionIdentifier &left, QString &right)
{
return !(left.IdentifierString() == right);
}
// To make QMap happy
friend bool operator<(const ConnectionIdentifier left, const ConnectionIdentifier right)
{
return left.IdentifierString() < right.IdentifierString();
}
friend bool operator>(const ConnectionIdentifier left, const ConnectionIdentifier right)
{
return left.IdentifierString() > right.IdentifierString();
}
XTOSTRUCT(O(subscriptionName, connectionName))
using namespace std::chrono;
// Common struct for Groups and Subscriptions
struct _QvGroupObjectBase {
QString displayName;
QList<QString> connections;
_QvGroupObjectBase(): displayName(), connections() { }
};
struct QvGroupObject : _QvGroupObjectBase {
QvGroupObject() { }
XTOSTRUCT(O(displayName, connections))
};
struct QvSubscriptionObject : _QvGroupObjectBase {
QString address;
int64_t lastUpdated;
float updateInterval;
QvSubscriptionObject(): address(""), lastUpdated(system_clock::to_time_t(system_clock::now())), updateInterval(10) { }
XTOSTRUCT(O(lastUpdated, updateInterval, address, connections, displayName))
};
struct QvConnectionObject {
QString displayName;
int64_t importDate;
int64_t lastConnected;
int64_t latency;
int64_t upLinkData;
int64_t downLinkData;
QvConnectionObject(): displayName(), importDate(system_clock::to_time_t(system_clock::now())), lastConnected(), latency(0), upLinkData(0), downLinkData(0) { }
XTOSTRUCT(O(displayName, importDate, lastConnected, latency, upLinkData, downLinkData))
};
}
Q_DECLARE_METATYPE(Qv2ray::base::ConnectionIdentifier);

View File

@ -4,181 +4,148 @@
#include "base/models/QvConfigIdentifier.hpp"
#include <chrono>
const int QV2RAY_CONFIG_VERSION = 8;
const int QV2RAY_CONFIG_VERSION = 9;
namespace Qv2ray::base
namespace Qv2ray::base::config
{
namespace config
{
struct QvBarLine {
QString Family;
bool Bold, Italic;
int ColorA, ColorR, ColorG, ColorB;
int ContentType;
double Size;
QString Message;
QvBarLine(): Family("Consolas"), Bold(true), Italic(false), ColorA(255), ColorR(255), ColorG(255), ColorB(255),
ContentType(0), Size(9), Message("") { }
XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
};
struct QvBarPage {
int OffsetYpx;
QList<QvBarLine> Lines;
QvBarPage(): OffsetYpx(5) { }
XTOSTRUCT(O(OffsetYpx, Lines))
};
struct QvBarLine {
QString Family;
bool Bold;
bool Italic;
int ColorA;
int ColorR;
int ColorG;
int ColorB;
int ContentType;
double Size;
QString Message;
QvBarLine()
: Family("Consolas")
, Bold(true)
, Italic(false)
, ColorA(255), ColorR(255), ColorG(255), ColorB(255)
, ContentType(0)
, Size(9),
Message("") { }
XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
};
struct Qv2rayToolBarConfig {
QList<QvBarPage> Pages;
XTOSTRUCT(O(Pages))
};
struct QvBarPage {
int OffsetYpx;
QList<QvBarLine> Lines;
QvBarPage() : OffsetYpx(5) { }
XTOSTRUCT(O(OffsetYpx, Lines))
};
struct Qv2rayPACConfig {
bool enablePAC;
int port;
QString localIP;
bool useSocksProxy;
Qv2rayPACConfig(): enablePAC(false), port(8989), useSocksProxy(false) { }
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
};
struct Qv2rayToolBarConfig {
QList<QvBarPage> Pages;
XTOSTRUCT(O(Pages))
};
struct Qv2rayForwardProxyConfig {
bool enableForwardProxy;
QString type;
QString serverAddress;
int port;
bool useAuth;
QString username;
QString password;
Qv2rayForwardProxyConfig(): enableForwardProxy(false), type("http"), serverAddress("127.0.0.1"), port(8008),
useAuth(false), username(), password() { }
XTOSTRUCT(O(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
};
struct Qv2raySubscriptionConfig {
time_t lastUpdated;
float updateInterval;
QString address;
Qv2raySubscriptionConfig() : lastUpdated(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())), updateInterval(5), address("") { }
XTOSTRUCT(O(lastUpdated, updateInterval, address))
};
struct Qv2rayInboundsConfig {
QString listenip;
bool setSystemProxy;
Qv2rayPACConfig pacConfig;
struct Qv2rayPACConfig {
bool enablePAC;
int port;
QString localIP;
bool useSocksProxy;
Qv2rayPACConfig() : enablePAC(false), port(8989), useSocksProxy(false) { }
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
};
// SOCKS
bool useSocks;
int socks_port;
bool socks_useAuth;
bool socksUDP;
QString socksLocalIP;
objects::AccountObject socksAccount;
// HTTP
bool useHTTP;
int http_port;
bool http_useAuth;
objects::AccountObject httpAccount;
struct Qv2rayForwardProxyConfig {
bool enableForwardProxy;
QString type;
QString serverAddress;
int port;
bool useAuth;
QString username;
QString password;
Qv2rayInboundsConfig():
listenip("127.0.0.1"), setSystemProxy(false), pacConfig(),
useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true), socksLocalIP("127.0.0.1"), socksAccount(),
useHTTP(true), http_port(8888), http_useAuth(false), httpAccount() {}
Qv2rayForwardProxyConfig() :
enableForwardProxy(false),
type("http"), serverAddress("127.0.0.1"), port(8008), useAuth(false),
username("username"), password("password")
{ }
XTOSTRUCT(O(setSystemProxy, pacConfig, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP, http_port, http_useAuth, httpAccount))
};
XTOSTRUCT(O(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
};
struct Qv2rayUIConfig {
QString theme;
QString language;
bool useDarkTheme;
bool useDarkTrayIcon;
int maximumLogLines;
Qv2rayUIConfig() : theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500) { }
XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon, maximumLogLines))
};
struct Qv2rayInboundsConfig {
QString listenip;
bool setSystemProxy;
Qv2rayPACConfig pacConfig;
struct Qv2rayConnectionConfig {
bool bypassCN;
bool enableProxy;
bool withLocalDNS;
QList<QString> dnsList;
Qv2rayForwardProxyConfig forwardProxyConfig;
Qv2rayConnectionConfig() : bypassCN(true), enableProxy(true), withLocalDNS(false), dnsList(QStringList() << "8.8.4.4" << "1.1.1.1") { }
XTOSTRUCT(O(bypassCN, enableProxy, withLocalDNS, dnsList, forwardProxyConfig))
};
// SOCKS
bool useSocks;
int socks_port;
bool socks_useAuth;
bool socksUDP;
QString socksLocalIP;
objects::AccountObject socksAccount;
// HTTP
bool useHTTP;
int http_port;
bool http_useAuth;
objects::AccountObject httpAccount;
struct Qv2rayAPIConfig {
bool enableAPI;
int statsPort;
Qv2rayAPIConfig(): enableAPI(true), statsPort(15490) { }
XTOSTRUCT(O(enableAPI, statsPort))
};
Qv2rayInboundsConfig():
listenip("127.0.0.1"), setSystemProxy(false), pacConfig(),
useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true), socksLocalIP("127.0.0.1"), socksAccount(),
useHTTP(true), http_port(8888), http_useAuth(false), httpAccount() {}
struct Qv2rayConfig {
int config_version;
bool tProxySupport;
int logLevel;
//
QString v2CorePath;
QString v2AssetsPath;
QString ignoredVersion;
QString autoStartId;
//
// Key = groupId, connectionId, subscriptionId
QMap<QString, QvGroupObject> groups;
QMap<QString, QvSubscriptionObject> subscriptions;
/// Connections are used privately.
QMap<QString, QvConnectionObject> connections;
//
Qv2rayUIConfig uiConfig;
Qv2rayAPIConfig apiConfig;
Qv2rayToolBarConfig toolBarConfig;
Qv2rayInboundsConfig inboundConfig;
Qv2rayConnectionConfig connectionConfig;
XTOSTRUCT(O(setSystemProxy, pacConfig, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP, http_port, http_useAuth, httpAccount))
};
Qv2rayConfig():
config_version(QV2RAY_CONFIG_VERSION),
tProxySupport(false),
logLevel(),
v2CorePath(),
v2AssetsPath(),
ignoredVersion(),
groups(),
subscriptions(),
connections(),
uiConfig(), apiConfig(), toolBarConfig(), inboundConfig(), connectionConfig() { }
struct Qv2rayUIConfig {
QString theme;
QString language;
bool useDarkTheme;
bool useDarkTrayIcon;
int maximumLogLines;
Qv2rayUIConfig() : theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500) { }
XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon, maximumLogLines))
};
struct Qv2rayConnectionConfig {
bool bypassCN;
bool enableProxy;
bool withLocalDNS;
QList<QString> dnsList;
Qv2rayForwardProxyConfig forwardProxyConfig;
Qv2rayConnectionConfig() : bypassCN(true), enableProxy(true), withLocalDNS(false), dnsList(QStringList() << "8.8.4.4" << "1.1.1.1") { }
XTOSTRUCT(O(bypassCN, enableProxy, withLocalDNS, dnsList, forwardProxyConfig))
};
struct Qv2rayAPIConfig {
bool enableAPI;
int statsPort;
Qv2rayAPIConfig(): enableAPI(true), statsPort(15490) { }
XTOSTRUCT(O(enableAPI, statsPort))
};
struct Qv2rayConfig {
int config_version;
bool tProxySupport;
int logLevel;
//
QString v2CorePath;
QString v2AssetsPath;
ConnectionIdentifier autoStartConfig;
QString ignoredVersion;
//
QList<QString> configs;
QMap<QString, Qv2raySubscriptionConfig> subscriptions;
//
Qv2rayUIConfig uiConfig;
Qv2rayAPIConfig apiConfig;
Qv2rayInboundsConfig inboundConfig;
Qv2rayConnectionConfig connectionConfig;
Qv2rayToolBarConfig toolBarConfig;
Qv2rayConfig():
config_version(QV2RAY_CONFIG_VERSION),
tProxySupport(false),
logLevel(),
v2CorePath(),
v2AssetsPath(),
autoStartConfig(),
ignoredVersion(),
configs(),
subscriptions(),
uiConfig(),
apiConfig(),
inboundConfig(),
connectionConfig(),
toolBarConfig() { }
XTOSTRUCT(O(config_version,
ignoredVersion,
tProxySupport,
logLevel,
autoStartConfig,
v2CorePath, v2AssetsPath,
configs,
uiConfig,
subscriptions, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
};
}
XTOSTRUCT(O(config_version, ignoredVersion,
tProxySupport,
logLevel, uiConfig,
v2CorePath, v2AssetsPath,
groups, connections, subscriptions,
autoStartId, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
};
}

View File

@ -1,17 +1,20 @@
#pragma once
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#define SAFE_TYPEDEF(Base, name) \
#define SAFE_TYPEDEF_EXTRA(Base, name, extra) \
class name : public Base { \
public: \
template <class... Args> \
explicit name (Args... args) : Base(args...) {} \
const Base& raw() const { return *this; } \
};
extra };
#define nothing
#define SAFE_TYPEDEF(Base, name) SAFE_TYPEDEF_EXTRA(Base, name, nothing)
using namespace std;
namespace Qv2ray::base::safetype
{
// To prevent anonying QJsonObject misuse
@ -22,10 +25,11 @@ namespace Qv2ray::base::safetype
SAFE_TYPEDEF(QJsonObject, CONFIGROOT)
SAFE_TYPEDEF(QJsonObject, PROXYSETTING)
//
SAFE_TYPEDEF(QJsonArray, ROUTERULELIST)
SAFE_TYPEDEF(QJsonArray, INOUTLIST)
SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
SAFE_TYPEDEF(QJsonObject, ROUTING)
SAFE_TYPEDEF(QJsonObject, ROUTERULE)
SAFE_TYPEDEF(QJsonArray, ROUTERULELIST)
SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
}

View File

@ -36,22 +36,22 @@ namespace Qv2ray::common
return CommandLineHelpRequested;
if (parser.isSet(noAPIOption)) {
DEBUG(INIT, "noAPIOption is set.")
DEBUG(MODULE_INIT, "noAPIOption is set.")
StartupOption.noAPI = true;
}
if (parser.isSet(runAsRootOption)) {
DEBUG(INIT, "runAsRootOption is set.")
DEBUG(MODULE_INIT, "runAsRootOption is set.")
StartupOption.forceRunAsRootUser = true;
}
if (parser.isSet(debugOption)) {
DEBUG(INIT, "debugOption is set.")
DEBUG(MODULE_INIT, "debugOption is set.")
StartupOption.debugLog = true;
}
if (parser.isSet(withToolbarOption)) {
DEBUG(INIT, "withToolbarOption is set.")
DEBUG(MODULE_INIT, "withToolbarOption is set.")
StartupOption.enableToolbarPlguin = true;
}

View File

@ -19,7 +19,7 @@ namespace Qv2ray::common
QUrl qUrl = QUrl(url);
if (!qUrl.isValid()) {
LOG(NETWORK, "Provided URL is invalid: " + url)
LOG(MODULE_NETWORK, "Provided URL is invalid: " + url)
return false;
}
@ -29,7 +29,7 @@ namespace Qv2ray::common
void QvHttpRequestHelper::setHeader(const QByteArray &key, const QByteArray &value)
{
DEBUG(NETWORK, "Adding HTTP request header: " + key + ":" + value)
DEBUG(MODULE_NETWORK, "Adding HTTP request header: " + key + ":" + value)
request.setRawHeader(key, value);
}
@ -44,7 +44,7 @@ namespace Qv2ray::common
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
}
LOG(NETWORK, "Sync get is using system proxy settings")
LOG(MODULE_NETWORK, "Sync get is using system proxy settings")
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
reply = accessManager.get(request);
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
@ -104,13 +104,13 @@ namespace Qv2ray::common
void QvHttpRequestHelper::onRequestFinished()
{
LOG(NETWORK, "Network request errcode: " + QSTRN(reply->error()))
LOG(MODULE_NETWORK, "Network request errcode: " + QSTRN(reply->error()))
emit httpRequestFinished(this->data);
}
void QvHttpRequestHelper::onReadyRead()
{
DEBUG(NETWORK, "A request is now ready read")
DEBUG(MODULE_NETWORK, "A request is now ready read")
this->data += reply->readAll();
}
}

View File

@ -27,8 +27,7 @@ namespace Qv2ray::common
QString StringFromFile(QFile *source)
{
source->open(QFile::ReadOnly);
QTextStream stream(source);
QString str = stream.readAll();
QString str = QString::fromUtf8(source->readAll());
source->close();
return str;
}
@ -73,7 +72,7 @@ namespace Qv2ray::common
if (error.error == QJsonParseError::NoError) {
return "";
} else {
LOG(UI, "WARNING: Json parse returns: " + error.errorString())
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString())
return error.errorString();
}
}
@ -173,7 +172,7 @@ namespace Qv2ray::common
if (!QDir(baseDir).exists()) {
QDir(baseDir).mkpath(baseDir);
LOG(FILEIO, "Making path: " + baseDir)
LOG(MODULE_FILEIO, "Making path: " + baseDir)
}
while (true) {
@ -181,7 +180,7 @@ namespace Qv2ray::common
*fileName = *fileName + "_" + QSTRN(i);
return;
} else {
DEBUG(FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists")
DEBUG(MODULE_FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists")
}
i++;

View File

@ -37,6 +37,11 @@ namespace Qv2ray::common
// This function cannot be marked as inline.
QString RemoveInvalidFileName(const QString &fileName);
bool IsValidFileName(const QString &fileName);
inline QString GenerateUuid()
{
return GenerateRandomString().toLower();
//return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
//
template <typename TYPE>
QString StructToJsonString(const TYPE t)

View File

@ -6,7 +6,7 @@ namespace Qv2ray::components::geosite
QStringList ReadGeoSiteFromFile(QString filepath)
{
QStringList list;
LOG(FILEIO, "Reading geosites from: " + filepath)
LOG(MODULE_FILEIO, "Reading geosites from: " + filepath)
//
GOOGLE_PROTOBUF_VERIFY_VERSION;
//
@ -14,7 +14,7 @@ namespace Qv2ray::components::geosite
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
if (!opened) {
LOG(FILEIO, "File cannot be opened: " + filepath)
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
return list;
}
@ -29,7 +29,7 @@ namespace Qv2ray::components::geosite
list << QString::fromStdString(e.country_code()).toLower();
}
LOG(FILEIO, "Loaded " + QSTRN(list.count()) + " geosite entries from data file.")
LOG(MODULE_FILEIO, "Loaded " + QSTRN(list.count()) + " geosite entries from data file.")
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return list;

View File

@ -19,17 +19,17 @@ namespace Qv2ray::components::pac
}
void PACServer::SetProxyString(const QString &proxyString)
{
DEBUG(PROXY, "Setting new PAC proxy string: " + proxyString)
DEBUG(MODULE_PROXY, "Setting new PAC proxy string: " + proxyString)
this->proxyString = proxyString;
}
void PACServer::StartListen()
{
LOG(PROXY, "Starting PAC listener")
LOG(MODULE_PROXY, "Starting PAC listener")
//
auto address = GlobalConfig.inboundConfig.listenip;
auto port = GlobalConfig.inboundConfig.pacConfig.port;
//
DEBUG(PROXY, "PAC Listening local endpoint: " + address + ":" + QSTRN(port))
DEBUG(MODULE_PROXY, "PAC Listening local endpoint: " + address + ":" + QSTRN(port))
//
QString gfwContent = StringFromFile(QV2RAY_RULES_GFWLIST_PATH);
pacContent = ConvertGFWToPAC(gfwContent, proxyString);
@ -38,9 +38,9 @@ namespace Qv2ray::components::pac
if (result) {
isStarted = true;
DEBUG(PROXY, "Started PAC handler")
DEBUG(MODULE_PROXY, "Started PAC handler")
} else {
LOG(PROXY, "Failed to listen on port " + QSTRN(port) + ", possible permission denied.")
LOG(MODULE_PROXY, "Failed to listen on port " + QSTRN(port) + ", possible permission denied.")
QvMessageBoxWarn(nullptr, tr("PAC Handler"), tr("Failed to listen PAC request on this port, please verify the permissions"));
}
}
@ -49,7 +49,7 @@ namespace Qv2ray::components::pac
{
if (isStarted) {
pacServer.close();
DEBUG(PROXY, "PAC Handler stopped.")
DEBUG(MODULE_PROXY, "PAC Handler stopped.")
isStarted = false;
}
}
@ -61,12 +61,12 @@ namespace Qv2ray::components::pac
if (req->method() == QHttpRequest::HTTP_GET) {
//
if (req->path() == "/pac") {
DEBUG(PROXY, "Serving PAC file request.")
DEBUG(MODULE_PROXY, "Serving PAC file request.")
//
rsp->setHeader("Content-Type", "application/javascript; charset=utf-8");
rsp->writeHead(QHttpResponse::StatusCode::STATUS_OK);
rsp->end(pacContent.toUtf8());
DEBUG(PROXY, "Serving a pac file...")
DEBUG(MODULE_PROXY, "Serving a pac file...")
} else {
rsp->writeHead(QHttpResponse::StatusCode::STATUS_NOT_FOUND);
rsp->end("NOT FOUND");

View File

@ -31,13 +31,12 @@ namespace Qv2ray::components::plugins
QString GetAnswerToRequest(const QString &pchRequest)
{
auto instance = MainWindow::mwInstance;
if (instance == nullptr || instance->vinstance == nullptr) {
LOG(PLUGIN, "MainWindow != nullptr Assertion failed!")
return "{}";
}
auto vinstance = instance->vinstance;
//if (instance == nullptr || instance->vinstance == nullptr) {
// LOG(PLUGIN, "MainWindow != nullptr Assertion failed!")
// return "{}";
//}
//
//auto vinstance = instance->vinstance;
//
auto req = pchRequest.trimmed();
QString reply = "{}";
@ -81,67 +80,67 @@ namespace Qv2ray::components::plugins
break;
}
case 104: {
// Current Connection Name
CL.Message = instance->GetCurrentConnectedConfigName();
break;
}
case 105: {
// Current Connection Status
CL.Message = instance->vinstance->KernelStarted
? QObject::tr("Connected")
: QObject::tr("Disconnected");
break;
}
case 201: {
// Total upload speed;
CL.Message = FormatBytes(vinstance->getAllSpeedUp()) + "/s";
break;
}
case 202: {
// Total download speed;
CL.Message = FormatBytes(vinstance->getAllSpeedDown()) + "/s";
break;
}
case 203: {
// Upload speed for tag
CL.Message = FormatBytes(vinstance->getTagSpeedUp(CL.Message)) + "/s";
break;
}
case 204: {
// Download speed for tag
CL.Message = FormatBytes(vinstance->getTagSpeedDown(CL.Message)) + "/s";
break;
}
case 301: {
// Total Upload
CL.Message = FormatBytes(vinstance->getAllDataUp());
break;
}
case 302: {
// Total download
CL.Message = FormatBytes(vinstance->getAllDataDown());
break;
}
case 303: {
// Upload for tag
CL.Message = FormatBytes(vinstance->getTagDataUp(CL.Message));
break;
}
case 304: {
// Download for tag
CL.Message = FormatBytes(vinstance->getTagDataDown(CL.Message));
break;
}
//case 104: {
// // Current Connection Name
// CL.Message = instance->GetCurrentConnectedConfigName();
// break;
//}
//
//case 105: {
// // Current Connection Status
// CL.Message = instance->vinstance->KernelStarted
// ? QObject::tr("Connected")
// : QObject::tr("Disconnected");
// break;
//}
//
//case 201: {
// // Total upload speed;
// CL.Message = FormatBytes(vinstance->getAllSpeedUp()) + "/s";
// break;
//}
//
//case 202: {
// // Total download speed;
// CL.Message = FormatBytes(vinstance->getAllSpeedDown()) + "/s";
// break;
//}
//
//case 203: {
// // Upload speed for tag
// CL.Message = FormatBytes(vinstance->getTagSpeedUp(CL.Message)) + "/s";
// break;
//}
//
//case 204: {
// // Download speed for tag
// CL.Message = FormatBytes(vinstance->getTagSpeedDown(CL.Message)) + "/s";
// break;
//}
//
//case 301: {
// // Total Upload
// CL.Message = FormatBytes(vinstance->getAllDataUp());
// break;
//}
//
//case 302: {
// // Total download
// CL.Message = FormatBytes(vinstance->getAllDataDown());
// break;
//}
//
//case 303: {
// // Upload for tag
// CL.Message = FormatBytes(vinstance->getTagDataUp(CL.Message));
// break;
//}
//
//case 304: {
// // Download for tag
// CL.Message = FormatBytes(vinstance->getTagDataDown(CL.Message));
// break;
//}
default: {
CL.Message = "Not Supported?";

View File

@ -35,7 +35,7 @@ namespace Qv2ray::components::plugins::Toolbar
}
}
} catch (...) {
LOG(PLUGIN, "Closing a broken socket.")
LOG(MODULE_PLUGIN, "Closing a broken socket.")
}
}
void DataMessageQThread()
@ -55,8 +55,8 @@ namespace Qv2ray::components::plugins::Toolbar
while (!isExiting) {
bool result = server->waitForNewConnection(5000, &timeOut);
DEBUG(PLUGIN, "Plugin thread listening failed: " + server->errorString())
DEBUG(PLUGIN, "waitForNewConnection: " + QString(result ? "true" : "false") + ", " + QString(timeOut ? "true" : "false"))
DEBUG(MODULE_PLUGIN, "Plugin thread listening failed: " + server->errorString())
DEBUG(MODULE_PLUGIN, "waitForNewConnection: " + QString(result ? "true" : "false") + ", " + QString(timeOut ? "true" : "false"))
}
server->close();
@ -73,7 +73,7 @@ namespace Qv2ray::components::plugins::Toolbar
isExiting = true;
if (linuxWorkerThread->isRunning()) {
LOG(PLUGIN, "Waiting for linuxWorkerThread to stop.")
LOG(MODULE_PLUGIN, "Waiting for linuxWorkerThread to stop.")
linuxWorkerThread->wait();
}

View File

@ -44,18 +44,18 @@ namespace Qv2ray::components::plugins::Toolbar
hPipe = CreateNamedPipe(lpszPipename.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, nullptr);
if (hPipe == INVALID_HANDLE_VALUE) {
LOG(PLUGIN, "CreateNamedPipe failed, GLE=" + QSTRN(GetLastError()))
LOG(MODULE_PLUGIN, "CreateNamedPipe failed, GLE=" + QSTRN(GetLastError()))
return static_cast<DWORD>(-1);
}
fConnected = ConnectNamedPipe(hPipe, nullptr) ? true : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected) {
LOG(PLUGIN, "Client connected, creating a processing thread")
LOG(MODULE_PLUGIN, "Client connected, creating a processing thread")
ThreadHandle = CreateThread(nullptr, 0, InstanceThread, hPipe, 0, &dwThreadId);
if (ThreadHandle == nullptr) {
LOG(PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
return static_cast<DWORD>(-1);
} else CloseHandle(ThreadHandle);
} else CloseHandle(hPipe);
@ -76,9 +76,9 @@ namespace Qv2ray::components::plugins::Toolbar
if (!fSuccess || cbBytesRead == 0) {
if (GetLastError() == ERROR_BROKEN_PIPE) {
LOG(PLUGIN, "InstanceThread: client disconnected, GLE=" + QSTRN(GetLastError()))
LOG(MODULE_PLUGIN, "InstanceThread: client disconnected, GLE=" + QSTRN(GetLastError()))
} else {
LOG(PLUGIN, "InstanceThread ReadFile failed, GLE=" + QSTRN(GetLastError()))
LOG(MODULE_PLUGIN, "InstanceThread ReadFile failed, GLE=" + QSTRN(GetLastError()))
}
break;
@ -98,7 +98,7 @@ namespace Qv2ray::components::plugins::Toolbar
fSuccess = WriteFile(hPipe, pchReply.c_str(), cbReplyBytes, &cbWritten, nullptr);
if (!fSuccess || cbReplyBytes != cbWritten) {
LOG(PLUGIN, "InstanceThread WriteFile failed, GLE=" + QSTRN(GetLastError()))
LOG(MODULE_PLUGIN, "InstanceThread WriteFile failed, GLE=" + QSTRN(GetLastError()))
break;
}
}

View File

@ -174,19 +174,19 @@ namespace Qv2ray::components::proxy
bool hasSOCKS = (socksPort != 0);
if (!(hasHTTP || hasSOCKS || usePAC)) {
LOG(PROXY, "Nothing?")
LOG(MODULE_PROXY, "Nothing?")
return;
}
if (usePAC) {
LOG(PROXY, "Qv2ray will set system proxy to use PAC file")
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use PAC file")
} else {
if (hasHTTP) {
LOG(PROXY, "Qv2ray will set system proxy to use HTTP")
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use HTTP")
}
if (hasSOCKS) {
LOG(PROXY, "Qv2ray will set system proxy to use SOCKS")
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use SOCKS")
}
}
@ -235,13 +235,13 @@ namespace Qv2ray::components::proxy
// note: do not use std::all_of / any_of / none_of,
// because those are short-circuit and cannot guarantee atomicity.
auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString & action) {
DEBUG(PROXY, action)
DEBUG(MODULE_PROXY, action)
return QProcess::execute(action) == QProcess::NormalExit;
}) == actions.size();
if (!result) {
LOG(PROXY, "Something wrong happens when setting system proxy -> Gnome ONLY.")
LOG(PROXY, "If you are using KDE Plasma and receiving this message, just simply ignore this.")
LOG(MODULE_PROXY, "Something wrong happens when setting system proxy -> Gnome ONLY.")
LOG(MODULE_PROXY, "If you are using KDE Plasma and receiving this message, just simply ignore this.")
}
Q_UNUSED(result);

View File

@ -27,23 +27,23 @@ namespace Qv2ray::components::tcping
worker->cancel();
}
}
void QvTCPingModel::StartPing(const ConnectionIdentifier &connectionName, const QString &hostName, int port)
void QvTCPingModel::StartPing(const QvConnectionObject &connectionName, const QString &hostName, int port)
{
QvTCPingData data;
data.hostName = hostName;
data.port = port;
data.connectionIdentifier = connectionName;
auto watcher = new QFutureWatcher<QvTCPingData>(this);
DEBUG(NETWORK, "Start Ping: " + hostName + ":" + QSTRN(port))
DEBUG(MODULE_NETWORK, "Start Ping: " + hostName + ":" + QSTRN(port))
watcher->setFuture(QtConcurrent::run(&QvTCPingModel::startTestLatency, data, count));
pingWorkingThreads.enqueue(watcher);
connect(watcher, &QFutureWatcher<void>::finished, this, [this, watcher]() {
this->pingWorkingThreads.removeOne(watcher);
auto result = watcher->result();
DEBUG(NETWORK, "Ping finished: " + result.hostName + ":" + QSTRN(result.port) + " --> " + QSTRN(result.avg) + "ms")
DEBUG(MODULE_NETWORK, "Ping finished: " + result.hostName + ":" + QSTRN(result.port) + " --> " + QSTRN(result.avg) + "ms")
if (!result.errorMessage.isEmpty()) {
LOG(NETWORK, "Ping --> " + result.errorMessage)
LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage)
}
emit this->PingFinished(result);
@ -78,13 +78,13 @@ namespace Qv2ray::components::tcping
if ((errcode = testLatency(resolved, &start, &end)) != 0) {
if (errcode != -EADDRNOTAVAIL) {
LOG(NETWORK, "Error connecting to host: " + data.hostName + ":" + QSTRN(data.port) + " " + strerror(-errcode))
LOG(MODULE_NETWORK, "Error connecting to host: " + data.hostName + ":" + QSTRN(data.port) + " " + strerror(-errcode))
errorCount++;
} else {
if (noAddress) {
LOG(NETWORK, ".")
LOG(MODULE_NETWORK, ".")
} else {
LOG(NETWORK, "error connecting to host: " + QSTRN(-errcode) + " " + strerror(-errcode))
LOG(MODULE_NETWORK, "error connecting to host: " + QSTRN(-errcode) + " " + strerror(-errcode))
}
noAddress = true;

View File

@ -5,7 +5,7 @@
namespace Qv2ray::components::tcping
{
struct QvTCPingData {
ConnectionIdentifier connectionIdentifier;
QvConnectionObject connectionIdentifier;
QString hostName;
int port;
QString errorMessage;
@ -19,7 +19,7 @@ namespace Qv2ray::components::tcping
public:
explicit QvTCPingModel(int defaultCount = 5, QObject *parent = nullptr);
void StartPing(const ConnectionIdentifier &connectionName, const QString &hostName, int port);
void StartPing(const QvConnectionObject &connectionName, const QString &hostName, int port);
void StopAllPing();
signals:
void PingFinished(QvTCPingData data);

View File

@ -0,0 +1,43 @@
#pragma once
#include <QString>
#include <QHash>
#include <QHashFunctions>
namespace Qv2ray::core
{
template <typename T>
class IDType
{
public:
IDType(const QString &id): m_id(id) {}
friend bool operator==(const IDType<T> &lhs, const IDType<T> &rhs)
{
return lhs.m_id == rhs.m_id;
}
const QString &toString() const
{
return m_id;
}
uint qHash(uint seed) const
{
return ::qHash(m_id, seed);
}
private:
QString m_id;
};
template <typename T> uint qHash(const IDType<T> &key, uint seed = 0)
{
return key.qHash(seed);
}
//
class __QvGroup;
class __QvConnection;
class __QvSubscription;
typedef IDType<__QvGroup> GroupId;
typedef IDType<__QvConnection> ConnectionId;
typedef IDType<__QvSubscription> SubscriptionId;
}
using namespace Qv2ray::core;

View File

@ -18,7 +18,7 @@ namespace Qv2ray::core
if (validOutboundFound) {
return make_tuple(host, port, outboundType);
} else {
LOG(UI, "Unknown outbound entry: " + outboundType + ", cannot deduce host and port.")
LOG(MODULE_UI, "Unknown outbound entry: " + outboundType + ", cannot deduce host and port.")
}
}

View File

@ -3,7 +3,7 @@
namespace Qv2ray::core::config
{
void SaveGlobalConfig(Qv2rayConfig conf)
void SaveGlobalConfig(const Qv2rayConfig &conf)
{
GlobalConfig = conf;
QFile config(QV2RAY_CONFIG_FILE);
@ -19,17 +19,6 @@ namespace Qv2ray::core::config
Qv2rayConfigPath += "/";
}
}
void LoadGlobalConfig()
{
QFile file(QV2RAY_CONFIG_FILE);
file.open(QFile::ReadOnly);
QTextStream stream(&file);
auto str = stream.readAll();
auto config = StructFromJsonString<Qv2rayConfig>(str);
SaveGlobalConfig(config);
file.close();
}
}
using namespace Qv2ray::core::config;

View File

@ -2,9 +2,8 @@
namespace Qv2ray::core::config
{
void SaveGlobalConfig(Qv2rayConfig conf);
void SaveGlobalConfig(const Qv2rayConfig &conf);
void SetConfigDirPath(const QString &path);
void LoadGlobalConfig();
}
using namespace Qv2ray::core;

View File

@ -6,7 +6,7 @@
#include "base/Qv2rayBase.hpp"
#include "common/QvHelpers.hpp"
#define UPDATELOG(msg) LOG(SETTINGS, " [" + QSTRN(fromVersion) + "-" + QSTRN(fromVersion + 1) + "] --> " + msg)
#define UPGRADELOG(msg) LOG(MODULE_SETTINGS, " [" + QSTRN(fromVersion) + "-" + QSTRN(fromVersion + 1) + "] --> " + msg)
namespace Qv2ray
{
@ -14,45 +14,6 @@ namespace Qv2ray
QJsonObject UpgradeConfig_Inc(int fromVersion, QJsonObject root)
{
switch (fromVersion) {
case 1: {
auto v1_oldConfigVersion = root["config_version"].toString();
// From 1 to 2, we changed the config_version from 'string' to 'int'
root.remove("config_version");
root["config_version"] = 2;
UPDATELOG("Upgrading config_version from old value " + v1_oldConfigVersion + " to 2")
break;
}
case 2: {
// We copied those files.
auto vCoreFilePath = root["v2CorePath"].toString();
auto vCoreDestPath = QString(QV2RAY_DEFAULT_VCORE_PATH);
// We also need v2ctl
auto v2CtlFilePath = QFileInfo(vCoreFilePath).dir().path() + "/v2ctl";
auto v2CtlDestPath = QFileInfo(vCoreDestPath).dir().path() + "/v2ctl";
#ifdef Q_OS_WIN
v2CtlFilePath = v2CtlFilePath.append(".exe");
v2CtlDestPath = v2CtlDestPath.append(".exe");
#endif
QFile::copy(vCoreFilePath, vCoreDestPath);
QFile::copy(v2CtlFilePath, v2CtlDestPath);
root.remove("v2CorePath");
UPDATELOG("v2CorePath value from: " + vCoreFilePath + " to " + vCoreDestPath)
UPDATELOG("v2CtlFilePath value from: " + v2CtlFilePath + " to " + v2CtlDestPath)
break;
}
case 3: {
// We changed a key name in the config file.
//proxyDefault
auto oldProxyDefault = root["proxyDefault"].toBool();
root.remove("proxyDefault");
root["enableProxy"] = oldProxyDefault;
//enableProxy
UPDATELOG("key: proxyDefault->enableProxy, value from: " + QSTRN(oldProxyDefault) + " to " + QSTRN(oldProxyDefault))
break;
}
// --------------------------------------------------------------------------------------
// Below is for Qv2ray version 2
case 4: {
@ -62,12 +23,12 @@ namespace Qv2ray
// From 3 to 4, we changed 'runAsRoot' to 'tProxySupport'
auto v3_oldrunAsRoot = root["runAsRoot"].toBool();
root.insert("tProxySupport", v3_oldrunAsRoot);
UPDATELOG("Upgrading runAsRoot to tProxySupport, the value is not changed: " + QSTRN(v3_oldrunAsRoot))
UPGRADELOG("Upgrading runAsRoot to tProxySupport, the value is not changed: " + QSTRN(v3_oldrunAsRoot))
//
QString path;
path = QV2RAY_DEFAULT_VCORE_PATH;
root["v2CorePath"] = path;
UPDATELOG("Added v2CorePath to the config file.")
UPGRADELOG("Added v2CorePath to the config file.")
//
QJsonObject uiSettings;
uiSettings["language"] = root["language"].toString("en-US").replace("-", "_");
@ -75,7 +36,7 @@ namespace Qv2ray
//
root["inboundConfig"] = root["inBoundSettings"];
root.remove("inBoundSettings");
UPDATELOG("Renamed inBoundSettings to inboundConfig.")
UPGRADELOG("Renamed inBoundSettings to inboundConfig.")
//
//connectionConfig
QJsonObject o;
@ -85,9 +46,9 @@ namespace Qv2ray
o["bypassCN"] = !v2_oldProxyCN;
o["enableStats"] = true;
o["statsPort"] = 13459;
UPDATELOG("Default statistics enabled.")
UPGRADELOG("Default statistics enabled.")
root["connectionConfig"] = o;
UPDATELOG("Renamed some connection configs to connectionConfig.")
UPGRADELOG("Renamed some connection configs to connectionConfig.")
//
// Do we need renaming here?
// //auto inbound = root["inboundConfig"].toObject();
@ -97,10 +58,10 @@ namespace Qv2ray
// //root["inboundConfig"] = inbound;
// //UPDATELOG("Renamed usePAC to enablePAC.")
//
ConnectionIdentifier i;
i.connectionName = root["autoStartConfig"].toString();
root["autoStartConfig"] = GetRootObject(i);
UPDATELOG("Added subscription feature to autoStartConfig.")
QJsonObject i;
i["connectionName"] = root["autoStartConfig"].toString();
root["autoStartConfig"] = i;
UPGRADELOG("Added subscription feature to autoStartConfig.")
break;
}
@ -113,7 +74,7 @@ namespace Qv2ray
for (auto item = subs.begin(); item != subs.end(); item++) {
auto key = item.key();
Qv2raySubscriptionConfig _conf;
QvSubscriptionObject _conf;
_conf.address = item.value().toString();
_conf.lastUpdated = system_clock::to_time_t(system_clock::now());
_conf.updateInterval = 5;
@ -122,7 +83,7 @@ namespace Qv2ray
}
root["subscriptions"] = newSubscriptions;
UPDATELOG("Added subscription renewal options.")
UPGRADELOG("Added subscription renewal options.")
break;
}
@ -141,9 +102,118 @@ namespace Qv2ray
auto uiConfig = root["uiConfig"].toObject();
uiConfig["language"] = lang;
root["uiConfig"] = uiConfig;
UPDATELOG("Changed language: " + lang)
UPGRADELOG("Changed language: " + lang)
break;
}
// From version 8 to 9, we introduced a lot of new connection metainfo(s)
case 8: {
// Generate a default group
QJsonObject defaultGroup;
QStringList defaultGroupConnectionId;
defaultGroup["displayName"] = QObject::tr("Default Group");
QString defaultGroupId = "000000000000";
if (!QDir(QV2RAY_CONNECTIONS_DIR + defaultGroupId).exists()) {
QDir().mkpath(QV2RAY_CONNECTIONS_DIR + defaultGroupId);
}
QString autoStartId;
UPGRADELOG("Upgrading connections...")
QJsonObject rootConnections;
for (auto config : root["configs"].toArray()) {
UPGRADELOG("Migrating: " + config.toString())
//
// MOVE FILES.
// OLD PATH is at QV2RAY_CONFIG_DIR
auto filePath = QV2RAY_CONFIG_DIR + config.toString() + QV2RAY_CONFIG_FILE_EXTENSION;
auto configFile = QFile(filePath);
auto newUuid = GenerateUuid();
DEBUG(MODULE_SETTINGS, "Generated new UUID: " + newUuid);
if (configFile.exists()) {
auto newPath = QV2RAY_CONNECTIONS_DIR + defaultGroupId + "/" + newUuid + QV2RAY_CONFIG_FILE_EXTENSION;
configFile.rename(newPath);
UPGRADELOG("Moved: " + filePath + " to " + newPath);
} else {
UPGRADELOG("WARNING! This file is not found, possible loss of data!")
continue;
}
QJsonObject connectionObject;
connectionObject["displayName"] = config.toString();
defaultGroupConnectionId << newUuid;
DEBUG(MODULE_SETTINGS, "Pushed uuid: " + newUuid + " to default group.")
rootConnections[newUuid] = connectionObject;
}
// Upgrading subscriptions.
QJsonObject rootSubscriptions = root.take("subscriptions").toObject();
QJsonObject newSubscriptions;
for (auto i = 0; i < rootSubscriptions.count(); i++) {
auto key = rootSubscriptions.keys()[i];
auto value = rootSubscriptions.value(key);
//
UPGRADELOG("Upgrading subscription: " + key)
QString subsUuid = GenerateUuid();
QJsonObject subs;
QStringList subsConnectionIds;
subs["address"] = value["address"].toString();
subs["lastUpdated"] = value["lastUpdated"];
subs["updateInterval"] = value["updateInterval"];
subs["displayName"] = key;
//
auto baseDirPath = QV2RAY_SUBSCRIPTION_DIR + key;
auto newDirPath = QV2RAY_SUBSCRIPTION_DIR + subsUuid;
QDir newDir(newDirPath);
if (!newDir.exists()) {
newDir.mkpath(newDirPath);
}
// With extensions
auto fileList = GetFileList(baseDirPath);
// Copy every file within a subscription.
for (auto fileName : fileList) {
auto subsConnectionId = GenerateUuid();
auto baseFilePath = baseDirPath + "/" + fileName;
auto newFilePath = newDirPath + "/" + subsConnectionId + QV2RAY_CONFIG_FILE_EXTENSION;
//
QJsonObject subsConnection;
subsConnection["displayName"] = fileName.chopped(QString(QV2RAY_CONFIG_FILE_EXTENSION).count());
QFile(baseFilePath).rename(newFilePath);
UPGRADELOG("Moved subscription file from: " + baseFilePath + " to: " + newFilePath);
subsConnectionIds << subsConnectionId;
rootConnections[subsConnectionId] = subsConnection;
}
subs["connections"] = QJsonArray::fromStringList(subsConnectionIds);
newSubscriptions[subsUuid] = subs;
QDir().rmdir(baseDirPath);
}
defaultGroup["connections"] = QJsonArray::fromStringList(defaultGroupConnectionId);
QJsonObject groups;
groups[defaultGroupId] = defaultGroup;
root["groups"] = groups;
root["connections"] = rootConnections;
root["subscriptions"] = newSubscriptions;
UPGRADELOG("Finished upgrading config, version 8.")
break;
}
default: {
// Due to technical issue, we cannot maintain all of those upgrade processes anymore.
// Check https://github.com/Qv2ray/Qv2ray/issues/353#issuecomment-586117507 for more information
QvMessageBoxWarn(nullptr, QObject::tr("Configuration Upgrade Failed"),
QObject::tr("Unsupported config version number: ") + QSTRN(fromVersion) + NEWLINE + NEWLINE +
QObject::tr("Please upgrade firstly up to Qv2ray v2.0/v2.1 and try again."));
throw new runtime_error("The configuration version of your old Qv2ray installation is out-of-date and that"
" version is not supported anymore, please try to update to an intermediate version of Qv2ray first.");
}
}
root["config_version"] = root["config_version"].toInt() + 1;
@ -153,7 +223,7 @@ namespace Qv2ray
// Exported function
QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root)
{
LOG(SETTINGS, "Migrating config from version " + QSTRN(fromVersion) + " to " + QSTRN(toVersion))
LOG(MODULE_SETTINGS, "Migrating config from version " + QSTRN(fromVersion) + " to " + QSTRN(toVersion))
for (int i = fromVersion; i < toVersion; i++) {
root = UpgradeConfig_Inc(i, root);

View File

@ -5,170 +5,132 @@ namespace Qv2ray::core::connection
{
namespace ConnectionIO
{
CONFIGROOT _ReadConnection(const QString &connection)
CONFIGROOT ReadConnectionInternal(const QString &connection)
{
QString jsonString = StringFromFile(connection);
auto conf = CONFIGROOT(JsonFromString(jsonString));
if (conf.count() == 0) {
LOG(SETTINGS, "WARN: Possible file corruption, failed to load file: " + connection + " --> File might be empty.")
LOG(MODULE_SETTINGS, "WARN: Possible file corruption, failed to load file: " + connection + " --> File might be empty.")
}
return conf;
}
QMap<QString, CONFIGROOT> GetRegularConnections(QStringList connectionNames)
CONFIGROOT GetConnectionRoot(const GroupId &group, const ConnectionId &id)
{
QMap<QString, CONFIGROOT> list;
for (auto conn : connectionNames) {
list.insert(conn, _ReadConnection(QV2RAY_CONFIG_DIR + conn + QV2RAY_CONFIG_FILE_EXTENSION));
}
return list;
return ReadConnectionInternal(QV2RAY_CONNECTIONS_DIR + group.toString() + "/" + id.toString() + QV2RAY_CONFIG_FILE_EXTENSION);
}
QMap<QString, CONFIGROOT> GetSubscriptionConnection(QString subscription)
CONFIGROOT GetConnectionRoot(const SubscriptionId &subscription, const ConnectionId &id)
{
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(SUBSCRIPTION, "Found a file in subscription folder but without proper suffix: " + _file)
}
}
if (_config.isEmpty()) {
LOG(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(SUBSCRIPTION, "Processing subscription: " + singleSub)
list[singleSub] = GetSubscriptionConnection(singleSub);
}
return list;
return ReadConnectionInternal(QV2RAY_SUBSCRIPTION_DIR + subscription.toString() + "/" + id.toString() + QV2RAY_CONFIG_FILE_EXTENSION);
}
////
//// 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);
// auto fullPath = QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION;
//
// 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);
auto fullPath = QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION;
// If there's already a file AND we CANNOT override existing file.
if (QFile::exists(fullPath) && !canOverrideExisting) {
// Alias is a pointer to a QString.
DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias, QV2RAY_CONFIG_FILE_EXTENSION);
fullPath = QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION;
}
LOG(SETTINGS, "Saving a config named: " + *alias)
QFile config(fullPath);
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(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + fName + QV2RAY_CONFIG_FILE_EXTENSION);
// If there's already a file. THIS IS EXTREMELY RARE
if (config.exists()) {
LOG(FILEIO, "Trying to overrwrite an existing subscription config file. THIS IS RARE")
}
LOG(SETTINGS, "Saving a subscription named: " + fName)
bool result = StringToFile(&str, &config);
if (!result) {
LOG(FILEIO, "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(FILEIO, "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(FILEIO, "Trying to remove a non-existing file?")
return false;
} else {
return config.remove();
}
}
bool RenameConnection(const QString &originalName, const QString &newName)
{
LOG(CONNECTION, "[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(SUBSCRIPTION, "[RENAME] --> ORIGINAL: " + originalName + ", NEW: " + newName)
return QDir().rename(QV2RAY_SUBSCRIPTION_DIR + originalName, QV2RAY_SUBSCRIPTION_DIR + newName);
}
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex)
{
QFile source(sourceFilePath);
if (!source.exists()) {
LOG(FILEIO, "Trying to import from an non-existing file.")
return CONFIGROOT();
}
auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
if (!importComplex) {
JSON_ROOT_TRY_REMOVE("inbounds")
JSON_ROOT_TRY_REMOVE("routing")
}
JSON_ROOT_TRY_REMOVE("log")
JSON_ROOT_TRY_REMOVE("api")
JSON_ROOT_TRY_REMOVE("stats")
JSON_ROOT_TRY_REMOVE("dns")
return root;
}
// // If there's already a file AND we CANNOT override existing file.
// if (QFile::exists(fullPath) && !canOverrideExisting) {
// // Alias is a pointer to a QString.
// DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias, QV2RAY_CONFIG_FILE_EXTENSION);
// fullPath = QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION;
// }
//
// LOG(MODULE_SETTINGS, "Saving a config named: " + *alias)
// QFile config(fullPath);
// 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(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + fName + QV2RAY_CONFIG_FILE_EXTENSION);
//
// // If there's already a file. THIS IS EXTREMELY RARE
// if (config.exists()) {
// LOG(MODULE_FILEIO, "Trying to overrwrite an existing subscription config file. THIS IS RARE")
// }
//
// LOG(MODULE_SETTINGS, "Saving a subscription named: " + fName)
// bool result = StringToFile(&str, &config);
//
// if (!result) {
// LOG(MODULE_FILEIO, "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_FILEIO, "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_FILEIO, "Trying to remove a non-existing file?")
// return false;
// } else {
// return config.remove();
// }
//}
//
//bool RenameConnection(const QString &originalName, const QString &newName)
//{
// LOG(MODULE_CONNECTION, "[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 importComplex)
//{
// QFile source(sourceFilePath);
//
// if (!source.exists()) {
// LOG(MODULE_FILEIO, "Trying to import from an non-existing file.")
// return CONFIGROOT();
// }
//
// auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
//
// if (!importComplex) {
// JSON_ROOT_TRY_REMOVE("inbounds")
// JSON_ROOT_TRY_REMOVE("routing")
// }
//
// JSON_ROOT_TRY_REMOVE("log")
// JSON_ROOT_TRY_REMOVE("api")
// JSON_ROOT_TRY_REMOVE("stats")
// JSON_ROOT_TRY_REMOVE("dns")
// return root;
//}
}
}

View File

@ -1,28 +1,27 @@
#include "base/Qv2rayBase.hpp"
#include "core/CoreSafeTypes.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);
CONFIGROOT GetConnectionRoot(const GroupId &group, const ConnectionId &id);
CONFIGROOT GetConnectionRoot(const SubscriptionId &subscription, const ConnectionId &id);
//
// Save Connection Config
bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool canOverrideExisting);
bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name);
bool SaveConnectionConfig(CONFIGROOT obj, const ConnectionId &id, bool canOverrideExisting);
bool SaveSubscriptionConfig(CONFIGROOT obj, const SubscriptionId &subscription, const ConnectionId &name);
//
bool RemoveConnection(const QString &alias);
bool RemoveSubscriptionConnection(const QString &subsName, const QString &name);
bool RemoveConnection(const SubscriptionId &id);
bool RemoveSubscriptionConnection(const SubscriptionId &id, const ConnectionId &name);
//
bool RenameConnection(const QString &originalName, const QString &newName);
bool RenameSubscription(const QString &originalName, const QString &newName);
bool RenameConnection(const ConnectionId &id, const QString &newName);
bool RenameSubscription(const SubscriptionId &id, const QString &newName);
// File Protocol
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex);
}
}
using namespace Qv2ray::core;
using namespace Qv2ray::core::connection;
using namespace Qv2ray::core::connection::ConnectionIO;

View File

@ -181,7 +181,7 @@ namespace Qv2ray::core::connection
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing, QJsonObject allocate)
{
INBOUND root;
LOG(CONNECTION, "allocation is not used here.")
LOG(MODULE_CONNECTION, "allocation is not used here.")
Q_UNUSED(allocate)
JADD(listen, port, protocol, settings, tag, sniffing)
RROOT
@ -261,7 +261,7 @@ namespace Qv2ray::core::connection
}
root["inbounds"] = inboundsList;
DEBUG(CONNECTION, "Added global config inbounds to the config")
DEBUG(MODULE_CONNECTION, "Added global config inbounds to the config")
}
// Process every inbounds to make sure a tag is configured, fixed API 0 speed
@ -272,7 +272,7 @@ namespace Qv2ray::core::connection
auto _inboundItem = newTaggedInbounds[i].toObject();
if (!_inboundItem.contains("tag") || _inboundItem["tag"].toString().isEmpty()) {
LOG(SETTINGS, "Adding a tag to an inbound.")
LOG(MODULE_SETTINGS, "Adding a tag to an inbound.")
_inboundItem["tag"] = GenerateRandomString(8);
newTaggedInbounds[i] = _inboundItem;
}
@ -294,7 +294,7 @@ namespace Qv2ray::core::connection
// And what's more, process (by removing unused items) from a rule object.
ROUTING routing = ROUTING(root["routing"].toObject());
ROUTERULELIST rules;
LOG(CONNECTION, "Processing an existing routing table.")
LOG(MODULE_CONNECTION, "Processing an existing routing table.")
for (auto _rule : routing["rules"].toArray()) {
auto _b = _rule.toObject();
@ -308,14 +308,14 @@ namespace Qv2ray::core::connection
_b.remove("balancerTag");
}
} else {
LOG(SETTINGS, "We found a rule without QV2RAY_RULE_USE_BALANCER, so don't process it.")
LOG(MODULE_SETTINGS, "We found a rule without QV2RAY_RULE_USE_BALANCER, so don't process it.")
}
// If this entry has been disabled.
if (_b.contains("QV2RAY_RULE_ENABLED") && _b["QV2RAY_RULE_ENABLED"].toBool() == true) {
rules.append(_b);
} else {
LOG(SETTINGS, "Discarded a rule as it's been set DISABLED")
LOG(MODULE_SETTINGS, "Discarded a rule as it's been set DISABLED")
}
}
@ -323,12 +323,12 @@ namespace Qv2ray::core::connection
root["routing"] = routing;
} else {
//
LOG(CONNECTION, "Inserting default values to simple config")
LOG(MODULE_CONNECTION, "Inserting default values to simple config")
if (root["outbounds"].toArray().count() != 1) {
// There are no ROUTING but 2 or more outbounds.... This is rare, but possible.
LOG(CONNECTION, "WARN: This message usually indicates the config file has logic errors:")
LOG(CONNECTION, "WARN: --> The config file has NO routing section, however more than 1 outbounds are detected.")
LOG(MODULE_CONNECTION, "WARN: This message usually indicates the config file has logic errors:")
LOG(MODULE_CONNECTION, "WARN: --> The config file has NO routing section, however more than 1 outbounds are detected.")
}
auto routeObject = GenerateRoutes(GlobalConfig.connectionConfig.enableProxy, GlobalConfig.connectionConfig.bypassCN);
@ -342,7 +342,7 @@ namespace Qv2ray::core::connection
auto firstOutbound = outboundArray.first().toObject();
if (firstOutbound[QV2RAY_USE_FPROXY_KEY].toBool(false)) {
LOG(CONNECTION, "Applying forward proxy to current connection.")
LOG(MODULE_CONNECTION, "Applying forward proxy to current connection.")
auto proxy = PROXYSETTING();
proxy["tag"] = OUTBOUND_TAG_FORWARD_PROXY;
firstOutbound["proxySettings"] = proxy;
@ -353,7 +353,7 @@ namespace Qv2ray::core::connection
fpOutbound = GenerateHTTPSOCKSOut(fpConf.serverAddress, fpConf.port, fpConf.useAuth, fpConf.username, fpConf.password);
outboundArray.push_back(GenerateOutboundEntry(fpConf.type.toLower(), fpOutbound, QJsonObject(), QJsonObject(), "0.0.0.0", OUTBOUND_TAG_FORWARD_PROXY));
} else {
LOG(CONNECTION, "WARNING: Unsupported outbound type: " + fpConf.type)
LOG(MODULE_CONNECTION, "WARNING: Unsupported outbound type: " + fpConf.type)
}
} else {
// Remove proxySettings from firstOutbound

View File

@ -38,7 +38,7 @@ namespace Qv2ray::core::connection
auto ssServer = StructFromJsonString<ShadowSocksServerObject>(JsonToString(outbound["settings"].toObject()["servers"].toArray().first().toObject()));
sharelink = ConvertConfigToSSString(ssServer, alias, isSip002);
} else {
LOG(CONNECTION, "Unsupported outbound type: " + type)
LOG(MODULE_CONNECTION, "Unsupported outbound type: " + type)
}
return sharelink;
@ -101,13 +101,13 @@ namespace Qv2ray::core::connection
//auto ssUri = _ssUri.toStdString();
if (ssUri.length() < 5) {
LOG(CONNECTION, "ss:// string too short")
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(CONNECTION, "Hash sign position: " + QSTRN(hashPos))
DEBUG(MODULE_CONNECTION, "Hash sign position: " + QSTRN(hashPos))
if (hashPos >= 0) {
// Get the name/remark
@ -123,13 +123,13 @@ namespace Qv2ray::core::connection
// uri.erase(pluginPos);
//}
auto atPos = uri.indexOf('@');
DEBUG(CONNECTION, "At sign position: " + QSTRN(atPos))
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(CONNECTION, "Colon position: " + QSTRN(colonPos))
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
if (colonPos < 0) {
*errMessage = QObject::tr("Can't find the colon separator between method and password");
@ -138,7 +138,7 @@ namespace Qv2ray::core::connection
server.method = decoded.left(colonPos);
decoded.remove(0, colonPos + 1);
atPos = decoded.lastIndexOf('@');
DEBUG(CONNECTION, "At sign position: " + QSTRN(atPos))
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
if (atPos < 0) {
*errMessage = QObject::tr("Can't find the at separator between password and hostname");
@ -147,7 +147,7 @@ namespace Qv2ray::core::connection
server.password = decoded.mid(0, atPos);
decoded.remove(0, atPos + 1);
colonPos = decoded.lastIndexOf(':');
DEBUG(CONNECTION, "Colon position: " + QSTRN(colonPos))
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
if (colonPos < 0) {
*errMessage = QObject::tr("Can't find the colon separator between hostname and port");
@ -163,7 +163,7 @@ namespace Qv2ray::core::connection
QString userInfo = Base64Decode(x.userName());
auto userInfoSp = userInfo.indexOf(':');
//
DEBUG(CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
DEBUG(MODULE_CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
if (userInfoSp < 0) {
*errMessage = QObject::tr("Can't find the colon separator between method and password");
@ -180,7 +180,7 @@ namespace Qv2ray::core::connection
outbounds.append(GenerateOutboundEntry("shadowsocks", GenerateShadowSocksOUT(QList<ShadowSocksServerObject>() << server), QJsonObject()));
JADD(outbounds)
*alias = alias->isEmpty() ? d_name : *alias + "_" + d_name;
LOG(CONNECTION, "Deduced alias: " + *alias)
LOG(MODULE_CONNECTION, "Deduced alias: " + *alias)
return root;
}
@ -189,12 +189,12 @@ namespace Qv2ray::core::connection
auto myAlias = QUrl::toPercentEncoding(alias);
if (isSip002) {
LOG(CONNECTION, "Converting an ss-server config to Sip002 ss:// format")
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) + "#" + myAlias;
} else {
LOG(CONNECTION, "Converting an ss-server config to old ss:// string format")
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) + "#" + myAlias;
}
@ -205,11 +205,11 @@ namespace Qv2ray::core::connection
CONFIGROOT ConvertConfigFromVMessString(const QString &vmessStr, QString *alias, QString *errMessage)
{
#define default CONFIGROOT()
LOG(SETTINGS, "Trying to convert from a vmess string.")
LOG(MODULE_SETTINGS, "Trying to convert from a vmess string.")
QString vmess = vmessStr;
if (vmess.trimmed() != vmess) {
LOG(SETTINGS, "VMess string has some prefix/postfix spaces, trimming.")
LOG(MODULE_SETTINGS, "VMess string has some prefix/postfix spaces, trimming.")
vmess = vmessStr.trimmed();
}
@ -264,7 +264,7 @@ namespace Qv2ray::core::connection
//return flag ? 0 : 1;
} catch (exception *e) {
*errMessage = e->what();
LOG(IMPORT, "Failed to decode vmess string: " + *errMessage)
LOG(MODULE_IMPORT, "Failed to decode vmess string: " + *errMessage)
delete e;
return default;
}
@ -292,15 +292,15 @@ namespace Qv2ray::core::connection
if (vmessConf.contains(#key) && !vmessConf[#key].toVariant().toString().trimmed().isEmpty() \
&& (val.size() <= 1 || val.contains(vmessConf[#key].toVariant().toString()))) {\
key = vmessConf[#key].toVariant().toString();\
DEBUG(IMPORT, "Found key \"" #key "\" within the vmess object.")\
DEBUG(MODULE_IMPORT, "Found key \"" #key "\" within the vmess object.")\
} else if (!val.isEmpty()) {\
key = val.first(); \
DEBUG(IMPORT, "Using key \"" #key "\" from the first candidate list: " + key)\
DEBUG(MODULE_IMPORT, "Using key \"" #key "\" from the first candidate list: " + key)\
} else{\
*errMessage = QObject::tr(#key " does not exist."); \
LOG(IMPORT, "Cannot process \"" #key "\" since it's not included in the json object." ) \
LOG(IMPORT, " --> values: " + val.join(";")) \
LOG(IMPORT, " --> PS: " + ps) \
LOG(MODULE_IMPORT, "Cannot process \"" #key "\" since it's not included in the json object." ) \
LOG(MODULE_IMPORT, " --> values: " + val.join(";")) \
LOG(MODULE_IMPORT, " --> PS: " + ps) \
}\
}
// Strict check of VMess protocol, to check if the specified value is in the correct range.

View File

@ -0,0 +1,86 @@
#include "ConnectionHandler.hpp"
namespace Qv2ray::core::handlers
{
template<typename IDType>
QList<IDType> StringsToIdList(const QList<QString> &strings)
{
QList<IDType> list;
for (auto str : strings) {
list << IDType(str);
}
return list;
}
QvConnectionHandler::QvConnectionHandler()
{
DEBUG(MODULE_CORE_HANDLER, "ConnectionHandler Constructor.")
// Do we need to check how many of them are loaded?
for (auto i = 0; i < GlobalConfig.connections.count(); i++) {
connections[ConnectionId(GlobalConfig.connections.keys()[i])] = GlobalConfig.connections.values()[i];
}
for (auto i = 0; i < GlobalConfig.subscriptions.count(); i++) {
subscriptions[SubscriptionId(GlobalConfig.subscriptions.keys()[i])] = GlobalConfig.subscriptions.values()[i];
}
for (auto i = 0; i < GlobalConfig.groups.count(); i++) {
groups[GroupId(GlobalConfig.groups.keys()[i])] = GlobalConfig.groups.values()[i];
}
kernelInstance = new V2rayKernelInstance();
saveTimerId = startTimer(60000);
}
const QList<GroupId> QvConnectionHandler::Groups() const
{
return groups.keys();
}
const QList<SubscriptionId> QvConnectionHandler::Subscriptions() const
{
return subscriptions.keys();
}
const QList<ConnectionId> QvConnectionHandler::Connections() const
{
return connections.keys();
}
const QList<ConnectionId> QvConnectionHandler::Connections(const GroupId &groupId) const
{
return StringsToIdList<ConnectionId>(groups[groupId].connections);
}
const QList<ConnectionId> QvConnectionHandler::Connections(const SubscriptionId &subscriptionId) const
{
return StringsToIdList<ConnectionId>(subscriptions[subscriptionId].connections);
}
const QvConnectionObject &QvConnectionHandler::GetConnection(const ConnectionId &id)
{
if (!connections.contains(id)) {
LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString());
}
return connections[id];
}
const QvGroupObject &QvConnectionHandler::GetGroup(const GroupId &id)
{
return groups[id];
}
const QvSubscriptionObject &QvConnectionHandler::GetSubscription(const SubscriptionId &id)
{
return subscriptions[id];
}
QvConnectionHandler::~QvConnectionHandler()
{
if (kernelInstance->KernelStarted) {
kernelInstance->StopConnection();
LOG(MODULE_CORE_HANDLER, "Stopped connection from destructor.")
}
delete kernelInstance;
}
}

View File

@ -0,0 +1,104 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include "core/CoreSafeTypes.hpp"
#include "core/connection/ConnectionIO.hpp"
namespace Qv2ray::core::handlers
{
class QvConnectionHandler : public QObject
{
Q_OBJECT
public:
explicit QvConnectionHandler();
~QvConnectionHandler();
//
const QList<GroupId> Groups() const;
const QList<ConnectionId> Connections() const;
const QList<SubscriptionId> Subscriptions() const;
const QList<ConnectionId> Connections(const GroupId &groupId) const;
const QList<ConnectionId> Connections(const SubscriptionId &subscriptionId) const;
//
optional<QString> StopConnection(const ConnectionId &id);
//
template<typename T>
optional<QString> StartConnection(const T &group, const ConnectionId &id)
{
if (!connections.contains(id)) {
return tr("No connection selected!") + NEWLINE + tr("Please select a config from the list.");
}
auto root = GetConnectionRoot(group, id);
return _CHTryStartConnection_p(id, root);
}
template<typename T> optional<QString> StartConnection(const GroupId &group, const ConnectionId &id);
template<typename T> optional<QString> StartConnection(const SubscriptionId &group, const ConnectionId &id);
//
public:
//
// Connection Operations.
const QvConnectionObject &GetConnection(const ConnectionId &id);
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
optional<QString> DeleteConnection(const ConnectionId &id);
optional<QString> UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
optional<QString> DuplicateConnection(const ConnectionId &id);
optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
//
// Misc Connection Operations
optional<QString> TestLatency(const ConnectionId &id);
optional<QString> TestLatency(const GroupId &id);
optional<QString> TestLatency(const SubscriptionId &id);
optional<QString> TestAllLatency();
//
// Group Operations
const QvGroupObject &GetGroup(const GroupId &id);
const GroupId CreateGroup(const QString displayName);
optional<QString> DeleteGroup(const GroupId &id);
optional<QString> DuplicateGroup(const GroupId &id);
optional<QString> RenameGroup(const GroupId &id, const QString &newName);
//
// Subscriptions
const QvSubscriptionObject &GetSubscription(const SubscriptionId &id);
const SubscriptionId &CreateSubscription(const QString &displayName, const QString &address);
optional<QString> RenameSubscription(const SubscriptionId &id, const QString &newName);
optional<QString> DeleteSubscription(const SubscriptionId &id);
optional<QString> UpdateSubscription(const SubscriptionId &id);
optional<QString> UpdateSubscriptionASync(const SubscriptionId &id);
signals:
void OnConnectionCreated(const ConnectionId &id, const QString &displayName);
void OnConnectionRenamed(const ConnectionId &id, const QString &originalName, const QString &newName);
void OnConnectionChanged(const ConnectionId &id);
void OnConnectionGroupChanged(const ConnectionId &id, const QString &originalGroup, const QString &newGroup);
//
void OnConnectionLatencyTestFinished(const ConnectionId &id);
//
void OnGroupCreated(const GroupId &id, const QString &displayName);
void OnGroupRenamed(const GroupId &id, const QString &oldName, const QString &newName);
void OnGroupDeleted(const GroupId &id, const QString &displayName);
//
void OnSubscriptionCreated(const SubscriptionId &id, const QString &displayName, const QString &address);
void OnSubscriptionDeleted(const SubscriptionId &id);
void OnSubscriptionRenamed(const SubscriptionId &id, const QString &oldName, const QString &newName);
void OnSubscriptionUpdateFinished(const SubscriptionId &id);
private:
int saveTimerId;
QHash<GroupId, QvGroupObject> groups;
QHash<ConnectionId, QvConnectionObject> connections;
QHash<SubscriptionId, QvSubscriptionObject> subscriptions;
//
// We only support one cuncurrent connection currently.
//QHash<ConnectionId, V2rayKernelInstance> kernelInstances;
V2rayKernelInstance *kernelInstance = nullptr;
//
optional<QString> _CHTryStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
};
//
inline QvConnectionHandler *ConnectionHandler = nullptr;
}
using namespace Qv2ray::core::handlers;

View File

@ -0,0 +1 @@
//

View File

@ -0,0 +1,56 @@
#include "ConnectionHandler.hpp"
#include "core/connection/Generation.hpp"
optional<QString> QvConnectionHandler::_CHTryStartConnection_p(const ConnectionId &id, const CONFIGROOT &root)
{
auto &connectionMeta = connections[id];
auto fullConfig = GenerateRuntimeConfig(root);
return kernelInstance->StartConnection(fullConfig);
//if (startFlag) {
// bool usePAC = GlobalConfig.inboundConfig.pacConfig.enablePAC;
// bool pacUseSocks = GlobalConfig.inboundConfig.pacConfig.useSocksProxy;
// bool httpEnabled = GlobalConfig.inboundConfig.useHTTP;
// bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
//
// if (usePAC) {
// bool canStartPAC = true;
// QString pacProxyString; // Something like this --> SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT; http://proxy:8080
// auto pacIP = GlobalConfig.inboundConfig.pacConfig.localIP;
//
// if (pacIP.isEmpty()) {
// LOG(MODULE_PROXY, "PAC Local IP is empty, default to 127.0.0.1")
// pacIP = "127.0.0.1";
// }
//
// if (pacUseSocks) {
// if (socksEnabled) {
// pacProxyString = "SOCKS5 " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.socks_port);
// } else {
// LOG(MODULE_UI, "PAC is using SOCKS, but it is not enabled")
// QvMessageBoxWarn(this, tr("Configuring PAC"), tr("Could not start PAC server as it is configured to use SOCKS, but it is not enabled"));
// canStartPAC = false;
// }
// } else {
// if (httpEnabled) {
// pacProxyString = "PROXY " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.http_port);
// } else {
// LOG(MODULE_UI, "PAC is using HTTP, but it is not enabled")
// QvMessageBoxWarn(this, tr("Configuring PAC"), tr("Could not start PAC server as it is configured to use HTTP, but it is not enabled"));
// canStartPAC = false;
// }
// }
//
// if (canStartPAC) {
// pacServer.SetProxyString(pacProxyString);
// pacServer.StartListen();
// } else {
// LOG(MODULE_PROXY, "Not starting PAC due to previous error.")
// }
// }
//
// if (GlobalConfig.inboundConfig.setSystemProxy) {
// MWSetSystemProxy();
// }
//}
return "startFlag";
}

View File

@ -19,15 +19,15 @@ namespace Qv2ray::core::kernel::api
{
thread = new QThread();
this->moveToThread(thread);
DEBUG(VCORE, "API Worker initialised.")
DEBUG(MODULE_VCORE, "API Worker initialised.")
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(thread, &QThread::finished, []() {
LOG(VCORE, "API thread stopped")
LOG(MODULE_VCORE, "API thread stopped")
});
started = true;
thread->start();
DEBUG(VCORE, "API Worker started.")
DEBUG(MODULE_VCORE, "API Worker started.")
}
void APIWorkder::StartAPI(QStringList tags)
@ -74,7 +74,7 @@ namespace Qv2ray::core::kernel::api
Stub = service.NewStub(Channel);
#else
auto str = Dial(const_cast<char *>(channelAddress.toStdString().c_str()), 10000);
LOG(VCORE, QString(str))
LOG(MODULE_VCORE, QString(str))
free(str);
#endif
dialed = true;
@ -105,10 +105,10 @@ namespace Qv2ray::core::kernel::api
thread->exit();
}
long APIWorkder::CallStatsAPIByName(QString name)
qint64 APIWorkder::CallStatsAPIByName(QString name)
{
if (apiFailedCounter == QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD) {
LOG(VCORE, "API call failure threshold reached, cancelling further API aclls.")
LOG(MODULE_VCORE, "API call failure threshold reached, cancelling further API aclls.")
emit error("Failed to get statistics data, please check if V2ray is running properly");
apiFailedCounter++;
return 0;
@ -129,13 +129,13 @@ namespace Qv2ray::core::kernel::api
apiFailedCounter++;
}
auto data = response.stat().value();
qint64 data = response.stat().value();
#else
auto data = GetStats(const_cast<char *>(name.toStdString().c_str()), 1000);
qint64 data = GetStats(const_cast<char *>(name.toStdString().c_str()), 1000);
#endif
if (data < 0) {
LOG(VCORE, "API call returns: " + QSTRN(data))
LOG(MODULE_VCORE, "API call returns: " + QSTRN(data))
apiFailedCounter++;
return 0;
}

View File

@ -26,11 +26,11 @@ namespace Qv2ray::core::kernel::api
void process();
signals:
void OnDataReady(QString tag, long dataUp, long dataDown);
void OnDataReady(QString tag, qint64 dataUp, qint64 dataDown);
void error(QString err);
private:
long CallStatsAPIByName(QString name);
qint64 CallStatsAPIByName(QString name);
QStringList inboundTags;
QThread *thread;
//

View File

@ -12,14 +12,14 @@ namespace Qv2ray::core::kernel
QFile coreFile(vCorePath);
if (!coreFile.exists()) {
DEBUG(VCORE, "V2ray core file cannot be found.")
DEBUG(MODULE_VCORE, "V2ray core file cannot be found.")
*message = tr("V2ray core executable not found.");
return false;
}
// Use open() here to prevent `executing` a folder, which may have the same name as the V2ray core.
if (!coreFile.open(QFile::ReadOnly)) {
DEBUG(VCORE, "V2ray core file cannot be opened, possibly be a folder?")
DEBUG(MODULE_VCORE, "V2ray core file cannot be opened, possibly be a folder?")
*message = tr("V2ray core file cannot be opened, please ensure there's a file instead of a folder.");
return false;
}
@ -33,19 +33,19 @@ namespace Qv2ray::core::kernel
bool hasGeoSite = FileExistsIn(QDir(vAssetsPath), "geosite.dat");
if (!hasGeoIP && !hasGeoSite) {
DEBUG(VCORE, "V2ray assets path contains none of those two files.")
DEBUG(MODULE_VCORE, "V2ray assets path contains none of those two files.")
*message = tr("V2ray assets path is not valid.");
return false;
}
if (!hasGeoIP) {
DEBUG(VCORE, "No geoip.dat in assets path, aborting.")
DEBUG(MODULE_VCORE, "No geoip.dat in assets path, aborting.")
*message = tr("No geoip.dat in assets path.");
return false;
}
if (!hasGeoSite) {
DEBUG(VCORE, "No geosite.dat in assets path, aborting.")
DEBUG(MODULE_VCORE, "No geosite.dat in assets path, aborting.")
*message = tr("No geosite.dat in assets path.");
return false;
}
@ -66,13 +66,13 @@ namespace Qv2ray::core::kernel
auto exitCode = proc.exitCode();
if (exitCode != 0) {
DEBUG(VCORE, "VCore failed with an exit code: " + QSTRN(exitCode))
DEBUG(MODULE_VCORE, "VCore failed with an exit code: " + QSTRN(exitCode))
*message = tr("V2ray core failed with an exit code: ") + QSTRN(exitCode);
return false;
}
QString output = proc.readAllStandardOutput();
LOG(VCORE, "V2ray output: " + SplitLines(output).join(";"))
LOG(MODULE_VCORE, "V2ray output: " + SplitLines(output).join(";"))
if (SplitLines(output).isEmpty()) {
*message = tr("V2ray core returns empty string.");
@ -89,14 +89,14 @@ namespace Qv2ray::core::kernel
QString v2rayCheckResult;
if (ValidateKernel(GlobalConfig.v2CorePath, GlobalConfig.v2AssetsPath, &v2rayCheckResult)) {
DEBUG(VCORE, "V2ray version: " + v2rayCheckResult)
DEBUG(MODULE_VCORE, "V2ray version: " + v2rayCheckResult)
// Append assets location env.
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("V2RAY_LOCATION_ASSET", GlobalConfig.v2AssetsPath);
//
QProcess process;
process.setProcessEnvironment(env);
DEBUG(VCORE, "Starting V2ray core with test options")
DEBUG(MODULE_VCORE, "Starting V2ray core with test options")
process.start(GlobalConfig.v2CorePath, QStringList() << "-test" << "-config" << path, QIODevice::ReadWrite | QIODevice::Text);
process.waitForFinished();
@ -105,7 +105,7 @@ namespace Qv2ray::core::kernel
QvMessageBoxWarn(nullptr, tr("Configuration Error"), output.mid(output.indexOf("anti-censorship.") + 17));
return false;
} else {
DEBUG(VCORE, "Config file check passed.")
DEBUG(MODULE_VCORE, "Config file check passed.")
return true;
}
} else {
@ -123,11 +123,11 @@ namespace Qv2ray::core::kernel
emit onProcessOutputReadyRead(vProcess->readAllStandardOutput().trimmed());
});
connect(vProcess, &QProcess::stateChanged, [this](QProcess::ProcessState state) {
DEBUG(VCORE, "V2ray kernel process status changed: " + QVariant::fromValue(state).toString())
DEBUG(MODULE_VCORE, "V2ray kernel process status changed: " + QVariant::fromValue(state).toString())
// If V2ray crashed AFTER we start it.
if (KernelStarted && state == QProcess::NotRunning) {
LOG(VCORE, "V2ray kernel crashed.")
LOG(MODULE_VCORE, "V2ray kernel crashed.")
StopConnection();
emit onProcessErrored();
}
@ -137,15 +137,14 @@ namespace Qv2ray::core::kernel
KernelStarted = false;
}
bool V2rayKernelInstance::StartConnection(CONFIGROOT root)
optional<QString> V2rayKernelInstance::StartConnection(CONFIGROOT root)
{
if (KernelStarted) {
LOG(VCORE, "Status is invalid, expect STOPPED when calling StartConnection")
return false;
LOG(MODULE_VCORE, "Status is invalid, expect STOPPED when calling StartConnection")
return tr("Invalid V2ray Instance Status.");
}
// Write the final configuration to the disk.
QString json = JsonToString(root);
QFile configFile(QV2RAY_GENERATED_FILE_PATH);
StringToFile(&json, &configFile);
@ -158,7 +157,7 @@ namespace Qv2ray::core::kernel
vProcess->setProcessEnvironment(env);
vProcess->start(GlobalConfig.v2CorePath, QStringList() << "-config" << filePath, QIODevice::ReadWrite | QIODevice::Text);
vProcess->waitForStarted();
DEBUG(VCORE, "V2ray core started.")
DEBUG(MODULE_VCORE, "V2ray core started.")
KernelStarted = true;
QStringList inboundTags;
@ -173,26 +172,26 @@ namespace Qv2ray::core::kernel
inboundTags.append(tag);
}
DEBUG(VCORE, "Found inbound tags: " + inboundTags.join(";"))
DEBUG(MODULE_VCORE, "Found inbound tags: " + inboundTags.join(";"))
apiEnabled = false;
//
if (StartupOption.noAPI) {
LOG(VCORE, "API has been disabled by the command line argument \"-noAPI\"")
LOG(MODULE_VCORE, "API has been disabled by the command line argument \"-noAPI\"")
} else if (!GlobalConfig.apiConfig.enableAPI) {
LOG(VCORE, "API has been disabled by the global config option")
LOG(MODULE_VCORE, "API has been disabled by the global config option")
} else if (inboundTags.isEmpty()) {
LOG(VCORE, "API is disabled since no inbound tags configured. This is probably caused by a bad complex config.")
LOG(MODULE_VCORE, "API is disabled since no inbound tags configured. This is probably caused by a bad complex config.")
} else {
apiWorker->StartAPI(inboundTags);
apiEnabled = true;
DEBUG(VCORE, "Qv2ray API started")
DEBUG(MODULE_VCORE, "Qv2ray API started")
}
return true;
return {};
} else {
KernelStarted = false;
return false;
return tr("V2ray kernel failed to start.");
}
}
@ -226,7 +225,7 @@ namespace Qv2ray::core::kernel
delete vProcess;
}
void V2rayKernelInstance::onAPIDataReady(QString tag, long totalUp, long totalDown)
void V2rayKernelInstance::onAPIDataReady(QString tag, qulonglong totalUp, qulonglong totalDown)
{
auto dataup = totalUp - transferDataUp[tag];
transferDataUp[tag] = totalUp;
@ -238,23 +237,23 @@ namespace Qv2ray::core::kernel
}
// ------------------------------------------------------------- API FUNCTIONS --------------------------
long V2rayKernelInstance::getTagSpeedUp(const QString &tag)
qulonglong V2rayKernelInstance::getTagSpeedUp(const QString &tag)
{
return transferSpeedUp[tag];
}
long V2rayKernelInstance::getTagSpeedDown(const QString &tag)
qulonglong V2rayKernelInstance::getTagSpeedDown(const QString &tag)
{
return transferSpeedDown[tag];
}
long V2rayKernelInstance::getTagDataUp(const QString &tag)
qulonglong V2rayKernelInstance::getTagDataUp(const QString &tag)
{
return transferDataUp[tag];
}
long V2rayKernelInstance::getTagDataDown(const QString &tag)
qulonglong V2rayKernelInstance::getTagDataDown(const QString &tag)
{
return transferDataDown[tag];
}
long V2rayKernelInstance::getAllDataUp()
qulonglong V2rayKernelInstance::getAllDataUp()
{
long val = 0;
@ -264,7 +263,7 @@ namespace Qv2ray::core::kernel
return val;
}
long V2rayKernelInstance::getAllDataDown()
qulonglong V2rayKernelInstance::getAllDataDown()
{
long val = 0;
@ -274,9 +273,9 @@ namespace Qv2ray::core::kernel
return val;
}
long V2rayKernelInstance::getAllSpeedUp()
qulonglong V2rayKernelInstance::getAllSpeedUp()
{
long val = 0;
qulonglong val = 0;
for (auto _val : transferSpeedUp.values()) {
val += _val;
@ -284,9 +283,9 @@ namespace Qv2ray::core::kernel
return val;
}
long V2rayKernelInstance::getAllSpeedDown()
qulonglong V2rayKernelInstance::getAllSpeedDown()
{
long val = 0;
qulonglong val = 0;
for (auto _val : transferSpeedDown.values()) {
val += _val;

View File

@ -13,16 +13,16 @@ namespace Qv2ray::core::kernel
~V2rayKernelInstance() override;
//
// Speed
long getTagSpeedUp(const QString &tag);
long getTagSpeedDown(const QString &tag);
long getTagDataUp(const QString &tag);
long getTagDataDown(const QString &tag);
long getAllDataUp();
long getAllDataDown();
long getAllSpeedUp();
long getAllSpeedDown();
qulonglong getTagSpeedUp(const QString &tag);
qulonglong getTagSpeedDown(const QString &tag);
qulonglong getTagDataUp(const QString &tag);
qulonglong getTagDataDown(const QString &tag);
qulonglong getAllDataUp();
qulonglong getAllDataDown();
qulonglong getAllSpeedUp();
qulonglong getAllSpeedDown();
//
bool StartConnection(CONFIGROOT root);
optional<QString> StartConnection(CONFIGROOT root);
void StopConnection();
bool KernelStarted = false;
//
@ -34,16 +34,16 @@ namespace Qv2ray::core::kernel
void onProcessOutputReadyRead(QString);
public slots:
void onAPIDataReady(QString tag, long totalUp, long totalDown);
void onAPIDataReady(QString tag, qulonglong totalUp, qulonglong totalDown);
private:
APIWorkder *apiWorker;
QProcess *vProcess;
bool apiEnabled;
QMap<QString, long> transferDataUp;
QMap<QString, long> transferDataDown;
QMap<QString, long> transferSpeedUp;
QMap<QString, long> transferSpeedDown;
QMap<QString, qulonglong> transferDataUp;
QMap<QString, qulonglong> transferDataDown;
QMap<QString, qulonglong> transferSpeedUp;
QMap<QString, qulonglong> transferSpeedDown;
};
}

View File

@ -9,6 +9,9 @@
#include <singleapplication.h>
#include <csignal>
#include "ui/w_MainWindow.hpp"
#include "core/config/ConfigBackend.hpp"
#include "core/handler/ConnectionHandler.hpp"
#include "common/QvHelpers.hpp"
#include "common/CommandArgs.hpp"
#include "common/QvTranslator.hpp"
@ -21,12 +24,10 @@
void signalHandler(int signum)
{
cout << "Interrupt signal (" << signum << ") received." << endl;
if (MainWindow::mwInstance && MainWindow::mwInstance->vinstance) {
cout << "Trying to stop connection..." << endl;
MainWindow::mwInstance->vinstance->StopConnection();
}
//if (MainWindow::mwInstance && MainWindow::mwInstance->vinstance) {
// cout << "Trying to stop connection..." << endl;
// MainWindow::mwInstance->vinstance->StopConnection();
//}
qApp->exit(-99);
}
@ -41,8 +42,8 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
bool opened = testFile.open(QFile::OpenModeFlag::ReadWrite);
if (!opened) {
LOG(SETTINGS, "Directory at: " + path + " cannot be used as a valid config file path.")
LOG(INIT, "---> Cannot create a new file or openwrite a file.")
LOG(MODULE_SETTINGS, "Directory at: " + path + " cannot be used as a valid config file path.")
LOG(MODULE_INIT, "---> Cannot create a new file or openwrite a file.")
return false;
} else {
testFile.write("Qv2ray test file, feel free to remove.");
@ -52,8 +53,8 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
if (!removed) {
// This is rare, as we can create a file but failed to remove it.
LOG(SETTINGS, "Directory at: " + path + " cannot be used as a valid config file path.")
LOG(INIT, "---> Cannot remove a file.")
LOG(MODULE_SETTINGS, "Directory at: " + path + " cannot be used as a valid config file path.")
LOG(MODULE_INIT, "---> Cannot remove a file.")
return false;
}
}
@ -78,21 +79,21 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
auto err = VerifyJsonString(StringFromFile(&configFile));
if (!err.isEmpty()) {
LOG(INIT, "Json parse returns: " + err)
LOG(MODULE_INIT, "Json parse returns: " + err)
return false;
} else {
// If the file format is valid.
auto conf = JsonFromString(StringFromFile(&configFile));
LOG(SETTINGS, "Path: " + path + " contains a config file, in version " + conf["config_version"].toVariant().toString())
LOG(MODULE_SETTINGS, "Path: " + path + " contains a config file, in version " + conf["config_version"].toVariant().toString())
configFile.close();
return true;
}
} else {
LOG(SETTINGS, "File: " + configFile.fileName() + " cannot be opened!")
LOG(MODULE_SETTINGS, "File: " + configFile.fileName() + " cannot be opened!")
return false;
}
} catch (...) {
LOG(SETTINGS, "Exception raised when checking config: " + configFile.fileName())
LOG(MODULE_SETTINGS, "Exception raised when checking config: " + configFile.fileName())
//LOG(INIT, e->what())
QvMessageBoxWarn(nullptr, QObject::tr("Warning"), QObject::tr("Qv2ray cannot load the config file from here:") + NEWLINE + configFile.fileName());
return false;
@ -102,7 +103,7 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
bool initialiseQv2ray()
{
LOG(INIT, "Application exec path: " + QApplication::applicationDirPath())
LOG(MODULE_INIT, "Application exec path: " + QApplication::applicationDirPath())
const QString currentPathConfig = QApplication::applicationDirPath() + "/config" QV2RAY_CONFIG_DIR_SUFFIX;
const QString configQv2ray = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/qv2ray" QV2RAY_CONFIG_DIR_SUFFIX;
const QString homeQv2ray = QDir::homePath() + "/.qv2ray" QV2RAY_CONFIG_DIR_SUFFIX;
@ -131,11 +132,11 @@ bool initialiseQv2ray()
if (hasExistingConfig) break;
if (isValidConfigPath) {
DEBUG(INIT, "Path: " + path + " is valid.")
DEBUG(MODULE_INIT, "Path: " + path + " is valid.")
configPath = path;
hasExistingConfig = true;
} else {
LOG(INIT, "Path: " + path + " does not contain a valid config file.")
LOG(MODULE_INIT, "Path: " + path + " does not contain a valid config file.")
}
}
@ -143,7 +144,7 @@ bool initialiseQv2ray()
if (hasExistingConfig) {
// Use the config path found by the checks above
SetConfigDirPath(configPath);
LOG(INIT, "Using " + QV2RAY_CONFIG_DIR + " as the config path.")
LOG(MODULE_INIT, "Using " + QV2RAY_CONFIG_DIR + " as the config path.")
} else {
//
// Create new config at these dirs, these are default values for each platform.
@ -157,7 +158,7 @@ bool initialiseQv2ray()
// Check if the dirs are write-able
if (mkpathResult && verifyConfigAvaliability(configPath, false)) {
// Found a valid config dir, with write permission, but assume no config is located in it.
LOG(INIT, "Set " + configPath + " as the config path.")
LOG(MODULE_INIT, "Set " + configPath + " as the config path.")
SetConfigDirPath(configPath);
if (QFile::exists(QV2RAY_CONFIG_FILE)) {
@ -167,7 +168,7 @@ bool initialiseQv2ray()
// It usually means that QV2RAY_CONFIG_FILE here is corrupted, in JSON format.
// Otherwise Qv2ray would have loaded this config already instead of notifying to
// create a new config in this folder.
LOG(INIT, "This should not occur: Qv2ray config exists but failed to load.")
LOG(MODULE_INIT, "This should not occur: Qv2ray config exists but failed to load.")
QvMessageBoxWarn(nullptr, QObject::tr("Failed to initialise Qv2ray"),
QObject::tr("Failed to determine the location of config file.") + NEWLINE +
QObject::tr("Qv2ray will now exit.") + NEWLINE +
@ -182,12 +183,12 @@ bool initialiseQv2ray()
//
// Save initial config.
SaveGlobalConfig(conf);
LOG(INIT, "Created initial config file.")
LOG(MODULE_INIT, "Created initial config file.")
} else {
// None of the path above can be used as a dir for storing config.
// Even the last folder failed to pass the check.
LOG(INIT, "FATAL")
LOG(INIT, " ---> CANNOT find a proper place to store Qv2ray config files.")
LOG(MODULE_INIT, "FATAL")
LOG(MODULE_INIT, " ---> CANNOT find a proper place to store Qv2ray config files.")
QString searchPath = configFilePaths.join(NEWLINE);
QvMessageBoxWarn(nullptr, QObject::tr("Cannot Start Qv2ray"),
QObject::tr("Cannot find a place to store config files.") + NEWLINE +
@ -201,7 +202,7 @@ bool initialiseQv2ray()
if (!QDir(QV2RAY_GENERATED_DIR).exists()) {
// The dir used to generate final config file, for V2ray interaction.
QDir().mkdir(QV2RAY_GENERATED_DIR);
LOG(INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
}
return true;
@ -262,7 +263,7 @@ int main(int argc, char *argv[])
// finished: command line parsing
LOG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO)
LOG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
LOG(INIT, "Qv2ray " QV2RAY_VERSION_STRING " running on " + QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture() + NEWLINE)
LOG(MODULE_INIT, "Qv2ray " QV2RAY_VERSION_STRING " running on " + QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture() + NEWLINE)
//
// This line must be called before any other ones, since we are using these values to identify instances.
SingleApplication::setApplicationName("Qv2ray");
@ -285,7 +286,7 @@ int main(int argc, char *argv[])
//
// Do not install en-US as it's the default language.
bool _result_ = _qApp.installTranslator(Qv2rayTranslator.get());
LOG(UI, "Installing a tranlator from OS: " + _lang + " -- " + (_result_ ? "OK" : "Failed"))
LOG(MODULE_UI, "Installing a tranlator from OS: " + _lang + " -- " + (_result_ ? "OK" : "Failed"))
//
LOG("LICENCE", NEWLINE "This program comes with ABSOLUTELY NO WARRANTY." NEWLINE
"This is free software, and you are welcome to redistribute it" NEWLINE
@ -306,7 +307,7 @@ int main(int argc, char *argv[])
"Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE
NEWLINE)
//
LOG(INIT, "Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay()))
LOG(MODULE_INIT, "Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay()))
//
#ifdef QT_DEBUG
cout << "WARNING: ============================== This is a debug build, many features are not stable enough. ==============================" << endl;
@ -316,11 +317,11 @@ int main(int argc, char *argv[])
auto langs = GetFileList(QDir(":/translations"));
if (langs.empty()) {
LOG(INIT, "FAILED to find any translations. THIS IS A BUILD ERROR.")
LOG(MODULE_INIT, "FAILED to find any translations. THIS IS A BUILD ERROR.")
QvMessageBoxWarn(nullptr, QObject::tr("Cannot load languages"), QObject::tr("Qv2ray will continue running, but you cannot change the UI language."));
} else {
for (auto lang : langs) {
LOG(INIT, "Found Translator: " + lang)
LOG(MODULE_INIT, "Found Translator: " + lang)
}
}
@ -353,18 +354,18 @@ int main(int argc, char *argv[])
auto confObject = StructFromJsonString<Qv2rayConfig>(JsonToString(conf));
// Remove system translator, for loading custom translations.
qApp->removeTranslator(Qv2rayTranslator.get());
LOG(INIT, "Removed system translations")
LOG(MODULE_INIT, "Removed system translations")
if (confObject.uiConfig.language.isEmpty()) {
// Prevent empty.
LOG(UI, "Setting default UI language to en-US")
LOG(MODULE_UI, "Setting default UI language to en-US")
confObject.uiConfig.language = "en-US";
}
Qv2rayTranslator = std::move(QvTranslator(confObject.uiConfig.language).pTranslator);
if (qApp->installTranslator(Qv2rayTranslator.get())) {
LOG(INIT, "Successfully installed a translator for " + confObject.uiConfig.language)
LOG(MODULE_INIT, "Successfully installed a translator for " + confObject.uiConfig.language)
} else {
// Do not translate these.....
// If a translator fails to load, pop up a message.
@ -380,11 +381,11 @@ int main(int argc, char *argv[])
// Check OpenSSL version for auto-update and subscriptions
auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString();
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
LOG(NETWORK, "Current OpenSSL version: " + osslCurVersion)
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)
if (!QSslSocket::supportsSsl()) {
LOG(NETWORK, "Required OpenSSL version: " + osslReqVersion)
LOG(NETWORK, "OpenSSL library MISSING, Quitting.")
LOG(MODULE_NETWORK, "Required OpenSSL version: " + osslReqVersion)
LOG(MODULE_NETWORK, "OpenSSL library MISSING, Quitting.")
QvMessageBoxWarn(nullptr, QObject::tr("Dependency Missing"),
QObject::tr("Cannot find openssl libs") + NEWLINE +
QObject::tr("This could be caused by a missing of `openssl` package in your system.") + NEWLINE +
@ -406,7 +407,7 @@ int main(int argc, char *argv[])
LOG(UI, "Using built-in theme.")
if (confObject.uiConfig.useDarkTheme) {
LOG(UI, " --> Using built-in dark theme.")
LOG(MODULE_UI, " --> Using built-in dark theme.")
// From https://forum.qt.io/topic/101391/windows-10-dark-theme/4
_qApp.setStyle("Fusion");
QPalette darkPalette;
@ -442,17 +443,20 @@ int main(int argc, char *argv[])
if (themes.contains(confObject.uiConfig.theme)) {
_qApp.setStyle(confObject.uiConfig.theme);
LOG(INIT + " " + UI, "Setting Qv2ray UI themes: " + confObject.uiConfig.theme)
LOG(MODULE_INIT + " " + MODULE_UI, "Setting Qv2ray UI themes: " + confObject.uiConfig.theme)
}
#endif
// Show MainWindow
MainWindow w;
#ifndef QT_DEBUG
try {
#endif
QObject::connect(&_qApp, &SingleApplication::instanceStarted, [&w]() {
//_qApp.setAttribute(Qt::AA_DontUseNativeMenuBar);
// Initialise Connection Handler
ConnectionHandler = new QvConnectionHandler();
// Show MainWindow
MainWindow w;
QObject::connect(&_qApp, &SingleApplication::instanceStarted, [&]() {
// When a second instance is connected, show the mainwindow.
w.show();
w.raise();
@ -462,7 +466,7 @@ int main(int argc, char *argv[])
// Will not block.
QGuiApplication::setFallbackSessionManagementEnabled(false);
QObject::connect(&_qApp, &QGuiApplication::commitDataRequest, []() {
LOG(INIT, "Quit triggered by session manager.")
LOG(MODULE_INIT, "Quit triggered by session manager.")
});
#ifndef Q_OS_WIN
signal(SIGUSR1, [](int) {
@ -473,12 +477,13 @@ int main(int argc, char *argv[])
});
#endif
auto rcode = _qApp.exec();
LOG(INIT, "Quitting normally")
delete ConnectionHandler;
LOG(MODULE_INIT, "Quitting normally")
return rcode;
#ifndef QT_DEBUG
} catch (...) {
QvMessageBoxWarn(nullptr, "ERROR", "There's something wrong happened and Qv2ray will quit now.");
LOG(INIT, "EXCEPTION THROWN: " __FILE__)
LOG(MODULE_INIT, "EXCEPTION THROWN: " __FILE__)
return -99;
}

View File

@ -27,11 +27,11 @@ InboundEditor::InboundEditor(INBOUND root, QWidget *parent) :
mtSettings = root["settings"].toObject();
} else {
if (!root["protocol"].toString().isEmpty()) {
LOG(UI, "Unsupported inbound type: " + inboundType)
LOG(MODULE_UI, "Unsupported inbound type: " + inboundType)
QvMessageBoxWarn(this, tr("Inbound type not supported"), tr("The inbound type is not supported by Qv2ray (yet). Please use JsonEditor to change the settings") + "\r\n" +
tr("Inbound: ") + inboundType);
} else {
LOG(UI, "Creating new inbound config")
LOG(MODULE_UI, "Creating new inbound config")
root["protocol"] = inboundType = "http";
}
}
@ -201,7 +201,7 @@ void InboundEditor::on_httpRemoveUserBtn_clicked()
if (entry == item->text().trimmed()) {
list.removeAt(i);
httpSettings["accounts"] = list;
LOG(UI, "Removed http inbound user " + entry)
LOG(MODULE_UI, "Removed http inbound user " + entry)
httpAccountListBox->takeItem(httpAccountListBox->currentRow());
}
}
@ -254,7 +254,7 @@ void InboundEditor::on_socksRemoveUserBtn_clicked()
if (entry == item->text().trimmed()) {
list.removeAt(i);
socksSettings["accounts"] = list;
LOG(UI, "Removed http inbound user " + entry)
LOG(MODULE_UI, "Removed http inbound user " + entry)
socksAccountListBox->takeItem(socksAccountListBox->currentRow());
return;
}

View File

@ -12,7 +12,7 @@ JsonEditor::JsonEditor(QJsonObject rootObject, QWidget *parent) :
QString jsonString = JsonToString(rootObject);
if (VerifyJsonString(jsonString).isEmpty()) {
LOG(UI, "Begin loading Json Model")
LOG(MODULE_UI, "Begin loading Json Model")
jsonTree->setModel(&model);
model.loadJson(QJsonDocument(rootObject).toJson());
} else {

View File

@ -113,13 +113,13 @@ OUTBOUND OutboundEditor::GenerateConnectionJson()
settings.insert("vnext", vnext);
} else if (OutboundType == "shadowsocks") {
streaming = QJsonObject();
LOG(CONNECTION, "Shadowsocks outbound does not need StreamSettings.")
LOG(MODULE_CONNECTION, "Shadowsocks outbound does not need StreamSettings.")
QJsonArray servers;
servers.append(GetRootObject(shadowsocks));
settings["servers"] = servers;
} else if (OutboundType == "socks") {
streaming = QJsonObject();
LOG(CONNECTION, "Socks outbound does not need StreamSettings.")
LOG(MODULE_CONNECTION, "Socks outbound does not need StreamSettings.")
QJsonArray servers;
servers.append(GetRootObject(socks));
settings["servers"] = servers;

View File

@ -12,9 +12,9 @@
#include "ui/w_ImportConfig.hpp"
#include "core/CoreUtils.hpp"
#include "ui/nodemodels/RuleNodeModel.hpp"
#include "ui/nodemodels/InboundNodeModel.hpp"
#include "ui/nodemodels/OutboundNodeModel.hpp"
#include "ui/models/RuleNodeModel.hpp"
#include "ui/models/InboundNodeModel.hpp"
#include "ui/models/OutboundNodeModel.hpp"
#include "NodeStyle.hpp"
#include "FlowView.hpp"
@ -29,7 +29,7 @@ static bool isLoading = false;
#define GetFirstNodeData(node, nodeModel, dataModel) (static_cast<dataModel *>(static_cast<nodeModel *>((node).nodeDataModel())->outData(0).get()))
#define CHECKEMPTYRULES if (this->rules.isEmpty()) { \
LOG(UI, "No rules currently, we add one.") \
LOG(MODULE_UI, "No rules currently, we add one.") \
AddNewRule(); \
}
@ -143,7 +143,7 @@ void RouteEditor::onNodeClicked(Node &n)
if (isRule) {
// It's a rule object
currentRuleTag = GetFirstNodeData(n, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
DEBUG(GRAPH, "Selecting rule: " + currentRuleTag)
DEBUG(MODULE_GRAPH, "Selecting rule: " + currentRuleTag)
ShowCurrentRuleDetail();
toolBox->setCurrentIndex(1);
} else if (isOut || isIn) {
@ -171,7 +171,7 @@ void RouteEditor::onNodeClicked(Node &n)
portLabel->setNum(port);
hostLabel->setText(host);
} else {
LOG(GRAPH, "Selected an unknown node, RARE.")
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
}
}
@ -190,7 +190,7 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
// It's a inbound-rule connection
onNodeClicked(*sourceNode);
onNodeClicked(*targetNode);
LOG(GRAPH, "Inbound-rule new connection.")
LOG(MODULE_GRAPH, "Inbound-rule new connection.")
// Get all connected inbounds to this rule node.
// QStringList has an helper to let us remove duplicates, see below.
QStringList _inbounds;
@ -219,10 +219,10 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
CurrentRule.QV2RAY_RULE_USE_BALANCER = false;
// Update balancer settings.
ShowCurrentRuleDetail();
LOG(GRAPH, "Updated outbound: " + CurrentRule.outboundTag)
LOG(MODULE_GRAPH, "Updated outbound: " + CurrentRule.outboundTag)
} else {
// It's an impossible connection
LOG(GRAPH, "Unrecognized connection, RARE.")
LOG(MODULE_GRAPH, "Unrecognized connection, RARE.")
}
}
@ -242,7 +242,7 @@ void RouteEditor::onConnectionDeleted(QtNodes::Connection const &c)
onNodeClicked(*target);
currentRuleTag = GetFirstNodeData(*target, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
auto _inboundTag = GetFirstNodeData(*source, QvInboundNodeModel, InboundNodeData)->GetInbound();
LOG(UI, "Removing inbound: " + _inboundTag + " from rule: " + currentRuleTag)
LOG(MODULE_UI, "Removing inbound: " + _inboundTag + " from rule: " + currentRuleTag)
CurrentRule.inboundTag.removeAll(_inboundTag);
} else if (ruleNodes.values().contains(source) && outboundNodes.values().contains(target)) {
// It's a rule-outbound connection
@ -255,10 +255,10 @@ void RouteEditor::onConnectionDeleted(QtNodes::Connection const &c)
CurrentRule.outboundTag.clear();
}
LOG(GRAPH, "Removing an outbound: " + _outboundTag)
LOG(MODULE_GRAPH, "Removing an outbound: " + _outboundTag)
} else {
// It's an impossible connection
LOG(GRAPH, "Selected an unknown node, RARE.")
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
}
}
@ -288,7 +288,7 @@ CONFIGROOT RouteEditor::OpenEditor()
// Find balancer list
if (!balancers.contains(_rule.balancerTag)) {
LOG(UI, "Cannot find a balancer for tag: " + _rule.balancerTag)
LOG(MODULE_UI, "Cannot find a balancer for tag: " + _rule.balancerTag)
} else {
auto _balancerList = balancers[_rule.balancerTag];
QJsonObject balancerEntry;
@ -331,7 +331,7 @@ CONFIGROOT RouteEditor::OpenEditor()
continue;
if (getTag(x) == defaultOutbound) {
LOG(CONNECTION, "Pushing default outbound to the front.")
LOG(MODULE_CONNECTION, "Pushing default outbound to the front.")
// Put the default outbound to the first.
_outbounds.push_front(x.raw());
} else {
@ -363,13 +363,13 @@ void RouteEditor::ShowCurrentRuleDetail()
LOADINGCHECK
if (currentRuleTag.isEmpty()) {
LOG(UI, "WARNING, trying to access a non-exist rule entry. return.")
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
return;
}
if (!rules.contains(currentRuleTag)) {
QvMessageBoxWarn(this, tr("Show rule details"), tr("A rule cannot be found: ") + currentRuleTag);
LOG(UI, "WARNING, trying to access a non-exist rule entry. return.")
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
return;
}
@ -570,15 +570,15 @@ void RouteEditor::on_enableBalancerCB_stateChanged(int arg1)
balancersWidget->setEnabled(useBalancer);
if (CurrentRule.balancerTag.isEmpty()) {
LOG(UI, "Creating a new balancer tag.")
LOG(MODULE_UI, "Creating a new balancer tag.")
CurrentRule.balancerTag = GenerateRandomString(6);
balancers[CurrentRule.balancerTag] = QStringList();
}
DEBUG(UI, "Balancer: " + CurrentRule.balancerTag)
DEBUG(MODULE_UI, "Balancer: " + CurrentRule.balancerTag)
if (useBalancer) {
LOG(UI, "A rule has been set to use balancer, disconnect it to any outbound.")
LOG(MODULE_UI, "A rule has been set to use balancer, disconnect it to any outbound.")
auto ruleNode = ruleNodes[currentRuleTag];
for (auto conn : Qv2ray::common::Values(nodeScene->connections())) {
@ -723,7 +723,7 @@ void RouteEditor::on_delBtn_clicked()
//currentRuleTag = rules.firstKey();
//ShowCurrentRuleDetail();
} else {
LOG(UI, "Unknown node selected.")
LOG(MODULE_UI, "Unknown node selected.")
QvMessageBoxWarn(this, tr("Error"), tr("Qv2ray entered an unknown state."));
}
}
@ -773,9 +773,9 @@ void RouteEditor::on_editBtn_clicked()
RenameItemTag(RENAME_INBOUND, getTag(_in), getTag(_result));
}
DEBUG(UI, "Removed old tag: " + getTag(_in))
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_in))
inbounds.remove(getTag(_in));
DEBUG(UI, "Adding new tag: " + getTag(_result))
DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result))
inbounds[getTag(_result)] = _result;
}
} else if (isOutbound) {
@ -810,18 +810,18 @@ void RouteEditor::on_editBtn_clicked()
bool isTagChanged = getTag(_out) != getTag(_result);
if (isTagChanged) {
DEBUG(UI, "Outbound tag is changed: " + QString(isTagChanged))
DEBUG(MODULE_UI, "Outbound tag is changed: " + QString(isTagChanged))
RenameItemTag(RENAME_OUTBOUND, getTag(_out), getTag(_result));
DEBUG(UI, "Removed old tag: " + getTag(_out))
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_out))
outbounds.remove(getTag(_out));
}
DEBUG(UI, "Adding new tag: " + getTag(_result))
DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result))
outbounds[getTag(_result)] = _result;
statusLabel->setText(tr("OK"));
}
} else {
LOG(UI, "Cannot apply 'edit' operation to non-inbound and non-outbound")
LOG(MODULE_UI, "Cannot apply 'edit' operation to non-inbound and non-outbound")
}
}
@ -842,13 +842,13 @@ void RouteEditor::on_ruleRenameBtn_clicked()
auto newTag = ruleTagLineEdit->text();
if (newTag.isEmpty()) {
LOG(UI, "Tag is empty, this is ILLEGAL!")
LOG(MODULE_UI, "Tag is empty, this is ILLEGAL!")
QvMessageBoxWarn(this, tr("Renaming a tag"), tr("New tag is empty, please try another."));
} else if (newTag == CurrentRule.QV2RAY_RULE_TAG) {
LOG(UI, "No tag changed, returning.")
LOG(MODULE_UI, "No tag changed, returning.")
QvMessageBoxInfo(this, tr("Renaming a tag"), tr("New tag is the same as the original one."));
} else if (rules.contains(newTag)) {
LOG(UI, "Tag duplicate detected.")
LOG(MODULE_UI, "Tag duplicate detected.")
QvMessageBoxWarn(this, tr("Renaming a tag"), tr("Duplicate rule tag detected, please try another."));
} else {
RenameItemTag(RENAME_RULE, CurrentRule.QV2RAY_RULE_TAG, newTag);

View File

@ -78,7 +78,7 @@ void RouteEditor::AddRule(RuleObject rule)
for (auto inTag : rule.inboundTag) {
if (!inboundNodes.contains(inTag)) {
LOG(UI, "No inbound tag found for rule: " + rule.QV2RAY_RULE_TAG + ", inbound tag: " + inTag)
LOG(MODULE_UI, "No inbound tag found for rule: " + rule.QV2RAY_RULE_TAG + ", inbound tag: " + inTag)
QvMessageBoxWarn(this, tr("No Inbound"), tr("No inbound item found: ") + inTag);
rule.inboundTag.removeAll(inTag);
} else {
@ -90,10 +90,10 @@ void RouteEditor::AddRule(RuleObject rule)
// If not using balancers (use outbound tag)
if (!rule.QV2RAY_RULE_USE_BALANCER) {
if (outboundNodes.contains(rule.outboundTag)) {
DEBUG(GRAPH, "Found outbound tag: " + rule.outboundTag + ", for rule: " + rule.QV2RAY_RULE_TAG)
DEBUG(MODULE_GRAPH, "Found outbound tag: " + rule.outboundTag + ", for rule: " + rule.QV2RAY_RULE_TAG)
nodeScene->createConnection(*outboundNodes[rule.outboundTag], 0, node, 0);
} else {
LOG(GRAPH, "Outbound tag not found: " + rule.outboundTag + ", for: " + rule.QV2RAY_RULE_TAG)
LOG(MODULE_GRAPH, "Outbound tag not found: " + rule.outboundTag + ", for: " + rule.QV2RAY_RULE_TAG)
//QvMessageBoxWarn(this, tr("No outbound tag"), tr("Please connect the rule with an outbound."));
}
}
@ -116,7 +116,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
auto node = static_cast<QvRuleNodeDataModel *>(ruleNodes[originalTag]->nodeDataModel());
if (node == nullptr) {
LOG(GRAPH, "EMPTY NODE WARN")
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
node->setData(newTag);
@ -129,7 +129,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
auto items = ruleListWidget->findItems(originalTag, Qt::MatchExactly);
if (items.isEmpty()) {
LOG(UI, "Cannot find a node: " + originalTag)
LOG(MODULE_UI, "Cannot find a node: " + originalTag)
} else {
items.first()->setText(newTag);
}
@ -138,7 +138,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
currentRuleTag = newTag;
}
} else {
LOG(UI, "There's nothing match " + originalTag + " in the containers.")
LOG(MODULE_UI, "There's nothing match " + originalTag + " in the containers.")
}
break;
@ -155,7 +155,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
auto node = static_cast<QvOutboundNodeModel *>(outboundNodes[newTag]->nodeDataModel());
if (node == nullptr) {
LOG(GRAPH, "EMPTY NODE WARN")
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
node->setData(newTag);
@ -174,7 +174,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
// Resolve default outbound.
ResolveDefaultOutboundTag(originalTag, newTag);
} else {
LOG(UI, "Failed to rename an outbound --> Item not found.")
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
}
break;
@ -191,7 +191,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
auto node = static_cast<QvInboundNodeModel *>(inboundNodes[newTag]->nodeDataModel());
if (node == nullptr) {
LOG(GRAPH, "EMPTY NODE WARN")
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
node->setData(newTag);
@ -210,7 +210,7 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
}
}
} else {
LOG(UI, "Failed to rename an outbound --> Item not found.")
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
}
break;
@ -219,17 +219,17 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
void RouteEditor::ResolveDefaultOutboundTag(QString original, QString newTag)
{
LOG(UI, "Resolving default outbound settings: default=" + defaultOutbound + " original=" + original + " new=" + newTag)
LOG(MODULE_UI, "Resolving default outbound settings: default=" + defaultOutbound + " original=" + original + " new=" + newTag)
auto isDefaultChanged = original == defaultOutbound;
defaultOutboundCombo->clear();
defaultOutboundCombo->addItems(outbounds.keys());
if (!isDefaultChanged) {
LOG(UI, "Default outbound is not changed: retaining: " + defaultOutbound)
LOG(MODULE_UI, "Default outbound is not changed: retaining: " + defaultOutbound)
// Just simply restore the default one.
defaultOutboundCombo->setCurrentText(defaultOutbound);
} else if (newTag.isEmpty()) {
LOG(UI, "Default outbound is removed, using first key from the outbounds as the default one.")
LOG(MODULE_UI, "Default outbound is removed, using first key from the outbounds as the default one.")
// Removed the default one, so set the first one as the default.
if (outbounds.isEmpty()) {
@ -239,7 +239,7 @@ void RouteEditor::ResolveDefaultOutboundTag(QString original, QString newTag)
defaultOutboundCombo->addItem(outbounds.firstKey());
}
} else {
LOG(UI, "Default outbound is renamed, ")
LOG(MODULE_UI, "Default outbound is renamed, ")
defaultOutboundCombo->setCurrentText(newTag);
defaultOutbound = newTag;
}

View File

@ -13,13 +13,13 @@ namespace Qv2ray::ui::messaging
void QvMessageBusObject::on_QvMessageReceived(QvMessage msg)
{
QMetaEnum metaEnum = QMetaEnum::fromType<QvMessage>();
DEBUG(MESSAGING, "Signal recieved: " + QString(metaEnum.valueToKey(msg)));
DEBUG(MODULE_MESSAGING, "Signal recieved: " + QString(metaEnum.valueToKey(msg)));
}
void QvMessageBusObject::EmitGlobalSignal(QvMessage msg)
{
QMetaEnum metaEnum = QMetaEnum::fromType<QvMessage>();
LOG(MESSAGING, "Emitting signal: " + QString(metaEnum.valueToKey(msg)));
LOG(MODULE_MESSAGING, "Emitting signal: " + QString(metaEnum.valueToKey(msg)));
emit QvSendMessage(msg);
}
}

View File

View File

View File

@ -1,4 +1,4 @@
#include "ui/nodemodels/InboundNodeModel.hpp"
#include "ui/models/InboundNodeModel.hpp"
QvInboundNodeModel::QvInboundNodeModel(std::shared_ptr<InboundNodeData> data): NodeDataModel()
{

View File

@ -1,7 +1,7 @@
#pragma once
#include <QtCore/qglobal.h>
#include "ui/nodemodels/NodeModelsBase.hpp"
#include "ui/models/NodeModelsBase.hpp"
class QvInboundNodeModel : public NodeDataModel
{

View File

@ -18,7 +18,7 @@ using QtNodes::NodeValidationState;
using QtNodes::NodeDataType;
using QtNodes::NodeData;
#define GRAPH_NODE_LABEL_FONTSIZE_INCREMENT 3
const int GRAPH_NODE_LABEL_FONTSIZE_INCREMENT = 3;
namespace Qv2ray::ui::nodemodels
{
@ -31,7 +31,7 @@ namespace Qv2ray::ui::nodemodels
public:
InboundNodeData()
{
DEBUG(GRAPH, "DANGER: Initialising a data model without value.")
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
}
InboundNodeData(QString in) : _inboundTag(in) { }
@ -55,7 +55,7 @@ namespace Qv2ray::ui::nodemodels
public:
OutboundNodeData() : _outboundTag()
{
DEBUG(GRAPH, "DANGER: Initialising a data model without value.")
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
}
OutboundNodeData(QString out) : _outboundTag(out) { }
@ -79,7 +79,7 @@ namespace Qv2ray::ui::nodemodels
public:
RuleNodeData() : _ruleTag()
{
DEBUG(GRAPH, "DANGER: Initialising a data model without value.")
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
}
RuleNodeData(QString out) : _ruleTag(out) { }

View File

@ -1,4 +1,4 @@
#include "ui/nodemodels/OutboundNodeModel.hpp"
#include "ui/models/OutboundNodeModel.hpp"
QvOutboundNodeModel::QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data): NodeDataModel()
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <QtCore/qglobal.h>
#include "ui/nodemodels/NodeModelsBase.hpp"
#include "ui/models/NodeModelsBase.hpp"
class QvOutboundNodeModel : public NodeDataModel
{

View File

@ -1,4 +1,4 @@
#include "ui/nodemodels/RuleNodeModel.hpp"
#include "ui/models/RuleNodeModel.hpp"
QvRuleNodeDataModel::QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data): NodeDataModel()
{

View File

@ -1,7 +1,7 @@
#pragma once
#include <QtCore/qglobal.h>
#include "ui/nodemodels/NodeModelsBase.hpp"
#include "ui/models/NodeModelsBase.hpp"
class QvRuleNodeDataModel : public NodeDataModel
{

View File

@ -25,16 +25,18 @@ ConfigExporter::~ConfigExporter()
{
}
ConfigExporter::ConfigExporter(const CONFIGROOT &root, const ConnectionIdentifier &alias, QWidget *parent) : ConfigExporter(parent)
{
message = ConvertConfigToString(root, alias.IdentifierString());
//
QZXingEncoderConfig conf;
conf.border = true;
conf.imageSize = QSize(400, 400);
auto img = qzxing.encodeData(message, conf);
image = img.copy();
}
//ConfigExporter::ConfigExporter(QWidget *parent) : ConfigExporter(parent)
//{
// // WIP
// // /auto &x = connection;
// //message = ConvertConfigToString(root, alias.IdentifierString());
// //
// QZXingEncoderConfig conf;
// conf.border = true;
// conf.imageSize = QSize(400, 400);
// auto img = qzxing.encodeData(message, conf);
// image = img.copy();
//}
void ConfigExporter::OpenExport()
{
@ -73,7 +75,7 @@ void ConfigExporter::on_saveBtn_clicked()
auto filePath = QFileDialog().getSaveFileName(this, tr("Save Image"), "", "Images (*.png)");
auto result = image.save(filePath);
QDesktopServices::openUrl(QUrl::fromUserInput(filePath));
LOG(FILEIO, "Saving an image to: " + filePath + " result: " + (result ? "OK" : "Failed"))
LOG(MODULE_FILEIO, "Saving an image to: " + filePath + " result: " + (result ? "OK" : "Failed"))
}
void ConfigExporter::on_copyImageBtn_clicked()

View File

@ -10,7 +10,7 @@ class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
Q_OBJECT
public:
explicit ConfigExporter(const CONFIGROOT &root, const ConnectionIdentifier &alias, QWidget *parent = nullptr);
explicit ConfigExporter(QWidget *parent = nullptr);
~ConfigExporter();
void OpenExport();
public slots:
@ -25,9 +25,7 @@ class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
void on_copyImageBtn_clicked();
void on_copyVMessBtn_clicked();
private:
explicit ConfigExporter(QWidget *parent);
QZXing qzxing;
QImage image;
QString message;

View File

@ -84,7 +84,7 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
//auto str = QZXing().decodeImage(pix);
if (str.trimmed().isEmpty()) {
LOG(UI, "Cannot decode QR Code from an image, size: h=" + QSTRN(pix.width()) + ", v=" + QSTRN(pix.height()))
LOG(MODULE_UI, "Cannot decode QR Code from an image, size: h=" + QSTRN(pix.width()) + ", v=" + QSTRN(pix.height()))
QvMessageBoxWarn(this, tr("Capture QRCode"), tr("Cannot find a valid QRCode from this region."));
} else {
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
@ -101,19 +101,19 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
switch (tabWidget->currentIndex()) {
case 0: {
// From File...
bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
QString path = fileLineTxt->text();
if (!V2rayKernelInstance::ValidateConfig(path)) {
QvMessageBoxWarn(this, tr("Import config file"), tr("Failed to check the validity of the config file."));
return;
}
aliasPrefix += "_" + QFileInfo(path).fileName();
CONFIGROOT config = ConvertConfigFromFile(path, ImportAsComplex);
connections[aliasPrefix] = config;
break;
//// From File...
//bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
//QString path = fileLineTxt->text();
//
//if (!V2rayKernelInstance::ValidateConfig(path)) {
// QvMessageBoxWarn(this, tr("Import config file"), tr("Failed to check the validity of the config file."));
// return;
//}
//
//aliasPrefix += "_" + QFileInfo(path).fileName();
////CONFIGROOT config = ConvertConfigFromFile(path, ImportAsComplex);
//connections[aliasPrefix] = config;
//break;
}
case 1: {
@ -124,7 +124,7 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
vmessConnectionStringTxt->clear();
errorsList->clear();
//
LOG(IMPORT, QSTRN(linkList.count()) + " string found in vmess box.")
LOG(MODULE_IMPORT, QSTRN(linkList.count()) + " string found in vmess box.")
while (!linkList.isEmpty()) {
aliasPrefix = nameTxt->text();
@ -217,12 +217,12 @@ void ImportConfigWindow::on_editFileBtn_clicked()
auto jsonCheckingError = VerifyJsonString(jsonString);
if (!jsonCheckingError.isEmpty()) {
LOG(FILEIO, "Currupted JSON file detected")
LOG(MODULE_FILEIO, "Currupted JSON file detected")
if (QvMessageBoxAsk(this, tr("Edit file as JSON"), tr("The file you selected has json syntax error. Continue editing may make you lose data. Would you like to continue?") + NEWLINE + jsonCheckingError) != QMessageBox::Yes) {
return;
} else {
LOG(FILEIO, "Continue editing curruped json file, data loss is expected.")
LOG(MODULE_FILEIO, "Continue editing curruped json file, data loss is expected.")
}
}
@ -238,7 +238,7 @@ void ImportConfigWindow::on_editFileBtn_clicked()
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions"));
}
} else {
LOG(FILEIO, "Canceled saving a file.")
LOG(MODULE_FILEIO, "Canceled saving a file.")
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,30 +7,20 @@
#include "ui_w_MainWindow.h"
#include "core/CoreUtils.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include "core/connection/ConnectionIO.hpp"
//#include "core/CoreUtils.hpp"
//#include "core/kernel/KernelInteractions.hpp"
//#include "core/connection/ConnectionIO.hpp"
#include "common/LogHighlighter.hpp"
#include "common/HTTPRequestHelper.hpp"
#include "components/tcping/QvTCPing.hpp"
#include "components/pac/QvPACHandler.hpp"
//#include "components/tcping/QvTCPing.hpp"
//#include "components/pac/QvPACHandler.hpp"
#include "components/speedchart/speedwidget.hpp"
#include "ui/messaging/QvMessageBus.hpp"
enum QvConnectionType {
CONNECTION_REGULAR = 1,
CONNECTION_SUBSCRIPTION = 2
};
//
struct ConnectionObject : ConnectionIdentifier {
QvConnectionType configType;
double latency;
CONFIGROOT config;
};
class MainWindow : public QMainWindow, Ui::MainWindow
{
Q_OBJECT
@ -43,7 +33,7 @@ class MainWindow : public QMainWindow, Ui::MainWindow
void ReConnect() const;
public slots:
QvMessageBusSlotHeader
void onPingFinished(QvTCPingData data);
//void onPingFinished(QvTCPingData data);
void UpdateVCoreLog(const QString &log);
void OnConfigListChanged(bool need_restart);
private slots:
@ -69,15 +59,12 @@ class MainWindow : public QMainWindow, Ui::MainWindow
void on_subsButton_clicked();
//
void ToggleVisibility();
void setMasterLogHBar();
void VersionUpdate(QByteArray &data);
void quit();
public:
static MainWindow *mwInstance;
ConnectionIdentifier CurrentConnectionIdentifier;
V2rayKernelInstance *vinstance;
QString GetCurrentConnectedConfigName();
//QvConnectionObject CurrentConnectionIdentifier;
protected:
void mouseReleaseEvent(QMouseEvent *e) override;
@ -92,20 +79,20 @@ class MainWindow : public QMainWindow, Ui::MainWindow
void on_action_RCM_RenameConnection_triggered();
void on_connectionListWidget_itemSelectionChanged();
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
private:
//
void SetEditWidgetEnable(bool enabled);
void ShowAndSetConnection(ConnectionIdentifier fullIdentifier, bool SetConnection, bool Apply);
CONFIGROOT currentFullConfig;
//void ShowAndSetConnection(QvConnectionObject fullIdentifier, bool SetConnection, bool Apply);
//CONFIGROOT currentFullConfig;
//
// Charts
SpeedWidget *speedChartView;
//
QMenu *connectionListMenu;
/// Key --> ListWidget.item.text
QMap<ConnectionIdentifier, ConnectionObject> connections;
//
ConnectionIdentifier renameOriginalIdentifier;
//QvConnectionObject renameOriginalIdentifier;
bool isRenamingInProgress;
//
// ID for QTimers
@ -117,13 +104,9 @@ class MainWindow : public QMainWindow, Ui::MainWindow
//
QvHttpRequestHelper *requestHelper;
QSystemTrayIcon hTray;
PACServer pacServer;
QvTCPingModel tcpingHelper;
//PACServer pacServer;
//QvTCPingModel tcpingHelper;
SyntaxHighlighter *vCoreLogHighlighter;
SyntaxHighlighter *qvAppLogHighlighter;
//
QList<QTextBrowser *> logTextBrowsers;
int currentLogBrowserId = 0;
QTreeWidgetItem *CurrentSelectedItemPtr;
//
// Actions in the system tray menu
@ -144,14 +127,8 @@ class MainWindow : public QMainWindow, Ui::MainWindow
// ----------------------------------- Extra Headers For w_MainWindow_extra.cpp Handling V2ray Connectivities.
bool systemProxyEnabled;
void MWFindAndStartAutoConfig();
bool MWtryStartConnection();
void MWStopConnection();
void MWTryPingConnection(const ConnectionIdentifier &alias);
tuple<QString, int, QString> MWGetConnectionInfo(const ConnectionIdentifier &alias);
void MWSetSystemProxy();
void MWClearSystemProxy(bool);
void CheckSubscriptionsUpdate();
//
QTreeWidgetItem *FindItemByIdentifier(ConnectionIdentifier identifier);
};

File diff suppressed because it is too large Load Diff

View File

@ -5,65 +5,65 @@
#include "components/proxy/QvProxyConfigurator.hpp"
#include "core/connection/Generation.hpp"
QTreeWidgetItem *MainWindow::FindItemByIdentifier(ConnectionIdentifier identifier)
{
// First filter out all items with our config name.
auto items = connectionListWidget->findItems(identifier.connectionName, Qt::MatchExactly | Qt::MatchRecursive);
for (auto item : items) {
// This connectable prevents the an item with (which is the parent node of a subscription, having the same
// -- name as our current connected name)
if (!IsConnectableItem(item)) {
LOG(UI, "Invalid Item found: " + item->text(0))
continue;
}
auto thisIdentifier = ItemConnectionIdentifier(item);
DEBUG(UI, "Item Identifier: " + thisIdentifier.IdentifierString())
if (identifier == thisIdentifier) {
return item;
}
}
LOG(UI, "Warning: Failed to find an item named: " + identifier.IdentifierString())
return nullptr;
}
//QTreeWidgetItem *MainWindow::FindItemByIdentifier(QvConnectionObject identifier)
//{
// //// First filter out all items with our config name.
// //auto items = connectionListWidget->findItems(identifier.connectionName, Qt::MatchExactly | Qt::MatchRecursive);
// //
// //for (auto item : items) {
// // // This connectable prevents the an item with (which is the parent node of a subscription, having the same
// // // -- name as our current connected name)
// // if (!IsConnectableItem(item)) {
// // LOG(UI, "Invalid Item found: " + item->text(0))
// // continue;
// // }
// //
// // auto thisIdentifier = ItemConnectionIdentifier(item);
// // DEBUG(UI, "Item Identifier: " + thisIdentifier.IdentifierString())
// //
// // if (identifier == thisIdentifier) {
// // return item;
// // }
// //}
// //
// //LOG(UI, "Warning: Failed to find an item named: " + identifier.IdentifierString())
// return nullptr;
//}
void MainWindow::MWFindAndStartAutoConfig()
{
if (!GlobalConfig.autoStartConfig.connectionName.isEmpty()) {
// User has auto start configured, we try to find that connection item.
auto name = GlobalConfig.autoStartConfig.subscriptionName.isEmpty()
? GlobalConfig.autoStartConfig.connectionName
: GlobalConfig.autoStartConfig.connectionName + " (" + tr("Subscription:") + " " + GlobalConfig.autoStartConfig.subscriptionName + ")";
//
LOG(UI, "Found auto start config: " + name)
auto item = FindItemByIdentifier(GlobalConfig.autoStartConfig);
if (item != nullptr) {
// We found the item required and start it.
connectionListWidget->setCurrentItem(item);
on_connectionListWidget_currentItemChanged(item, nullptr);
connectionListWidget->scrollToItem(item);
tray_RootMenu->actions()[0]->setText(tr("Show"));
on_startButton_clicked();
} else {
QvMessageBoxWarn(this, tr("Autostarting a config"), tr("Could not find a specified config named: ") + NEWLINE +
name + NEWLINE + NEWLINE +
tr("Please reset the settings in Preference Window"));
}
} else if (connectionListWidget->topLevelItemCount() > 0) {
// Make the first one our default selected item.
connectionListWidget->setCurrentItem(connectionListWidget->topLevelItem(0));
ShowAndSetConnection(ItemConnectionIdentifier(connectionListWidget->topLevelItem(0)), true, false);
}
//if (!GlobalConfig.autoStartConfig.connectionName.isEmpty()) {
// // User has auto start configured, we try to find that connection item.
// auto name = GlobalConfig.autoStartConfig.subscriptionName.isEmpty()
// ? GlobalConfig.autoStartConfig.connectionName
// : GlobalConfig.autoStartConfig.connectionName + " (" + tr("Subscription:") + " " + GlobalConfig.autoStartConfig.subscriptionName + ")";
// //
// LOG(UI, "Found auto start config: " + name)
// auto item = FindItemByIdentifier(GlobalConfig.autoStartConfig);
//
// if (item != nullptr) {
// // We found the item required and start it.
// connectionListWidget->setCurrentItem(item);
// on_connectionListWidget_currentItemChanged(item, nullptr);
// connectionListWidget->scrollToItem(item);
// tray_RootMenu->actions()[0]->setText(tr("Show"));
// on_startButton_clicked();
// } else {
// QvMessageBoxWarn(this, tr("Autostarting a config"), tr("Could not find a specified config named: ") + NEWLINE +
// name + NEWLINE + NEWLINE +
// tr("Please reset the settings in Preference Window"));
// }
//} else if (connectionListWidget->topLevelItemCount() > 0) {
// // Make the first one our default selected item.
// connectionListWidget->setCurrentItem(connectionListWidget->topLevelItem(0));
// ShowAndSetConnection(ItemConnectionIdentifier(connectionListWidget->topLevelItem(0)), true, false);
//}
}
void MainWindow::MWClearSystemProxy(bool showMessage)
{
ClearSystemProxy();
LOG(UI, "Clearing System Proxy")
LOG(MODULE_UI, "Clearing System Proxy")
systemProxyEnabled = false;
if (showMessage) {
@ -79,11 +79,12 @@ void MainWindow::MWSetSystemProxy()
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
//
// Set system proxy if necessary
bool isComplex = IsComplexConfig(connections[CurrentConnectionIdentifier].config);
//bool isComplex = IsComplexConfig(connections[CurrentConnectionIdentifier].config);
bool isComplex = true;
if (!isComplex) {
// Is simple config and we will try to set system proxy.
LOG(UI, "Preparing to set system proxy")
LOG(MODULE_UI, "Preparing to set system proxy")
//
QString proxyAddress;
bool canSetSystemProxy = true;
@ -91,13 +92,13 @@ void MainWindow::MWSetSystemProxy()
if (usePAC) {
if ((httpEnabled && !pacUseSocks) || (socksEnabled && pacUseSocks)) {
// If we use PAC and socks/http are properly configured for PAC
LOG(PROXY, "System proxy uses PAC")
LOG(MODULE_PROXY, "System proxy uses PAC")
proxyAddress = "http://" + GlobalConfig.inboundConfig.listenip + ":" + QSTRN(GlobalConfig.inboundConfig.pacConfig.port) + "/pac";
} else {
// Not properly configured
LOG(PROXY, "Failed to process pac due to following reasons:")
LOG(PROXY, " --> PAC is configured to use socks but socks is not enabled.")
LOG(PROXY, " --> PAC is configuted to use http but http is not enabled.")
LOG(MODULE_PROXY, "Failed to process pac due to following reasons:")
LOG(MODULE_PROXY, " --> PAC is configured to use socks but socks is not enabled.")
LOG(MODULE_PROXY, " --> PAC is configuted to use http but http is not enabled.")
QvMessageBoxWarn(this, tr("PAC Processing Failed"), tr("HTTP or SOCKS inbound is not properly configured for PAC") +
NEWLINE + tr("Qv2ray will continue, but will not set system proxy."));
canSetSystemProxy = false;
@ -106,18 +107,18 @@ void MainWindow::MWSetSystemProxy()
// Not using PAC
if (httpEnabled || socksEnabled) {
// Not use PAC, System proxy should use HTTP or SOCKS
LOG(PROXY, "Setting up system proxy.")
LOG(MODULE_PROXY, "Setting up system proxy.")
// A 'proxy host' should be a host WITHOUT `http://` uri scheme
proxyAddress = "localhost";
} else {
LOG(PROXY, "Neither of HTTP nor SOCKS is enabled, cannot set system proxy.")
LOG(MODULE_PROXY, "Neither of HTTP nor SOCKS is enabled, cannot set system proxy.")
QvMessageBoxWarn(this, tr("Cannot set system proxy"), tr("Both HTTP and SOCKS inbounds are not enabled"));
canSetSystemProxy = false;
}
}
if (canSetSystemProxy) {
LOG(UI, "Setting system proxy for simple config.")
LOG(MODULE_UI, "Setting system proxy for simple config.")
auto httpPort = GlobalConfig.inboundConfig.useHTTP ? GlobalConfig.inboundConfig.http_port : 0;
auto socksPort = GlobalConfig.inboundConfig.useSocks ? GlobalConfig.inboundConfig.socks_port : 0;
//
@ -131,96 +132,40 @@ void MainWindow::MWSetSystemProxy()
}
}
bool MainWindow::MWtryStartConnection()
{
auto connectionRoot = connections[CurrentConnectionIdentifier].config;
currentFullConfig = GenerateRuntimeConfig(connectionRoot);
bool startFlag = this->vinstance->StartConnection(currentFullConfig);
if (startFlag) {
bool usePAC = GlobalConfig.inboundConfig.pacConfig.enablePAC;
bool pacUseSocks = GlobalConfig.inboundConfig.pacConfig.useSocksProxy;
bool httpEnabled = GlobalConfig.inboundConfig.useHTTP;
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
if (usePAC) {
bool canStartPAC = true;
QString pacProxyString; // Something like this --> SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT; http://proxy:8080
auto pacIP = GlobalConfig.inboundConfig.pacConfig.localIP;
if (pacIP.isEmpty()) {
LOG(PROXY, "PAC Local IP is empty, default to 127.0.0.1")
pacIP = "127.0.0.1";
}
if (pacUseSocks) {
if (socksEnabled) {
pacProxyString = "SOCKS5 " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.socks_port);
} else {
LOG(UI, "PAC is using SOCKS, but it is not enabled")
QvMessageBoxWarn(this, tr("Configuring PAC"), tr("Could not start PAC server as it is configured to use SOCKS, but it is not enabled"));
canStartPAC = false;
}
} else {
if (httpEnabled) {
pacProxyString = "PROXY " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.http_port);
} else {
LOG(UI, "PAC is using HTTP, but it is not enabled")
QvMessageBoxWarn(this, tr("Configuring PAC"), tr("Could not start PAC server as it is configured to use HTTP, but it is not enabled"));
canStartPAC = false;
}
}
if (canStartPAC) {
pacServer.SetProxyString(pacProxyString);
pacServer.StartListen();
} else {
LOG(PROXY, "Not starting PAC due to previous error.")
}
}
if (GlobalConfig.inboundConfig.setSystemProxy) {
MWSetSystemProxy();
}
}
return startFlag;
}
void MainWindow::MWStopConnection()
{
if (systemProxyEnabled) {
MWClearSystemProxy(false);
}
this->vinstance->StopConnection();
QFile(QV2RAY_GENERATED_FILE_PATH).remove();
if (GlobalConfig.inboundConfig.pacConfig.enablePAC) {
pacServer.StopServer();
LOG(UI, "Stopping PAC server")
}
//if (systemProxyEnabled) {
// MWClearSystemProxy(false);
//}
//
//this->vinstance->StopConnection();
//QFile(QV2RAY_GENERATED_FILE_PATH).remove();
//
//if (GlobalConfig.inboundConfig.pacConfig.enablePAC) {
// pacServer.StopServer();
// LOG(UI, "Stopping PAC server")
//}
}
void MainWindow::MWTryPingConnection(const ConnectionIdentifier &alias)
{
try {
auto info = MWGetConnectionInfo(alias);
QString host = get<0>(info);
int port = get<1>(info);
tcpingHelper.StartPing(alias, host, port);
} catch (...) {
QvMessageBoxWarn(this, tr("Latency Test"), tr("Failed to test latency for this connection."));
}
}
tuple<QString, int, QString> MainWindow::MWGetConnectionInfo(const ConnectionIdentifier &alias)
{
if (!connections.contains(alias))
return make_tuple(tr("N/A"), 0, tr("N/A"));
return GetConnectionInfo(connections[alias].config);
}
//void MainWindow::MWTryPingConnection(const QvConnectionObject &alias)
//{
// //try {
// // auto info = MWGetConnectionInfo(alias);
// // QString host = get<0>(info);
// // int port = get<1>(info);
// // tcpingHelper.StartPing(alias, host, port);
// //} catch (...) {
// // QvMessageBoxWarn(this, tr("Latency Test"), tr("Failed to test latency for this connection."));
// //}
//}
//
//tuple<QString, int, QString> MainWindow::MWGetConnectionInfo(const QvConnectionObject &alias)
//{
// //if (!connections.contains(alias))
// // return make_tuple(tr("N/A"), 0, tr("N/A"));
// //
// //return GetConnectionInfo(connections[alias].config);
//}
void MainWindow::CheckSubscriptionsUpdate()
{
@ -232,13 +177,13 @@ void MainWindow::CheckSubscriptionsUpdate()
//
auto lastRenewDate = QDateTime::fromTime_t(subs.lastUpdated);
auto renewTime = lastRenewDate.addSecs(subs.updateInterval * 86400);
LOG(SUBSCRIPTION, "Subscription \"" + key + "\": " + NEWLINE +
LOG(MODULE_SUBSCRIPTION, "Subscription \"" + key + "\": " + NEWLINE +
" --> Last renewal time: " + lastRenewDate.toString() + NEWLINE +
" --> Renew interval: " + QSTRN(subs.updateInterval) + NEWLINE +
" --> Ideal renew time: " + renewTime.toString())
if (renewTime <= QDateTime::currentDateTime()) {
LOG(SUBSCRIPTION, "Subscription: " + key + " needs to be updated.")
LOG(MODULE_SUBSCRIPTION, "Subscription: " + key + " needs to be updated.")
updateList.append(key);
}
}

View File

@ -147,24 +147,26 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
CurrentBarPageId = 0;
//
// Empty for global config.
auto autoSub = CurrentConfig.autoStartConfig.subscriptionName;
auto autoCon = CurrentConfig.autoStartConfig.connectionName;
autoStartConnCombo->addItem("");
//auto autoSub = CurrentConfig.autoStartConfig.subscriptionName;
//auto autoCon = CurrentConfig.autoStartConfig.connectionName;
//autoStartConnCombo->addItem("");
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
for (auto item : CurrentConfig.subscriptions.keys()) {
autoStartSubsCombo->addItem(item);
}
autoStartSubsCombo->setCurrentText(autoSub);
if (CurrentConfig.autoStartConfig.subscriptionName.isEmpty()) {
autoStartConnCombo->addItems(CurrentConfig.configs);
} else {
auto list = GetSubscriptionConnection(autoSub);
autoStartConnCombo->addItems(list.keys());
}
autoStartConnCombo->setCurrentText(autoCon);
// TODO: Now use grouping, subscriptions are the special type of group
//autoStartConnCombo->setCurrentText(autoCon);for (auto item : CurrentConfig.subscriptions.keys()) {
// autoStartSubsCombo->addItem(item);
//}
//
//autoStartSubsCombo->setCurrentText(autoSub);
//
//if (CurrentConfig.autoStartConfig.subscriptionName.isEmpty()) {
// autoStartConnCombo->addItems(CurrentConfig.configs);
//} else {
// auto list = GetSubscriptionConnection(autoSub);
// autoStartConnCombo->addItems(list.keys());
//}
//
//
// FP Settings
if (CurrentConfig.connectionConfig.forwardProxyConfig.type.trimmed().isEmpty()) {
@ -242,7 +244,7 @@ void PreferencesWindow::on_buttonBox_accepted()
// Install translator
if (!qApp->installTranslator(Qv2rayTranslator.get())) {
LOG(UI, "Failed to translate UI to: " + CurrentConfig.uiConfig.language)
LOG(MODULE_UI, "Failed to translate UI to: " + CurrentConfig.uiConfig.language)
} else {
messageBus.EmitGlobalSignal(QvMessage::RETRANSLATE);
QApplication::processEvents();
@ -419,48 +421,48 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
tr("If anything goes wrong after enabling this, please check issue #57 or the link below:") + NEWLINE +
" https://github.com/Qv2ray/Qv2ray/wiki/FAQ ") != QMessageBox::Yes) {
tProxyCheckBox->setChecked(false);
LOG(UI, "Canceled enabling tProxy feature.")
LOG(MODULE_UI, "Canceled enabling tProxy feature.")
} else {
LOG(VCORE, "ENABLING tProxy Support")
LOG(FILEIO, " --> Origin V2ray core file is at: " + CurrentConfig.v2CorePath)
LOG(MODULE_VCORE, "ENABLING tProxy Support")
LOG(MODULE_FILEIO, " --> Origin V2ray core file is at: " + CurrentConfig.v2CorePath)
auto v2ctlPath = QFileInfo(CurrentConfig.v2CorePath).absolutePath() + "/v2ctl";
auto newPath = QFileInfo(QV2RAY_TPROXY_VCORE_PATH).absolutePath();
QString mkPathResult = QDir().mkpath(newPath) ? "OK" : "FAILED";
LOG(FILEIO, " --> mkPath result: " + mkPathResult)
LOG(MODULE_FILEIO, " --> mkPath result: " + mkPathResult)
//
LOG(FILEIO, " --> Origin v2ctl file is at: " + v2ctlPath)
LOG(FILEIO, " --> New V2ray files will be placed in: " + newPath)
LOG(MODULE_FILEIO, " --> Origin v2ctl file is at: " + v2ctlPath)
LOG(MODULE_FILEIO, " --> New V2ray files will be placed in: " + newPath)
//
LOG(FILEIO, " --> Copying files....")
LOG(MODULE_FILEIO, " --> Copying files....")
if (QFileInfo(CurrentConfig.v2CorePath).absoluteFilePath() != QFileInfo(QV2RAY_TPROXY_VCORE_PATH).absoluteFilePath()) {
// Only trying to remove file when they are not in the default dir.
// (In other words...) Keep using the current files. <Because we don't know where else we can copy the file from...>
//
if (QFile(QV2RAY_TPROXY_VCORE_PATH).exists()) {
LOG(FILEIO, QString(QV2RAY_TPROXY_VCORE_PATH) + ": File already exists.")
LOG(FILEIO, QString(QV2RAY_TPROXY_VCORE_PATH) + ": Deleting file.")
LOG(MODULE_FILEIO, QString(QV2RAY_TPROXY_VCORE_PATH) + ": File already exists.")
LOG(MODULE_FILEIO, QString(QV2RAY_TPROXY_VCORE_PATH) + ": Deleting file.")
QFile(QV2RAY_TPROXY_VCORE_PATH).remove();
}
if (QFile(QV2RAY_TPROXY_VCTL_PATH).exists()) {
LOG(FILEIO, QV2RAY_TPROXY_VCTL_PATH + ": File already exists.")
LOG(FILEIO, QV2RAY_TPROXY_VCTL_PATH + ": Deleting file.")
LOG(MODULE_FILEIO, QV2RAY_TPROXY_VCTL_PATH + ": File already exists.")
LOG(MODULE_FILEIO, QV2RAY_TPROXY_VCTL_PATH + ": Deleting file.")
QFile(QV2RAY_TPROXY_VCTL_PATH).remove();
}
QString vCoreresult = QFile(CurrentConfig.v2CorePath).copy(QV2RAY_TPROXY_VCORE_PATH) ? "OK" : "FAILED";
LOG(FILEIO, " --> V2ray Core: " + vCoreresult)
LOG(MODULE_FILEIO, " --> V2ray Core: " + vCoreresult)
//
QString vCtlresult = QFile(v2ctlPath).copy(QV2RAY_TPROXY_VCTL_PATH) ? "OK" : "FAILED";
LOG(FILEIO, " --> V2ray Ctl: " + vCtlresult)
LOG(MODULE_FILEIO, " --> V2ray Ctl: " + vCtlresult)
//
if (vCoreresult == "OK" && vCtlresult == "OK") {
LOG(VCORE, " --> Done copying files.")
LOG(MODULE_VCORE, " --> Done copying files.")
on_vCorePathTxt_textEdited(QV2RAY_TPROXY_VCORE_PATH);
} else {
LOG(VCORE, "FAILED to copy V2ray files. Aborting.")
LOG(MODULE_VCORE, "FAILED to copy V2ray files. Aborting.")
QvMessageBoxWarn(this, tr("Enable tProxy Support"),
tr("Qv2ray cannot copy one or both V2ray files from: ") + NEWLINE + NEWLINE +
CurrentConfig.v2CorePath + NEWLINE + v2ctlPath + NEWLINE + NEWLINE +
@ -468,15 +470,15 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
return;
}
} else {
LOG(VCORE, "Skipped removing files since the current V2ray core is in the default path.")
LOG(VCORE, " --> Actually because we don't know where else to obtain the files.")
LOG(MODULE_VCORE, "Skipped removing files since the current V2ray core is in the default path.")
LOG(MODULE_VCORE, " --> Actually because we don't know where else to obtain the files.")
}
LOG(UI, "Calling pkexec and setcap...")
LOG(MODULE_UI, "Calling pkexec and setcap...")
int ret = QProcess::execute("pkexec setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip " + CurrentConfig.v2CorePath);
if (ret != 0) {
LOG(UI, "WARN: setcap exits with code: " + QSTRN(ret))
LOG(MODULE_UI, "WARN: setcap exits with code: " + QSTRN(ret))
QvMessageBoxWarn(this, tr("Preferences"), tr("Failed to setcap onto V2ray executable. You may need to run `setcap` manually."));
}
@ -487,7 +489,7 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
int ret = QProcess::execute("pkexec setcap -r " + CurrentConfig.v2CorePath);
if (ret != 0) {
LOG(UI, "WARN: setcap exits with code: " + QSTRN(ret))
LOG(MODULE_UI, "WARN: setcap exits with code: " + QSTRN(ret))
QvMessageBoxWarn(this, tr("Preferences"), tr("Failed to setcap onto V2ray executable. You may need to run `setcap` manually."));
}
@ -564,7 +566,7 @@ void PreferencesWindow::on_nsBarPageAddBTN_clicked()
CurrentBarLineId = 0;
nsBarPagesList->addItem(QSTRN(CurrentBarPageId));
ShowLineParameters(CurrentBarLine);
LOG(UI, "Adding new page Id: " + QSTRN(CurrentBarPageId))
LOG(MODULE_UI, "Adding new page Id: " + QSTRN(CurrentBarPageId))
nsBarPageDelBTN->setEnabled(true);
nsBarLineAddBTN->setEnabled(true);
nsBarLineDelBTN->setEnabled(true);
@ -607,7 +609,7 @@ void PreferencesWindow::on_nsBarLineAddBTN_clicked()
nsBarLinesList->addItem(QSTRN(CurrentBarLineId));
ShowLineParameters(CurrentBarLine);
nsBarLineDelBTN->setEnabled(true);
LOG(UI, "Adding new line Id: " + QSTRN(CurrentBarLineId))
LOG(MODULE_UI, "Adding new line Id: " + QSTRN(CurrentBarLineId))
nsBarLinesList->setCurrentRow(static_cast<int>(CurrentBarPage.Lines.size() - 1));
}
@ -837,7 +839,7 @@ void PreferencesWindow::on_pacGoBtn_clicked()
pacGoBtn->setEnabled(false);
gfwListCB->setEnabled(false);
QvHttpRequestHelper request;
LOG(PROXY, "Downloading GFWList file.")
LOG(MODULE_PROXY, "Downloading GFWList file.")
bool withProxy = getGFWListWithProxyCB->isChecked();
switch (gfwListCB->currentIndex()) {
@ -883,7 +885,7 @@ void PreferencesWindow::on_pacGoBtn_clicked()
break;
}
LOG(NETWORK, "Fetched: " + gfwLocation)
LOG(MODULE_NETWORK, "Fetched: " + gfwLocation)
QvMessageBoxInfo(this, tr("Download GFWList"), tr("Successfully downloaded GFWList."));
pacGoBtn->setEnabled(true);
gfwListCB->setEnabled(true);
@ -936,22 +938,24 @@ void PreferencesWindow::on_pacProxyTxt_textEdited(const QString &arg1)
void PreferencesWindow::on_autoStartSubsCombo_currentIndexChanged(const QString &arg1)
{
LOADINGCHECK
CurrentConfig.autoStartConfig.subscriptionName = arg1;
autoStartConnCombo->clear();
if (arg1.isEmpty()) {
autoStartConnCombo->addItem("");
autoStartConnCombo->addItems(CurrentConfig.configs);
} else {
auto list = GetSubscriptionConnection(arg1);
autoStartConnCombo->addItems(list.keys());
}
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
//CurrentConfig.autoStartConfig.subscriptionName = arg1;
//autoStartConnCombo->clear();
//
//if (arg1.isEmpty()) {
// autoStartConnCombo->addItem("");
// autoStartConnCombo->addItems(CurrentConfig.configs);
//} else {
// auto list = GetSubscriptionConnection(arg1);
// autoStartConnCombo->addItems(list.keys());
//}
}
void PreferencesWindow::on_autoStartConnCombo_currentIndexChanged(const QString &arg1)
{
LOADINGCHECK
CurrentConfig.autoStartConfig.connectionName = arg1;
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
//CurrentConfig.autoStartConfig.connectionName = arg1;
}
void PreferencesWindow::on_startWithLoginCB_stateChanged(int arg1)

View File

@ -29,7 +29,7 @@ ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubber
QImage ScreenShotWindow::DoScreenShot()
{
LOG(IMPORT, "We currently only support the current screen.")
LOG(MODULE_IMPORT, "We currently only support the current screen.")
// The msleep is the only solution which prevent capturing our windows again.
// It works on KDE, https://www.qtcentre.org/threads/55708-Get-Desktop-Screenshot-Without-Application-Window-Being-Shown?p=248993#post248993
QThread::msleep(100);

View File

@ -34,7 +34,7 @@ QPair<QString, CONFIGROOT> SubscribeEditor::GetSelectedConfig()
return currentSelectedConfig;
}
void SubscribeEditor::LoadSubscriptionList(QMap<QString, Qv2raySubscriptionConfig> list)
void SubscribeEditor::LoadSubscriptionList(QMap<QString, QvSubscriptionObject> list)
{
subscriptionList->clear();
@ -69,7 +69,7 @@ void SubscribeEditor::on_updateButton_clicked()
if (currentSubName != newName) {
// Rename needed.
LOG(SUBSCRIPTION, "Renaming a subscription, from " + currentSubName + " to: " + newName)
LOG(MODULE_SUBSCRIPTION, "Renaming a subscription, from " + currentSubName + " to: " + newName)
bool canGo = true;
if (newName.isEmpty() || !IsValidFileName(newName)) {
@ -87,24 +87,23 @@ void SubscribeEditor::on_updateButton_clicked()
return;
}
bool result = RenameSubscription(currentSubName, newName);
if (!result) {
QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("Failed to rename a subscription, this is an unknown error."));
return;
}
////bool result = RenameSubscription(currentSubName, newName);
//
//if (!result) {
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("Failed to rename a subscription, this is an unknown error."));
// return;
//}
subscriptions[newName] = subscriptions[currentSubName];
subscriptions.remove(currentSubName);
subNameTxt->setText(newName);
//
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
// Update auto-start config if possible
auto ASsetting = GlobalConfig.autoStartConfig.subscriptionName;
if (ASsetting == currentSubName) {
GlobalConfig.autoStartConfig.subscriptionName = newName;
}
//auto ASsetting = GlobalConfig.autoStartConfig.subscriptionName;
//
//if (ASsetting == currentSubName) {
// GlobalConfig.autoStartConfig.subscriptionName = newName;
//}
SaveGlobalConfig(GlobalConfig);
// This will set the name to the new name.
LoadSubscriptionList(subscriptions);
@ -114,7 +113,7 @@ void SubscribeEditor::on_updateButton_clicked()
subscriptions[currentSubName].updateInterval = newUpdateInterval;
if (subscriptions[currentSubName].address != newAddress) {
LOG(SUBSCRIPTION, "Setting new address, from " + subscriptions[currentSubName].address + " to: " + newAddress)
LOG(MODULE_SUBSCRIPTION, "Setting new address, from " + subscriptions[currentSubName].address + " to: " + newAddress)
subscriptions[currentSubName].address = newAddress;
}
@ -127,92 +126,91 @@ void SubscribeEditor::on_updateButton_clicked()
void SubscribeEditor::StartUpdateSubscription(const QString &subscriptionName)
{
this->setEnabled(false);
auto data = helper.syncget(subscriptions[subscriptionName].address, withProxyCB->isChecked());
auto content = DecodeSubscriptionString(data).trimmed();
if (!content.isEmpty()) {
connectionsList->clear();
auto vmessList = SplitLines(content);
QDir(QV2RAY_SUBSCRIPTION_DIR + subscriptionName).removeRecursively();
QDir().mkpath(QV2RAY_SUBSCRIPTION_DIR + subscriptionName);
for (auto vmess : vmessList) {
QString errMessage;
QString _alias;
auto config = ConvertConfigFromString(vmess.trimmed(), &_alias, &errMessage);
if (!errMessage.isEmpty()) {
LOG(SUBSCRIPTION, "Processing a subscription with following error: " + errMessage)
} else {
SaveSubscriptionConfig(config, subscriptionName, &_alias);
connectionsList->addItem(_alias);
}
}
subscriptions[subscriptionName].lastUpdated = system_clock::to_time_t(system_clock::now());
lastUpdatedLabel->setText(timeToString(subscriptions[subscriptionName].lastUpdated));
isUpdateInProgress = false;
} else {
LOG(NETWORK, "We have received an empty string from the URL.")
QvMessageBoxWarn(this, tr("Updating subscriptions"), tr("Failed to process the result from the upstream, please check your Url."));
}
this->setEnabled(true);
//this->setEnabled(false);
//auto data = helper.syncget(subscriptions[subscriptionName].address, withProxyCB->isChecked());
//auto content = DecodeSubscriptionString(data).trimmed();
//
//if (!content.isEmpty()) {
// connectionsList->clear();
// auto vmessList = SplitLines(content);
// QDir(QV2RAY_SUBSCRIPTION_DIR + subscriptionName).removeRecursively();
// QDir().mkpath(QV2RAY_SUBSCRIPTION_DIR + subscriptionName);
//
// for (auto vmess : vmessList) {
// QString errMessage;
// QString _alias;
// auto config = ConvertConfigFromString(vmess.trimmed(), &_alias, &errMessage);
//
// if (!errMessage.isEmpty()) {
// LOG(MODULE_SUBSCRIPTION, "Processing a subscription with following error: " + errMessage)
// } else {
// //SaveSubscriptionConfig(config, subscriptionName, &_alias);
// connectionsList->addItem(_alias);
// }
// }
//
// subscriptions[subscriptionName].lastUpdated = system_clock::to_time_t(system_clock::now());
// lastUpdatedLabel->setText(timeToString(subscriptions[subscriptionName].lastUpdated));
// isUpdateInProgress = false;
//} else {
// LOG(MODULE_NETWORK, "We have received an empty string from the URL.")
// QvMessageBoxWarn(this, tr("Updating subscriptions"), tr("Failed to process the result from the upstream, please check your Url."));
//}
//
//this->setEnabled(true);
}
void SubscribeEditor::on_removeSubsButton_clicked()
{
if (subscriptionList->currentRow() < 0)
return;
auto name = subscriptionList->currentItem()->text();
subscriptionList->takeItem(subscriptionList->currentRow());
subscriptions.remove(name);
if (!name.isEmpty()) {
QDir(QV2RAY_SUBSCRIPTION_DIR + name).removeRecursively();
}
// If removed a whole subscription...
if (GlobalConfig.autoStartConfig.subscriptionName == name) {
GlobalConfig.autoStartConfig = ConnectionIdentifier();
SaveGlobalConfig(GlobalConfig);
}
groupBox_2->setEnabled(subscriptionList->count() > 0);
SaveConfig();
//if (subscriptionList->currentRow() < 0)
// return;
//
//auto name = subscriptionList->currentItem()->text();
//subscriptionList->takeItem(subscriptionList->currentRow());
//subscriptions.remove(name);
//
//if (!name.isEmpty()) {
// QDir(QV2RAY_SUBSCRIPTION_DIR + name).removeRecursively();
//}
//
////// If removed a whole subscription...
////if (GlobalConfig.autoStartConfig.subscriptionName == name) {
//// GlobalConfig.autoStartConfig = QvConnectionObject();
//// SaveGlobalConfig(GlobalConfig);
////}
//groupBox_2->setEnabled(subscriptionList->count() > 0);
//SaveConfig();
}
void SubscribeEditor::on_subscriptionList_currentRowChanged(int currentRow)
{
if (subscriptionList->count() == 0) {
return;
}
if (currentRow < 0 && subscriptionList->count() > 0) {
subscriptionList->setCurrentRow(0);
}
currentSubName = subscriptionList->currentItem()->text();
LOG(UI, "Subscription row changed, new name: " + currentSubName)
//if (subscriptionList->count() == 0) {
// return;
//}
//
subNameTxt->setText(currentSubName);
subAddrTxt->setText(subscriptions[currentSubName].address);
updateIntervalSB->setValue(subscriptions[currentSubName].updateInterval);
lastUpdatedLabel->setText(timeToString(subscriptions[currentSubName].lastUpdated));
//if (currentRow < 0 && subscriptionList->count() > 0) {
// subscriptionList->setCurrentRow(0);
//}
//
connectionsList->clear();
auto _list = GetSubscriptionConnection(currentSubName);
for (auto i = 0; i < _list.count(); i++) {
connectionsList->addItem(_list.keys()[i]);
}
//currentSubName = subscriptionList->currentItem()->text();
//LOG(MODULE_UI, "Subscription row changed, new name: " + currentSubName)
////
//subNameTxt->setText(currentSubName);
//subAddrTxt->setText(subscriptions[currentSubName].address);
//updateIntervalSB->setValue(subscriptions[currentSubName].updateInterval);
//lastUpdatedLabel->setText(timeToString(subscriptions[currentSubName].lastUpdated));
////
//connectionsList->clear();
//auto _list = GetSubscriptionConnection(currentSubName);
//
//for (auto i = 0; i < _list.count(); i++) {
// connectionsList->addItem(_list.keys()[i]);
//}
}
void SubscribeEditor::SaveConfig()
{
QMap<QString, Qv2raySubscriptionConfig> newConf;
QMap<QString, QvSubscriptionObject> newConf;
for (auto _ : subscriptions.toStdMap()) {
if (!_.second.address.isEmpty()) {
@ -244,6 +242,6 @@ void SubscribeEditor::on_connectionsList_itemClicked(QListWidgetItem *item)
if (item != nullptr) {
auto name = item->text();
currentSelectedConfig.first = name;
currentSelectedConfig.second = GetSubscriptionConnection(currentSubName)[name];
//currentSelectedConfig.second = GetSubscriptionConnection(currentSubName)[name];
}
}

View File

@ -38,11 +38,11 @@ class SubscribeEditor : public QDialog, private Ui::w_SubscribeEditor
private:
void StartUpdateSubscription(const QString &subscriptionName);
void SaveConfig();
void LoadSubscriptionList(QMap<QString, Qv2raySubscriptionConfig> list);
void LoadSubscriptionList(QMap<QString, QvSubscriptionObject> list);
bool isUpdateInProgress = false;
QvHttpRequestHelper helper;
QPair<QString, CONFIGROOT> currentSelectedConfig;
QMap<QString, Qv2raySubscriptionConfig> subscriptions;
QMap<QString, QvSubscriptionObject> subscriptions;
QString currentSubName;
};

View File

@ -0,0 +1 @@
#include "ConnectionWidget.hpp"

View File

@ -0,0 +1,105 @@
#pragma once
#include <QWidget>
#include "ui_ConnectionWidget.h"
#include "core/handler/ConnectionHandler.hpp"
enum CONNECTION_ITEM_TYPE {
INVALID,
GROUP,
SUBSCRIPTION
};
class ConnectionWidget : public QWidget, private Ui::ConnectionWidget
{
Q_OBJECT
public:
//
// ======================================= Initialisation for connection nodes.
//
explicit ConnectionWidget(const GroupId &group, const ConnectionId &id, QWidget *parent = nullptr): ConnectionWidget(parent)
{
type = GROUP;
connectionId = id;
groupId = group;
InitialiseForConnection(id);
}
explicit ConnectionWidget(const SubscriptionId &group, const ConnectionId &id, QWidget *parent = nullptr): ConnectionWidget(parent)
{
type = SUBSCRIPTION;
connectionId = id;
subscriptionId = group;
InitialiseForConnection(id);
}
//
// ======================================= Initialisation for root nodes.
//
explicit ConnectionWidget(const GroupId &id, QWidget *parent = nullptr) : ConnectionWidget(parent)
{
type = INVALID;
groupId = id;
InitialiseForGroup(ConnectionHandler->GetGroup(id).displayName, ConnectionHandler->Connections(id).count());
}
explicit ConnectionWidget(const SubscriptionId &id, QWidget *parent = nullptr) : ConnectionWidget(parent)
{
type = INVALID;
subscriptionId = id;
InitialiseForGroup(ConnectionHandler->GetSubscription(id).displayName, ConnectionHandler->Connections(id).count());
}
inline bool IsConnection() const
{
return isConnectionItem;
}
void BeginConnection()
{
if (isConnectionItem) {
if (type == GROUP) {
ConnectionHandler->StartConnection(groupId, connectionId);
} else if (type == SUBSCRIPTION) {
ConnectionHandler->StartConnection(subscriptionId, connectionId);
} else {
LOG(MODULE_UI, "Trying to start an INVALID non-connection entry, this call is illegal.")
}
} else {
LOG(MODULE_UI, "Trying to start a non-connection entry, this call is illegal.")
}
}
~ConnectionWidget()
{
//
}
private:
ConnectionWidget(QWidget *parent = nullptr) : QWidget(parent), connectionId("null"), groupId("null"), subscriptionId("null")
{
setupUi(this);
}
void InitialiseForConnection(const ConnectionId &id)
{
isConnectionItem = true;
auto connection = ConnectionHandler->GetConnection(id);
rawDisplayName = connection.displayName;
connNameLabel->setText(rawDisplayName);
latencyLabel->setText(tr("Latency: ") + QSTRN(connection.latency) + " " + tr("ms"));
}
void InitialiseForGroup(const QString &displayName, int connectionCount)
{
rawDisplayName = displayName;
connNameLabel->setText(rawDisplayName);
latencyLabel->setText(QSTRN(connectionCount) + " " + (connectionCount < 2 ? tr("connection") : tr("connections")));
//
layout()->removeWidget(connTypeLabel);
delete connTypeLabel;
layout()->removeWidget(dataLabel);
delete dataLabel;
}
CONNECTION_ITEM_TYPE type;
bool isConnectionItem = false;
QString rawDisplayName;
//
ConnectionId connectionId;
GroupId groupId;
SubscriptionId subscriptionId;
Q_DISABLE_COPY_MOVE(ConnectionWidget)
};

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConnectionWidget</class>
<widget class="QWidget" name="ConnectionWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>283</width>
<height>84</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="connNameLabel">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Connection Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="latencyLabel">
<property name="text">
<string>Latency: 500ms</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="connTypeLabel">
<property name="text">
<string>Type: vmess + tls + ws</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="dataLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>0KB / 0KB</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>