fix: update code style

This commit is contained in:
Qv2ray-dev 2020-02-28 22:49:53 +08:00
parent 194f07c027
commit 09de96efe5
106 changed files with 4787 additions and 4162 deletions

View File

@ -1,306 +0,0 @@
# ~/.astylerc
#
# Courtesy of HN's super_mario: http://news.ycombinator.com/item?id=5348401
#
# Use K&R formatting style
style=kr
# Indent class and struct blocks so that the blocks 'public', 'private' and
# 'protected' are indented. This option is effective in C++ files only
indent-classes
# Indent 'switch' blocks so that the 'case X:' statements are indented with
# the switch block. The entire case block is indented.
#
# For example:
# switch (foo)
# {
# case 1:
# a += 1;
# break;
#
# case 2:
# {
# a += 2;
# break;
# }
# }
#
# becomes
#
# switch (foo)
# {
# case 1:
# a += 1;
# break;
#
# case 2:
# {
# a += 2;
# break;
# }
# }
indent-switches
# Indent C++ namespaces (this option has no effect on other file types)
# Add extra indentation to namespace blocks.
# For example:
# namespace foospace
# {
# class Foo
# {
# public:
# Foo();
# virtual ~Foo();
# };
# }
#
# becomes
#
# namespace foospace
# {
# class Foo
# {
# public:
# Foo();
# virtual ~Foo();
# };
# }
indent-namespaces
# Indent multi line preprocessor definitions ending with a backslash
# For example:
#
# #define Is_Bar(arg,a,b) \
# (Is_Foo((arg), (a)) \
# || Is_Foo((arg), (b)))
#
# becomes:
#
# #define Is_Bar(arg,a,b) \
# (Is_Foo((arg), (a)) \
# || Is_Foo((arg), (b)))
#
indent-preprocessor
# Indent C++ comments beginning in column one.
# For example
#
# void Foo()\n"
# {
# // comment
# if (isFoo)
# bar();
# }
#
# becomes:
#
# void Foo()\n"
# {
# // comment
# if (isFoo)
# bar();
# }
#
indent-col1-comments
# Pad empty lines around header blocks (e.g. 'if', 'for', 'while'...).
#
# isFoo = true;
# if (isFoo) {
# bar();
# } else {
# anotherBar();
# }
# isBar = false;
#
# becomes:
#
# isFoo = true;
#
# if (isFoo) {
# bar();
# } else {
# anotherBar();
# }
#
# isBar = false;
#
break-blocks
# Insert space padding around operators. Any end of line comments will remain
# in the original column, if possible. Note that there is no option to unpad.
# Once padded, they stay padded.
#
# if (foo==2)
# a=bar((b-c)*a,d--);
#
# becomes:
#
# if (foo == 2)
# a = bar((b - c) * a, d--);
#
pad-oper
# Insert space padding after paren headers only (e.g. 'if', 'for', 'while'...).
# Any end of line comments will remain in the original column, if possible.
# This can be used with unpad-paren to remove unwanted spaces.
#
# if(isFoo(a, b))
# bar(a, b);
#
# becomes:
#
# if (isFoo(a, b))
# bar(a, b);
#
pad-header
# Remove extra space padding around parenthesis on the inside and outside. Any
# end of line comments will remain in the original column, if possible. This
# option can be used in combination with the paren padding options padparen,
# padparenout, padparenin, and padheader above. Only padding that has not
# been requested by other options will be removed.
#
# For example, if a source has parens padded on both the inside and outside,
# and you want inside only. You need to use unpad-paren to remove the outside
# padding, and padparenin to retain the inside padding. Using only
# padparenin would not remove the outside padding.
#
# if ( isFoo( a, b ) )
# bar ( a, b );
#
# becomes (with no padding option requested):
#
# if(isFoo(a, b))
# bar(a, b);
#
unpad-paren
# Delete empty lines within a function or method. Empty lines outside of
# functions or methods are NOT deleted. If used with break-blocks or
# break-blocks=all it will delete all lines EXCEPT the lines added by the
# break-blocks options.
#
# void Foo()
# {
#
# foo1 = 1;
#
# foo2 = 2;
#
# }
#
# becomes:
#
# void Foo()
# {
# foo1 = 1;
# foo2 = 2;
# }
#
delete-empty-lines
# Attach a pointer or reference operator (* or &) to either the variable type
# (left) or variable name (right), or place it between the type and name
# (middle). The spacing between the type and name will be preserved, if
# possible. To format references separately use the following align-reference
# option.
#
# char *foo1;
# char &foo2;
#
# becomes (with align-pointer=type):
#
# char* foo1;
# char& foo2;
#
# char* foo1;
# char& foo2;
#
# becomes (with align-pointer=middle):
#
# char * foo1;
# char & foo2;
#
# char* foo1;
# char& foo2;
#
# becomes (with align-pointer=name):
#
# char *foo1;
# char &foo2;
#
align-pointer=name
# Set the minimal indent that is added when a header is built of multiple
# lines. This indent helps to easily separate the header from the command
# statements that follow. The value for # indicates a number of indents and is
# a minimum value. The indent may be greater to align with the data on the
# previous line.
# The valid values are:
# 0 - no minimal indent. The lines will be aligned with the paren on the
# preceding line.
# 1 - indent at least one additional indent.
# 2 - indent at least two additional indents.
# 3 - indent at least one-half an additional indent. This is intended for large
# indents (e.g. 8).
#
# The default value is 2, two additional indents.
#
# // default setting makes this non-bracketed code clear
# if (a < b
# || c > d)
# foo++;
#
# // but creates an exaggerated indent in this bracketed code
# if (a < b
# || c > d)
# {
# foo++;
# }
#
# becomes (when setting --min-conditional-indent=0):
#
# // setting makes this non-bracketed code less clear
# if (a < b
# || c > d)
# foo++;
#
# // but makes this bracketed code clearer
# if (a < b
# || c > d)
# {
# foo++;
# }
#
min-conditional-indent=0
# Set the maximum of # spaces to indent a continuation line. The # indicates
# a number of columns and must not be greater than 120. If no # is set, the
# default value of 40 will be used. A maximum of less than two indent lengths
# will be ignored. This option will prevent continuation lines from extending
# too far to the right. Setting a larger value will allow the code to be
# extended further to the right.
#
# fooArray[] = { red,
# green,
# blue };
#
# fooFunction(barArg1,
# barArg2,
# barArg3);
#
# becomes (with larger value):
#
# fooArray[] = { red,
# green,
# blue };
#
# fooFunction(barArg1,
# barArg2,
# barArg3);
#
#max-instatement-indent=9

50
_clang-format Normal file
View File

@ -0,0 +1,50 @@
---
BasedOnStyle: Microsoft
AccessModifierOffset: '-2'
AlignAfterOpenBracket: Align
AllowAllArgumentsOnNextLine: 'false'
AllowAllConstructorInitializersOnNextLine: 'false'
AllowAllParametersOfDeclarationOnNextLine: 'false'
AllowShortBlocksOnASingleLine: 'true'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: 'true'
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: 'false'
AlwaysBreakTemplateDeclarations: 'Yes'
BinPackArguments: 'true'
BinPackParameters: 'true'
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: 'false'
BreakInheritanceList: BeforeComma
BreakStringLiterals: 'false'
ColumnLimit: '145'
CompactNamespaces: 'false'
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
Cpp11BracedListStyle: 'false'
ExperimentalAutoDetectBinPacking: 'false'
FixNamespaceComments: 'true'
IncludeBlocks: Regroup
IndentCaseLabels: 'true'
IndentPPDirectives: BeforeHash
IndentWidth: '4'
Language: Cpp
MaxEmptyLinesToKeep: '1'
NamespaceIndentation: All
ReflowComments: 'true'
SortIncludes: 'true'
SortUsingDeclarations: 'true'
SpaceAfterCStyleCast: 'true'
SpaceAfterTemplateKeyword: 'false'
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: 'true'
SpacesInParentheses: 'false'
Standard: Cpp11
StatementMacros: [ Q_UNUSED LOG DEBUG ]
TabWidth: '4'
UseTab: Never
...

View File

@ -1 +1 @@
4014
4031

View File

@ -1,8 +1,8 @@
#pragma once
#include "base/models/QvConfigModel.hpp"
#include "base/models/QvRuntimeConfig.hpp"
#include "base/models/QvStartupConfig.hpp"
#include "base/models/QvConfigModel.hpp"
#include <QTranslator>
@ -18,4 +18,4 @@ namespace Qv2ray
inline base::QvStartupOptions StartupOption = base::QvStartupOptions();
//
inline std::unique_ptr<QTranslator> Qv2rayTranslator;
}
} // namespace Qv2ray

View File

@ -1,42 +1,42 @@
#pragma once
#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
#define EXPAND(x) x
#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
#define FOR_EACH_3(what, x, ...)\
what(x);\
#define FOR_EACH_2(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
#define FOR_EACH_3(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
#define FOR_EACH_4(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
#define FOR_EACH_5(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
#define FOR_EACH_6(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
#define FOR_EACH_7(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
#define FOR_EACH_8(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
#define FOR_EACH_4(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
#define FOR_EACH_5(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
#define FOR_EACH_6(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
#define FOR_EACH_7(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
#define FOR_EACH_8(what, x, ...) \
what(x); \
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define CONCATENATE(x,y) x##y
#define CONCATENATE(x, y) x##y
#define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__))
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
#define JADDEx_(jsonObj, field) jsonObj.insert(#field, field);

View File

@ -1,30 +1,30 @@
#pragma once
//
#ifndef XTOSTRUCT_QT
# define XTOSTRUCT_QT
#define XTOSTRUCT_QT
#endif
//
#include <QtCore>
#include <QtGui>
#include <QApplication>
#include <QMap>
#include <vector>
#include <QtCore>
#include <QtGui>
#include <algorithm>
#include <iostream>
#include <ctime>
#include <iostream>
#include <optional>
#include <vector>
// Base support.
#include "base/Qv2rayLog.hpp"
#include "base/Qv2rayFeatures.hpp"
#include "base/JsonHelpers.hpp"
#include "base/GlobalInstances.hpp"
#include "base/JsonHelpers.hpp"
#include "base/Qv2rayFeatures.hpp"
#include "base/Qv2rayLog.hpp"
// Code Models
#include "base/models/QvSafeType.hpp"
#include "base/models/CoreObjectModels.hpp"
#include "base/models/QvConfigModel.hpp"
#include "base/models/QvConfigIdentifier.hpp"
#include "base/models/QvStartupConfig.hpp"
#include "base/models/QvConfigModel.hpp"
#include "base/models/QvRuntimeConfig.hpp"
#include "base/models/QvSafeType.hpp"
#include "base/models/QvStartupConfig.hpp"
using namespace std;
using namespace std::chrono;
@ -38,9 +38,9 @@ using namespace Qv2ray::base::objects::transfer;
// Linux users and DEs should handle the darkMode UI themselves.
#ifndef QV2RAY_USE_BUILTIN_DARKTHEME
# ifndef Q_OS_LINUX
# define QV2RAY_USE_BUILTIN_DARKTHEME
# endif
#ifndef Q_OS_LINUX
#define QV2RAY_USE_BUILTIN_DARKTHEME
#endif
#endif
#define QV2RAY_BUILD_INFO QString(_QV2RAY_BUILD_INFO_STR_)
@ -48,9 +48,9 @@ using namespace Qv2ray::base::objects::transfer;
// Base folder suffix.
#ifdef QT_DEBUG
# define QV2RAY_CONFIG_DIR_SUFFIX "_debug/"
#define QV2RAY_CONFIG_DIR_SUFFIX "_debug/"
#else
# define QV2RAY_CONFIG_DIR_SUFFIX "/"
#define QV2RAY_CONFIG_DIR_SUFFIX "/"
#endif
// Get Configured Config Dir Path
@ -68,17 +68,17 @@ using namespace Qv2ray::base::objects::transfer;
#define QV2RAY_GENERATED_DIR (QV2RAY_CONFIG_DIR + "generated/")
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
#if ! defined (QV2RAY_DEFAULT_VCORE_PATH) && ! defined (QV2RAY_DEFAULT_VASSETS_PATH)
# define QV2RAY_DEFAULT_VASSETS_PATH (QV2RAY_CONFIG_DIR + "vcore/")
# ifdef Q_OS_WIN
# define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
# else
# define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
# endif
#elif defined (QV2RAY_DEFAULT_VCORE_PATH) && defined (QV2RAY_DEFAULT_VASSETS_PATH)
#if !defined(QV2RAY_DEFAULT_VCORE_PATH) && !defined(QV2RAY_DEFAULT_VASSETS_PATH)
#define QV2RAY_DEFAULT_VASSETS_PATH (QV2RAY_CONFIG_DIR + "vcore/")
#ifdef Q_OS_WIN
#define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
#else
#define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
#endif
#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 be presented when using manually specify 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
@ -86,8 +86,8 @@ using namespace Qv2ray::base::objects::transfer;
//# define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
//# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl.exe")
#else
# define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl")
#define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
#define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl")
#endif
#define QV2RAY_VCORE_LOG_DIRNAME "logs/"
@ -95,15 +95,15 @@ using namespace Qv2ray::base::objects::transfer;
#define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log"
// GUI TOOLS
#define RED(obj) \
auto _temp = obj->palette(); \
_temp.setColor(QPalette::Text, Qt::red); \
#define RED(obj) \
auto _temp = obj->palette(); \
_temp.setColor(QPalette::Text, Qt::red); \
obj->setPalette(_temp);
#define BLACK(obj) \
obj->setPalette(QWidget::palette());
#define BLACK(obj) obj->setPalette(QWidget::palette());
#define QV2RAY_UI_RESOURCES_ROOT ((GlobalConfig.uiConfig.useDarkTheme) ? QStringLiteral(":/assets/icons/ui_dark/") : QStringLiteral(":/assets/icons/ui_light/"))
#define QV2RAY_UI_RESOURCES_ROOT \
((GlobalConfig.uiConfig.useDarkTheme) ? QStringLiteral(":/assets/icons/ui_dark/") : QStringLiteral(":/assets/icons/ui_light/"))
#define QICON_R(file) QIcon(QV2RAY_UI_RESOURCES_ROOT + file)
#define QSTRN(num) QString::number(num)
@ -117,7 +117,8 @@ using namespace Qv2ray::base::objects::transfer;
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
#define JSON_ROOT_TRY_REMOVE(obj) if (root.contains(obj)) { root.remove(obj); }
#define JSON_ROOT_TRY_REMOVE(obj) \
if (root.contains(obj)) { root.remove(obj); }
namespace Qv2ray
{
@ -129,4 +130,4 @@ namespace Qv2ray
isExiting = true;
QApplication::quit();
}
}
} // namespace Qv2ray

View File

@ -3,7 +3,7 @@
//
// Always use libgRPC++ on windows platform.
#ifndef WITH_LIB_GRPCPP
# ifdef _WIN32
# define WITH_LIB_GRPCPP
# endif
#ifdef _WIN32
#define WITH_LIB_GRPCPP
#endif
#endif

View File

@ -1,5 +1,7 @@
#include "Qv2rayLog.hpp"
#include "base/GlobalInstances.hpp"
#include <iostream>
namespace Qv2ray::base
@ -15,18 +17,22 @@ namespace Qv2ray::base
auto logString = "[" + module + "]: " + log;
auto funcPrepend = QString::fromStdString(func + ":" + to_string(line) + " ");
if (isDebugBuild) {
// Debug build version, we only print info for DEBUG logs and print ALL info when debugLog presents,
if (type == QV2RAY_LOG_DEBUG || StartupOption.debugLog) {
logString = logString.prepend(funcPrepend);
}
} else {
if (isDebugBuild)
{
// Debug build version, we only print info for DEBUG logs and print
// ALL info when debugLog presents,
if (type == QV2RAY_LOG_DEBUG || StartupOption.debugLog) { logString = logString.prepend(funcPrepend); }
}
else
{
// We only process DEBUG log in Release mode
if (type == QV2RAY_LOG_DEBUG) {
if (StartupOption.debugLog) {
logString = logString.prepend(funcPrepend);
} else {
// Discard debug log in non-debug Qv2ray version with no-debugLog mode.
if (type == QV2RAY_LOG_DEBUG)
{
if (StartupOption.debugLog) { logString = logString.prepend(funcPrepend); }
else
{
// Discard debug log in non-debug Qv2ray version with
// no-debugLog mode.
return;
}
}
@ -50,4 +56,4 @@ namespace Qv2ray::base
__purgerBuffer->clear();
return result;
}
}
} // namespace Qv2ray::base

View File

@ -17,17 +17,17 @@ namespace Qv2ray::base
{
void __QV2RAY_LOG_FUNC__(int type, const std::string &func, int line, const QString &module, const QString &log);
const QString readLastLog();
}
} // namespace Qv2ray::base
#define NEWLINE "\r\n"
#define QV2RAY_LOG_NORMAL 0
#define QV2RAY_LOG_DEBUG 1
#define QV2RAY_LOG_DEBUG 1
#ifndef Q_OS_WIN
#define Qv2ray_PRETTY_FUNCTION __PRETTY_FUNCTION__
#define Qv2ray_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define Qv2ray_PRETTY_FUNCTION __FUNCSIG__
#define Qv2ray_PRETTY_FUNCTION __FUNCSIG__
#endif
#define __LOG_IMPL(LEVEL, MODULE, MSG) __QV2RAY_LOG_FUNC__(LEVEL, Qv2ray_PRETTY_FUNCTION, __LINE__, MODULE, MSG);
@ -36,23 +36,23 @@ namespace Qv2ray::base
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
// Log modules used by Qv2ray
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 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 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 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 MODULE_NETWORK = "COMMON-NETWORK" ;
const inline QString MODULE_FILEIO = "COMMON-FILEIO" ;
const inline QString MODULE_NETWORK = "COMMON-NETWORK";
const inline QString MODULE_FILEIO = "COMMON-FILEIO";
//
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_PROXY = "COMPONENT-PROXY";
const inline QString MODULE_UPDATE = "COMPONENT-UPDATE";
const inline QString MODULE_PLUGIN = "COMPONENT-PLUGIN";
// ================================================================
const inline QString MODULE_CORE_HANDLER = "QV2RAY-CORE";
const inline QString MODULE_CORE_HANDLER = "QV2RAY-CORE";

View File

@ -1,37 +1,46 @@
#pragma once
#include <QString>
#include "3rdparty/x2struct/x2struct.hpp"
#include <QList>
#include <QMap>
#include "3rdparty/x2struct/x2struct.hpp"
#include <QString>
namespace Qv2ray::base::objects
{
//
// Used in config generation
struct AccountObject {
struct AccountObject
{
QString user;
QString pass;
XTOSTRUCT(O(user, pass))
};
//
//
struct ApiObject {
struct ApiObject
{
QString tag;
QList<QString> services;
ApiObject() : tag("api"), services() {}
ApiObject() : tag("api"), services()
{
}
XTOSTRUCT(O(tag, services))
};
//
//
struct SystemPolicyObject {
struct SystemPolicyObject
{
bool statsInboundUplink;
bool statsInboundDownlink;
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink() {}
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink()
{
}
XTOSTRUCT(O(statsInboundUplink, statsInboundDownlink))
};
//
//
struct LevelPolicyObject {
struct LevelPolicyObject
{
int handshake;
int connIdle;
int uplinkOnly;
@ -39,20 +48,26 @@ namespace Qv2ray::base::objects
bool statsUserUplink;
bool statsUserDownlink;
int bufferSize;
LevelPolicyObject(): handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize() {}
LevelPolicyObject() : handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize()
{
}
XTOSTRUCT(O(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize))
};
//
//
struct PolicyObject {
struct PolicyObject
{
QMap<QString, LevelPolicyObject> level;
QList<SystemPolicyObject> system;
PolicyObject(): level(), system() {}
PolicyObject() : level(), system()
{
}
XTOSTRUCT(O(level, system))
};
//
//
struct RuleObject {
struct RuleObject
{
// Added due to the request of @aliyuchang33
bool QV2RAY_RULE_ENABLED;
bool QV2RAY_RULE_USE_BALANCER;
@ -70,65 +85,89 @@ namespace Qv2ray::base::objects
QString attrs;
QString outboundTag;
QString balancerTag;
RuleObject() : QV2RAY_RULE_ENABLED(true), QV2RAY_RULE_USE_BALANCER(false), QV2RAY_RULE_TAG("new rule"), type("field"), domain(), ip(), port("1-65535"), network(""), source(), user(), inboundTag(), protocol(), attrs(), outboundTag(""), balancerTag("") {}
XTOSTRUCT(O(QV2RAY_RULE_ENABLED, QV2RAY_RULE_USE_BALANCER, QV2RAY_RULE_TAG, type, domain, ip, port, network, source, user, inboundTag, protocol, attrs, outboundTag, balancerTag))
RuleObject()
: QV2RAY_RULE_ENABLED(true), QV2RAY_RULE_USE_BALANCER(false), QV2RAY_RULE_TAG("new rule"), type("field"), domain(), ip(),
port("1-65535"), network(""), source(), user(), inboundTag(), protocol(), attrs(), outboundTag(""), balancerTag("")
{
}
XTOSTRUCT(O(QV2RAY_RULE_ENABLED, QV2RAY_RULE_USE_BALANCER, QV2RAY_RULE_TAG, type, domain, ip, port, network, source, user, inboundTag,
protocol, attrs, outboundTag, balancerTag))
};
//
//
struct BalancerObject {
QString tag ;
struct BalancerObject
{
QString tag;
QList<QString> selector;
BalancerObject() : tag(), selector() {}
BalancerObject() : tag(), selector()
{
}
XTOSTRUCT(O(tag, selector))
};
//
//
namespace transfer
{
struct HTTPRequestObject {
struct HTTPRequestObject
{
QString version;
QString method;
QList<QString> path;
QMap<QString, QList<QString>> headers;
HTTPRequestObject(): version("1.1"), method("GET"), path(), headers() {}
HTTPRequestObject() : version("1.1"), method("GET"), path(), headers()
{
}
XTOSTRUCT(O(version, method, path, headers))
};
//
//
struct HTTPResponseObject {
struct HTTPResponseObject
{
QString version;
QString status;
QString reason;
QMap<QString, QList<QString>> headers;
HTTPResponseObject(): version("1.1"), status("200"), reason("OK"), headers() {}
HTTPResponseObject() : version("1.1"), status("200"), reason("OK"), headers()
{
}
XTOSTRUCT(O(version, status, reason, headers))
};
//
//
struct TCPHeader_M_Object {
struct TCPHeader_M_Object
{
QString type;
HTTPRequestObject request;
HTTPResponseObject response;
TCPHeader_M_Object(): type("none"), request(), response() {}
TCPHeader_M_Object() : type("none"), request(), response()
{
}
XTOSTRUCT(O(type, request, response))
};
//
//
struct HeaderObject {
struct HeaderObject
{
QString type;
HeaderObject(): type("none") {}
HeaderObject() : type("none")
{
}
XTOSTRUCT(O(type))
};
//
//
struct TCPObject {
struct TCPObject
{
TCPHeader_M_Object header;
TCPObject(): header() {}
TCPObject() : header()
{
}
XTOSTRUCT(O(header))
};
//
//
struct KCPObject {
struct KCPObject
{
int mtu = 1350;
int tti = 20;
int uplinkCapacity = 5;
@ -137,84 +176,111 @@ namespace Qv2ray::base::objects
int readBufferSize = 1;
int writeBufferSize = 1;
HeaderObject header;
KCPObject(): header() {}
KCPObject() : header()
{
}
XTOSTRUCT(O(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header))
};
//
//
struct WebSocketObject {
struct WebSocketObject
{
QString path;
QMap<QString, QString> headers;
WebSocketObject(): path("/"), headers() {}
WebSocketObject() : path("/"), headers()
{
}
XTOSTRUCT(O(path, headers))
};
//
//
struct HttpObject {
struct HttpObject
{
QList<QString> host;
QString path;
HttpObject() : host(), path("/") {}
HttpObject() : host(), path("/")
{
}
XTOSTRUCT(O(host, path))
};
//
//
struct DomainSocketObject {
struct DomainSocketObject
{
QString path;
DomainSocketObject(): path("/") {}
DomainSocketObject() : path("/")
{
}
XTOSTRUCT(O(path))
};
//
//
struct QuicObject {
struct QuicObject
{
QString security;
QString key;
HeaderObject header;
QuicObject(): security(""), key(""), header() {}
QuicObject() : security(""), key(""), header()
{
}
XTOSTRUCT(O(security, key, header))
};
//
//
struct SockoptObject {
struct SockoptObject
{
int mark;
bool tcpFastOpen;
QString tproxy;
SockoptObject(): mark(0), tcpFastOpen(false), tproxy("off") {}
SockoptObject() : mark(0), tcpFastOpen(false), tproxy("off")
{
}
XTOSTRUCT(O(mark, tcpFastOpen, tproxy))
};
//
//
struct CertificateObject {
struct CertificateObject
{
QString usage;
QString certificateFile;
QString keyFile;
QList<QString> certificate;
QList<QString> key;
CertificateObject(): usage(), certificateFile(), keyFile(), certificate(), key() {}
CertificateObject() : usage(), certificateFile(), keyFile(), certificate(), key()
{
}
XTOSTRUCT(O(usage, certificateFile, keyFile, certificate, key))
};
//
//
struct TLSObject {
struct TLSObject
{
QString serverName;
bool allowInsecure;
QList<QString> alpn;
QList<CertificateObject> certificates;
bool disableSystemRoot;
TLSObject(): serverName(), allowInsecure(), certificates(), disableSystemRoot() {}
TLSObject() : serverName(), allowInsecure(), certificates(), disableSystemRoot()
{
}
XTOSTRUCT(O(serverName, allowInsecure, alpn, certificates, disableSystemRoot))
};
}
} // namespace transfer
//
//
struct SniffingObject {
struct SniffingObject
{
bool enabled = false;
QList<QString> destOverride;
SniffingObject(): enabled(), destOverride() {}
SniffingObject() : enabled(), destOverride()
{
}
XTOSTRUCT(O(enabled, destOverride))
};
//
//
struct StreamSettingsObject {
struct StreamSettingsObject
{
QString network;
QString security;
transfer::SockoptObject sockopt;
@ -225,15 +291,22 @@ namespace Qv2ray::base::objects
transfer::HttpObject httpSettings;
transfer::DomainSocketObject dsSettings;
transfer::QuicObject quicSettings;
StreamSettingsObject(): network("tcp"), security("none"), sockopt(), tlsSettings(), tcpSettings(), kcpSettings(), wsSettings(), httpSettings(), dsSettings(), quicSettings() {}
StreamSettingsObject()
: network("tcp"), security("none"), sockopt(), tlsSettings(), tcpSettings(), kcpSettings(), wsSettings(), httpSettings(),
dsSettings(), quicSettings()
{
}
XTOSTRUCT(O(network, security, sockopt, tcpSettings, tlsSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings))
};
//
//
struct MuxObject {
struct MuxObject
{
bool enabled;
int concurrency;
MuxObject(): enabled(), concurrency() {}
MuxObject() : enabled(), concurrency()
{
}
XTOSTRUCT(O(enabled, concurrency))
};
//
@ -241,21 +314,28 @@ namespace Qv2ray::base::objects
namespace protocol
{
// DNS, OutBound
struct DNSOut {
struct DNSOut
{
QString network;
QString address;
int port;
DNSOut(): network(""), address("0.0.0.0"), port(0) {}
DNSOut() : network(""), address("0.0.0.0"), port(0)
{
}
XTOSTRUCT(O(network, address, port))
};
//
// MTProto, InBound || OutBound
struct MTProtoIn {
struct UserObject {
struct MTProtoIn
{
struct UserObject
{
QString email;
int level;
QString secret;
UserObject() : email("user@domain.com"), level(0), secret("") {}
UserObject() : email("user@domain.com"), level(0), secret("")
{
}
XTOSTRUCT(O(email, level, secret))
};
QList<UserObject> users;
@ -263,42 +343,55 @@ namespace Qv2ray::base::objects
};
//
// Socks, OutBound
struct SocksServerObject {
struct UserObject {
struct SocksServerObject
{
struct UserObject
{
QString user;
QString pass;
int level;
UserObject(): user("username"), pass("password"), level(0) {}
UserObject() : user("username"), pass("password"), level(0)
{
}
XTOSTRUCT(O(user, pass, level))
};
QString address;
int port;
QList<UserObject> users;
SocksServerObject(): address("0.0.0.0"), port(0), users() {}
SocksServerObject() : address("0.0.0.0"), port(0), users()
{
}
XTOSTRUCT(O(address, port, users))
};
//
// VMess Server
struct VMessServerObject {
struct UserObject {
struct VMessServerObject
{
struct UserObject
{
QString id;
int alterId;
QString security;
int level;
UserObject() : id(""), alterId(64), security("auto"), level(0) {}
UserObject() : id(""), alterId(64), security("auto"), level(0)
{
}
XTOSTRUCT(O(id, alterId, security, level))
};
QString address;
int port;
QList<UserObject> users;
VMessServerObject(): address(""), port(0), users() {}
VMessServerObject() : address(""), port(0), users()
{
}
XTOSTRUCT(O(address, port, users))
};
//
// ShadowSocks Server
struct ShadowSocksServerObject {
struct ShadowSocksServerObject
{
QString email;
QString address;
QString method;
@ -306,8 +399,11 @@ namespace Qv2ray::base::objects
bool ota;
int level;
int port;
ShadowSocksServerObject(): email("user@domain.com"), address("0.0.0.0"), method("aes-256-cfb"), password(""), ota(false), level(0), port(0) {}
ShadowSocksServerObject()
: email("user@domain.com"), address("0.0.0.0"), method("aes-256-cfb"), password(""), ota(false), level(0), port(0)
{
}
XTOSTRUCT(O(email, address, port, method, password, ota, level))
};
}
}
} // namespace protocol
} // namespace Qv2ray::base::objects

View File

@ -1,38 +1,50 @@
#pragma once
#include "3rdparty/x2struct/x2struct.hpp"
#include <QString>
#include <QtCore>
#include "3rdparty/x2struct/x2struct.hpp"
namespace Qv2ray::base
{
using namespace std::chrono;
// Common struct for Groups and Subscriptions
struct GroupObject_Config {
struct GroupObject_Config
{
QString displayName;
QList<QString> connections;
int64_t importDate;
GroupObject_Config(): displayName(), connections(), importDate() { }
GroupObject_Config() : displayName(), connections(), importDate()
{
}
XTOSTRUCT(O(displayName, connections, importDate))
};
struct SubscriptionObject_Config : GroupObject_Config {
struct SubscriptionObject_Config : GroupObject_Config
{
//
QString address;
int64_t lastUpdated;
float updateInterval;
SubscriptionObject_Config(): address(""), lastUpdated(system_clock::to_time_t(system_clock::now())), updateInterval(10) { }
SubscriptionObject_Config() : address(""), lastUpdated(system_clock::to_time_t(system_clock::now())), updateInterval(10)
{
}
XTOSTRUCT(O(lastUpdated, updateInterval, address, connections, displayName, importDate))
};
struct ConnectionObject_Config {
struct ConnectionObject_Config
{
QString displayName;
int64_t importDate;
int64_t lastConnected;
int64_t latency;
int64_t upLinkData;
int64_t downLinkData;
ConnectionObject_Config(): displayName(), importDate(system_clock::to_time_t(system_clock::now())), lastConnected(), latency(0), upLinkData(0), downLinkData(0) { }
ConnectionObject_Config()
: 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))
};
}
} // namespace Qv2ray::base
using namespace Qv2ray::base;

View File

@ -2,46 +2,59 @@
#include "3rdparty/x2struct/x2struct.hpp"
#include "base/models/CoreObjectModels.hpp"
#include "base/models/QvConfigIdentifier.hpp"
#include <chrono>
const int QV2RAY_CONFIG_VERSION = 9;
namespace Qv2ray::base::config
{
struct QvBarLine {
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("") { }
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 {
struct QvBarPage
{
int OffsetYpx;
QList<QvBarLine> Lines;
QvBarPage(): OffsetYpx(5) { }
QvBarPage() : OffsetYpx(5)
{
}
XTOSTRUCT(O(OffsetYpx, Lines))
};
struct Qv2rayToolBarConfig {
struct Qv2rayToolBarConfig
{
QList<QvBarPage> Pages;
XTOSTRUCT(O(Pages))
};
struct Qv2rayPACConfig {
struct Qv2rayPACConfig
{
bool enablePAC;
int port;
QString localIP;
bool useSocksProxy;
Qv2rayPACConfig(): enablePAC(false), port(8989), useSocksProxy(false) { }
Qv2rayPACConfig() : enablePAC(false), port(8989), useSocksProxy(false)
{
}
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
};
struct Qv2rayForwardProxyConfig {
struct Qv2rayForwardProxyConfig
{
bool enableForwardProxy;
QString type;
QString serverAddress;
@ -49,12 +62,15 @@ namespace Qv2ray::base::config
bool useAuth;
QString username;
QString password;
Qv2rayForwardProxyConfig(): enableForwardProxy(false), type("http"), serverAddress("127.0.0.1"), port(8008),
useAuth(false), username(), 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 Qv2rayInboundsConfig {
struct Qv2rayInboundsConfig
{
QString listenip;
bool setSystemProxy;
Qv2rayPACConfig pacConfig;
@ -72,42 +88,56 @@ namespace Qv2ray::base::config
bool http_useAuth;
objects::AccountObject httpAccount;
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() {}
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()
{
}
XTOSTRUCT(O(setSystemProxy, pacConfig, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP, http_port, http_useAuth, httpAccount))
XTOSTRUCT(O(setSystemProxy, pacConfig, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP,
http_port, http_useAuth, httpAccount))
};
struct Qv2rayUIConfig {
struct Qv2rayUIConfig
{
QString theme;
QString language;
bool useDarkTheme;
bool useDarkTrayIcon;
int maximumLogLines;
Qv2rayUIConfig() : theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500) { }
Qv2rayUIConfig() : theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500)
{
}
XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon, maximumLogLines))
};
struct Qv2rayConnectionConfig {
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") { }
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 {
struct Qv2rayAPIConfig
{
bool enableAPI;
int statsPort;
Qv2rayAPIConfig(): enableAPI(true), statsPort(15490) { }
Qv2rayAPIConfig() : enableAPI(true), statsPort(15490)
{
}
XTOSTRUCT(O(enableAPI, statsPort))
};
struct Qv2rayConfig {
struct Qv2rayConfig
{
int config_version;
bool tProxySupport;
int logLevel;
@ -129,23 +159,13 @@ namespace Qv2ray::base::config
Qv2rayInboundsConfig inboundConfig;
Qv2rayConnectionConfig connectionConfig;
Qv2rayConfig():
config_version(QV2RAY_CONFIG_VERSION),
tProxySupport(false),
logLevel(),
v2CorePath(),
v2AssetsPath(),
ignoredVersion(),
groups(),
subscriptions(),
connections(),
uiConfig(), apiConfig(), toolBarConfig(), inboundConfig(), connectionConfig() { }
Qv2rayConfig()
: config_version(QV2RAY_CONFIG_VERSION), tProxySupport(false), logLevel(), v2CorePath(), v2AssetsPath(), ignoredVersion(), groups(),
subscriptions(), connections(), uiConfig(), apiConfig(), toolBarConfig(), inboundConfig(), connectionConfig()
{
}
XTOSTRUCT(O(config_version, ignoredVersion,
tProxySupport,
logLevel, uiConfig,
v2CorePath, v2AssetsPath,
groups, connections, subscriptions,
autoStartId, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
XTOSTRUCT(O(config_version, ignoredVersion, tProxySupport, logLevel, uiConfig, v2CorePath, v2AssetsPath, groups, connections,
subscriptions, autoStartId, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
};
}
} // namespace Qv2ray::base::config

View File

@ -5,8 +5,9 @@
namespace Qv2ray::base
{
struct Qv2rayRuntimeConfig {
struct Qv2rayRuntimeConfig
{
//
bool screenShotHideQv2ray = false;
};
}
} // namespace Qv2ray::base

View File

@ -1,15 +1,22 @@
#pragma once
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#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 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)
@ -31,5 +38,4 @@ namespace Qv2ray::base::safetype
SAFE_TYPEDEF(QJsonObject, ROUTERULE)
SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
}
} // namespace Qv2ray::base::safetype

View File

@ -4,7 +4,8 @@ namespace Qv2ray
{
namespace base
{
struct QvStartupOptions {
struct QvStartupOptions
{
/// No API subsystem
bool noAPI;
/// Explicitly run as root user.
@ -14,5 +15,5 @@ namespace Qv2ray
/// Enable Network toolbar plugin.
bool enableToolbarPlguin;
};
}
}
} // namespace base
} // namespace Qv2ray

View File

@ -1,15 +1,16 @@
#include "CommandArgs.hpp"
#include "base/Qv2rayBase.hpp"
namespace Qv2ray::common
{
QvCommandArgParser::QvCommandArgParser() : QObject(),
noAPIOption("noAPI", QObject::tr("Disable gRPC API subsystems.")),
runAsRootOption("I-just-wanna-run-with-root", QObject::tr("Explicitly run Qv2ray as root.")),
debugOption("debug", QObject::tr("Enable Debug Output")),
withToolbarOption("withToolbarPlugin", QObject::tr("Enable Qv2ray network toolbar plugin")),
//
helpOption("FAKE"), versionOption("FAKE")
QvCommandArgParser::QvCommandArgParser()
: QObject(), noAPIOption("noAPI", QObject::tr("Disable gRPC API subsystems.")),
runAsRootOption("I-just-wanna-run-with-root", QObject::tr("Explicitly run Qv2ray as root.")),
debugOption("debug", QObject::tr("Enable Debug Output")),
withToolbarOption("withToolbarPlugin", QObject::tr("Enable Qv2ray network toolbar plugin")),
//
helpOption("FAKE"), versionOption("FAKE")
{
parser.setApplicationDescription(QObject::tr("Qv2ray - A cross-platform Qt frontend for V2ray."));
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
@ -24,33 +25,36 @@ namespace Qv2ray::common
CommandLineParseResult QvCommandArgParser::ParseCommandLine(QString *errorMessage)
{
if (!parser.parse(QCoreApplication::arguments())) {
if (!parser.parse(QCoreApplication::arguments()))
{
*errorMessage = parser.errorText();
return CommandLineError;
}
if (parser.isSet(versionOption))
return CommandLineVersionRequested;
if (parser.isSet(versionOption)) return CommandLineVersionRequested;
if (parser.isSet(helpOption))
return CommandLineHelpRequested;
if (parser.isSet(helpOption)) return CommandLineHelpRequested;
if (parser.isSet(noAPIOption)) {
if (parser.isSet(noAPIOption))
{
DEBUG(MODULE_INIT, "noAPIOption is set.")
StartupOption.noAPI = true;
}
if (parser.isSet(runAsRootOption)) {
if (parser.isSet(runAsRootOption))
{
DEBUG(MODULE_INIT, "runAsRootOption is set.")
StartupOption.forceRunAsRootUser = true;
}
if (parser.isSet(debugOption)) {
if (parser.isSet(debugOption))
{
DEBUG(MODULE_INIT, "debugOption is set.")
StartupOption.debugLog = true;
}
if (parser.isSet(withToolbarOption)) {
if (parser.isSet(withToolbarOption))
{
DEBUG(MODULE_INIT, "withToolbarOption is set.")
StartupOption.enableToolbarPlguin = true;
}
@ -58,4 +62,4 @@ namespace Qv2ray::common
return CommandLineOk;
}
}
} // namespace Qv2ray::common

View File

@ -4,7 +4,8 @@
namespace Qv2ray::common
{
enum CommandLineParseResult {
enum CommandLineParseResult
{
CommandLineOk,
CommandLineError,
CommandLineVersionRequested,
@ -12,24 +13,24 @@ namespace Qv2ray::common
};
class QvCommandArgParser : public QObject
{
Q_OBJECT
public:
QvCommandArgParser();
CommandLineParseResult ParseCommandLine(QString *errorMessage);
const QCommandLineParser *Parser()
{
return &parser;
}
Q_OBJECT
public:
QvCommandArgParser();
CommandLineParseResult ParseCommandLine(QString *errorMessage);
const QCommandLineParser *Parser()
{
return &parser;
}
private:
QCommandLineParser parser;
QCommandLineOption noAPIOption;
QCommandLineOption runAsRootOption;
QCommandLineOption debugOption;
QCommandLineOption withToolbarOption;
QCommandLineOption helpOption;
QCommandLineOption versionOption;
private:
QCommandLineParser parser;
QCommandLineOption noAPIOption;
QCommandLineOption runAsRootOption;
QCommandLineOption debugOption;
QCommandLineOption withToolbarOption;
QCommandLineOption helpOption;
QCommandLineOption versionOption;
};
}
} // namespace Qv2ray::common
using namespace Qv2ray::common;

View File

@ -1,7 +1,9 @@
#include "HTTPRequestHelper.hpp"
#include "base/Qv2rayBase.hpp"
#include <QByteArray>
#include <QNetworkProxy>
#include "base/Qv2rayBase.hpp"
namespace Qv2ray::common
{
@ -18,7 +20,8 @@ namespace Qv2ray::common
{
QUrl qUrl = QUrl(url);
if (!qUrl.isValid()) {
if (!qUrl.isValid())
{
LOG(MODULE_NETWORK, "Provided URL is invalid: " + url)
return false;
}
@ -37,11 +40,14 @@ namespace Qv2ray::common
{
this->setUrl(url);
if (useProxy) {
if (useProxy)
{
auto proxy = QNetworkProxyFactory::systemProxyForQuery();
accessManager.setProxy(proxy.first());
LOG(MODULE_NETWORK, "Sync get is using system proxy settings")
} else {
}
else
{
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
}
@ -62,28 +68,34 @@ namespace Qv2ray::common
void QvHttpRequestHelper::get(const QString &url)
{
this->setUrl(url);
// request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
// request.setRawHeader("Content-Type",
// "application/x-www-form-urlencoded");
reply = accessManager.get(request);
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
}
//void QvHttpRequestHelper::post(const QString &url, const QByteArray &data)
// void QvHttpRequestHelper::post(const QString &url, const QByteArray
// &data)
//{
// this->setUrl(url);
// request.setRawHeader("Content-Type", "application/json");
// reply = accessManager.post(request, data);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
// connect(reply, &QNetworkReply::finished, this,
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
//}
// void QvHttpRequestHelper::put(const QString &url, const QByteArray &data)
// void QvHttpRequestHelper::put(const QString &url, const QByteArray
// &data)
// {
// this->setUrl(url);
// request.setRawHeader("Content-Type", "application/json");
// reply = accessManager.put(request, data);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
// connect(reply, &QNetworkReply::finished, this,
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this,
// &QvHttpRequestHelper::onReadyRead);
// }
// void QvHttpRequestHelper::del(const QString &url)
@ -91,26 +103,31 @@ namespace Qv2ray::common
// this->setUrl(url);
// request.setRawHeader("Content-Type", "application/json");
// reply = accessManager.deleteResource(request);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
// connect(reply, &QNetworkReply::finished, this,
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this,
// &QvHttpRequestHelper::onReadyRead);
// }
// void QvHttpRequestHelper::login(const QString &url, const QByteArray &data)
// void QvHttpRequestHelper::login(const QString &url, const QByteArray
// &data)
// {
// this->setUrl(url);
// request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
// reply = accessManager.post(request, data);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
// request.setRawHeader("Content-Type",
// "application/x-www-form-urlencoded"); reply =
// accessManager.post(request, data); connect(reply,
// &QNetworkReply::finished, this,
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this,
// &QvHttpRequestHelper::onReadyRead);
// }
void QvHttpRequestHelper::onRequestFinished_p()
{
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) {
DEBUG(MODULE_NETWORK, "HTTP/2 was used.")
}
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) { DEBUG(MODULE_NETWORK, "HTTP/2 was used.") }
if (reply->error() != QNetworkReply::NoError) {
if (reply->error() != QNetworkReply::NoError)
{
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
LOG(MODULE_NETWORK, "Network request error string: " + error)
QByteArray empty;
@ -125,4 +142,4 @@ namespace Qv2ray::common
DEBUG(MODULE_NETWORK, "A request is now ready read")
this->data += reply->readAll();
}
}
} // namespace Qv2ray::common

View File

@ -18,45 +18,46 @@
#pragma once
#include <QObject>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QObject>
namespace Qv2ray::common
{
class QvHttpRequestHelper : public QObject
{
Q_OBJECT
public:
explicit QvHttpRequestHelper();
~QvHttpRequestHelper();
bool setUrl(const QString &url);
void setHeader(const QByteArray &key, const QByteArray &value);
// get
QByteArray syncget(const QString &url, bool useProxy);
void get(const QString &url);
//// insert
//void post(const QString &url, const QByteArray &data);
//// update
//void put(const QString &url, const QByteArray &data);
//// delete
//void del(const QString &url);
//void login(const QString &url, const QByteArray &data);
signals:
void httpRequestFinished(QByteArray &data);
Q_OBJECT
public:
explicit QvHttpRequestHelper();
~QvHttpRequestHelper();
bool setUrl(const QString &url);
void setHeader(const QByteArray &key, const QByteArray &value);
// get
QByteArray syncget(const QString &url, bool useProxy);
void get(const QString &url);
//// insert
// void post(const QString &url, const QByteArray &data);
//// update
// void put(const QString &url, const QByteArray &data);
//// delete
// void del(const QString &url);
// void login(const QString &url, const QByteArray &data);
signals:
void httpRequestFinished(QByteArray &data);
public slots:
void onRequestFinished_p();
private slots:
void onReadyRead();
private:
QByteArray data;
QUrl url;
QNetworkReply *reply;
QNetworkRequest request;
QNetworkAccessManager accessManager;
public slots:
void onRequestFinished_p();
private slots:
void onReadyRead();
private:
QByteArray data;
QUrl url;
QNetworkReply *reply;
QNetworkRequest request;
QNetworkAccessManager accessManager;
};
}
} // namespace Qv2ray::common
using namespace Qv2ray::common;

View File

@ -1,30 +1,32 @@
#include "LogHighlighter.hpp"
#include "common/QvHelpers.hpp"
#define TO_EOL "(([\\s\\S]*)|([\\d\\D]*)|([\\w\\W]*))$"
namespace Qv2ray::common
{
SyntaxHighlighter::SyntaxHighlighter(bool darkMode, QTextDocument *parent)
: QSyntaxHighlighter(parent)
SyntaxHighlighter::SyntaxHighlighter(bool darkMode, QTextDocument *parent) : QSyntaxHighlighter(parent)
{
HighlightingRule rule;
keywordFormat.setForeground(darkMode ? Qt::darkMagenta : Qt::magenta);
keywordFormat.setFontWeight(QFont::Bold);
const QString keywordPatterns[] = {
"tcp", "udp"
};
const QString keywordPatterns[] = { "tcp", "udp" };
for (const QString &pattern : keywordPatterns) {
for (const QString &pattern : keywordPatterns)
{
rule.pattern = QRegularExpression(pattern);
rule.format = keywordFormat;
highlightingRules.append(rule);
}
if (darkMode) {
if (darkMode)
{
ipHostFormat.setForeground(Qt::yellow);
warningFormat.setForeground(QColor(230, 180, 0));
} else {
}
else
{
ipHostFormat.setForeground(Qt::black);
ipHostFormat.setFontWeight(QFont::Bold);
warningFormat.setForeground(Qt::white);
@ -49,7 +51,7 @@ namespace Qv2ray::common
rule.format = debugFormat;
highlightingRules.append(rule);
//
infoFormat.setForeground(darkMode ? Qt::lightGray : Qt::darkCyan);
infoFormat.setForeground(darkMode ? Qt::lightGray : Qt::darkCyan);
rule.pattern = QRegularExpression("\\[[Ii]nfo\\]" TO_EOL);
rule.format = infoFormat;
highlightingRules.append(rule);
@ -119,10 +121,12 @@ namespace Qv2ray::common
void SyntaxHighlighter::highlightBlock(const QString &text)
{
for (const HighlightingRule &rule : qAsConst(highlightingRules)) {
for (const HighlightingRule &rule : qAsConst(highlightingRules))
{
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext()) {
while (matchIterator.hasNext())
{
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
@ -130,4 +134,4 @@ namespace Qv2ray::common
setCurrentBlockState(0);
}
}
} // namespace Qv2ray::common

View File

@ -49,45 +49,46 @@
****************************************************************************/
#pragma once
#include <QRegularExpression>
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include <QRegularExpression>
#include <QTextDocument>
namespace Qv2ray::common
{
class SyntaxHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
Q_OBJECT
public:
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
public:
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
protected:
void highlightBlock(const QString &text) override;
protected:
void highlightBlock(const QString &text) override;
private:
struct HighlightingRule {
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
private:
struct HighlightingRule
{
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
QTextCharFormat keywordFormat;
QTextCharFormat dateFormat;
QTextCharFormat acceptedFormat;
QTextCharFormat rejectedFormat;
QTextCharFormat failedFormat;
QTextCharFormat warningFormat;
QTextCharFormat infoFormat;
QTextCharFormat debugFormat;
QTextCharFormat timeFormat;
QTextCharFormat ipHostFormat;
QTextCharFormat v2rayComponentFormat;
//
QTextCharFormat qvAppLogFormat;
QTextCharFormat qvAppDebugLogFormat;
QTextCharFormat keywordFormat;
QTextCharFormat dateFormat;
QTextCharFormat acceptedFormat;
QTextCharFormat rejectedFormat;
QTextCharFormat failedFormat;
QTextCharFormat warningFormat;
QTextCharFormat infoFormat;
QTextCharFormat debugFormat;
QTextCharFormat timeFormat;
QTextCharFormat ipHostFormat;
QTextCharFormat v2rayComponentFormat;
//
QTextCharFormat qvAppLogFormat;
QTextCharFormat qvAppDebugLogFormat;
};
}
} // namespace Qv2ray::common
using namespace Qv2ray::common;

View File

@ -10,8 +10,8 @@
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -23,10 +23,10 @@
*/
#include "QJsonModel.hpp"
#include <QFile>
#include <QDebug>
#include <QFont>
#include <QDebug>
#include <QFile>
#include <QFont>
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
{
@ -60,8 +60,7 @@ int QJsonTreeItem::childCount() const
int QJsonTreeItem::row() const
{
if (mParent)
return mParent->mChilds.indexOf(const_cast<QJsonTreeItem *>(this));
if (mParent) return mParent->mChilds.indexOf(const_cast<QJsonTreeItem *>(this));
return 0;
}
@ -101,27 +100,34 @@ QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *paren
QJsonTreeItem *rootItem = new QJsonTreeItem(parent);
rootItem->setKey("root");
if (value.isObject()) {
//Get all QJsonValue childs
for (QString key : value.toObject().keys()) {
if (value.isObject())
{
// Get all QJsonValue childs
for (QString key : value.toObject().keys())
{
QJsonValue v = value.toObject().value(key);
QJsonTreeItem *child = load(v, rootItem);
child->setKey(key);
child->setType(v.type());
rootItem->appendChild(child);
}
} else if (value.isArray()) {
//Get all QJsonValue childs
}
else if (value.isArray())
{
// Get all QJsonValue childs
int index = 0;
for (QJsonValue v : value.toArray()) {
for (QJsonValue v : value.toArray())
{
QJsonTreeItem *child = load(v, rootItem);
child->setKey(QString::number(index));
child->setType(v.type());
rootItem->appendChild(child);
++index;
}
} else {
}
else
{
rootItem->setValue(value.toVariant().toString());
rootItem->setType(value.type());
}
@ -131,35 +137,27 @@ QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *paren
//=========================================================================
QJsonModel::QJsonModel(QObject *parent)
: QAbstractItemModel(parent)
, mRootItem{new QJsonTreeItem}
QJsonModel::QJsonModel(QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
{
mHeaders.append("key");
mHeaders.append("value");
}
QJsonModel::QJsonModel(const QString &fileName, QObject *parent)
: QAbstractItemModel(parent)
, mRootItem{new QJsonTreeItem}
QJsonModel::QJsonModel(const QString &fileName, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
{
mHeaders.append("key");
mHeaders.append("value");
load(fileName);
}
QJsonModel::QJsonModel(QIODevice *device, QObject *parent)
: QAbstractItemModel(parent)
, mRootItem{new QJsonTreeItem}
QJsonModel::QJsonModel(QIODevice *device, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
{
mHeaders.append("key");
mHeaders.append("value");
load(device);
}
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent)
: QAbstractItemModel(parent)
, mRootItem{new QJsonTreeItem}
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
{
mHeaders.append("key");
mHeaders.append("value");
@ -176,10 +174,13 @@ bool QJsonModel::load(const QString &fileName)
QFile file(fileName);
bool success = false;
if (file.open(QIODevice::ReadOnly)) {
if (file.open(QIODevice::ReadOnly))
{
success = load(&file);
file.close();
} else success = false;
}
else
success = false;
return success;
}
@ -193,14 +194,18 @@ bool QJsonModel::loadJson(const QByteArray &json)
{
auto const &jdoc = QJsonDocument::fromJson(json);
if (!jdoc.isNull()) {
if (!jdoc.isNull())
{
beginResetModel();
delete mRootItem;
if (jdoc.isArray()) {
if (jdoc.isArray())
{
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.array()));
mRootItem->setType(QJsonValue::Array);
} else {
}
else
{
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.object()));
mRootItem->setType(QJsonValue::Object);
}
@ -213,24 +218,21 @@ bool QJsonModel::loadJson(const QByteArray &json)
return false;
}
QVariant QJsonModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (!index.isValid()) return QVariant();
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
if (role == Qt::DisplayRole) {
if (index.column() == 0)
return QString("%1").arg(item->key());
if (role == Qt::DisplayRole)
{
if (index.column() == 0) return QString("%1").arg(item->key());
if (index.column() == 1)
return QString("%1").arg(item->value());
} else if (Qt::EditRole == role) {
if (index.column() == 1) {
return QString("%1").arg(item->value());
}
if (index.column() == 1) return QString("%1").arg(item->value());
}
else if (Qt::EditRole == role)
{
if (index.column() == 1) { return QString("%1").arg(item->value()); }
}
return QVariant();
@ -240,11 +242,13 @@ bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int ro
{
int col = index.column();
if (Qt::EditRole == role) {
if (col == 1) {
if (Qt::EditRole == role)
{
if (col == 1)
{
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
item->setValue(value.toString());
emit dataChanged(index, index, {Qt::EditRole});
emit dataChanged(index, index, { Qt::EditRole });
return true;
}
}
@ -252,49 +256,40 @@ bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int ro
return false;
}
QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (role != Qt::DisplayRole) return QVariant();
if (orientation == Qt::Horizontal) {
return mHeaders.value(section);
} else
if (orientation == Qt::Horizontal) { return mHeaders.value(section); }
else
return QVariant();
}
QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
if (!hasIndex(row, column, parent)) return QModelIndex();
QJsonTreeItem *parentItem;
if (!parent.isValid())
parentItem = mRootItem;
if (!parent.isValid()) parentItem = mRootItem;
else
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
QJsonTreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
if (childItem) return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex QJsonModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
if (!index.isValid()) return QModelIndex();
QJsonTreeItem *childItem = static_cast<QJsonTreeItem *>(index.internalPointer());
QJsonTreeItem *parentItem = childItem->parent();
if (parentItem == mRootItem)
return QModelIndex();
if (parentItem == mRootItem) return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
@ -303,11 +298,9 @@ int QJsonModel::rowCount(const QModelIndex &parent) const
{
QJsonTreeItem *parentItem;
if (parent.column() > 0)
return 0;
if (parent.column() > 0) return 0;
if (!parent.isValid())
parentItem = mRootItem;
if (!parent.isValid()) parentItem = mRootItem;
else
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
@ -322,14 +315,14 @@ int QJsonModel::columnCount(const QModelIndex &parent) const
Qt::ItemFlags QJsonModel::flags(const QModelIndex &index) const
{
int col = index.column();
int col = index.column();
auto item = static_cast<QJsonTreeItem *>(index.internalPointer());
auto isArray = QJsonValue::Array == item->type();
auto isObject = QJsonValue::Object == item->type();
if ((col == 1) && !(isArray || isObject)) {
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
} else {
if ((col == 1) && !(isArray || isObject)) { return Qt::ItemIsEditable | QAbstractItemModel::flags(index); }
else
{
return QAbstractItemModel::flags(index);
}
}
@ -339,40 +332,47 @@ QJsonDocument QJsonModel::json() const
auto v = genJson(mRootItem);
QJsonDocument doc;
if (v.isObject()) {
doc = QJsonDocument(v.toObject());
} else {
if (v.isObject()) { doc = QJsonDocument(v.toObject()); }
else
{
doc = QJsonDocument(v.toArray());
}
return doc;
}
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const
{
auto type = item->type();
int nchild = item->childCount();
auto type = item->type();
int nchild = item->childCount();
if (QJsonValue::Object == type) {
if (QJsonValue::Object == type)
{
QJsonObject jo;
for (int i = 0; i < nchild; ++i) {
for (int i = 0; i < nchild; ++i)
{
auto ch = item->child(i);
auto key = ch->key();
jo.insert(key, genJson(ch));
}
return jo;
} else if (QJsonValue::Array == type) {
return jo;
}
else if (QJsonValue::Array == type)
{
QJsonArray arr;
for (int i = 0; i < nchild; ++i) {
for (int i = 0; i < nchild; ++i)
{
auto ch = item->child(i);
arr.append(genJson(ch));
}
return arr;
} else {
}
else
{
QJsonValue va(item->value());
return va;
}

View File

@ -1,101 +1,94 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2011 SCHUTZ Sacha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
* The MIT License (MIT)
*
* Copyright (c) 2011 SCHUTZ Sacha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <QAbstractItemModel>
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonArray>
#include <QJsonObject>
#include <QIcon>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
class QJsonModel;
class QJsonItem;
class QJsonTreeItem
{
public:
QJsonTreeItem(QJsonTreeItem *parent = nullptr);
~QJsonTreeItem();
void appendChild(QJsonTreeItem *item);
QJsonTreeItem *child(int row);
QJsonTreeItem *parent();
int childCount() const;
int row() const;
void setKey(const QString &key);
void setValue(const QString &value);
void setType(const QJsonValue::Type &type);
QString key() const;
QString value() const;
QJsonValue::Type type() const;
static QJsonTreeItem *load(const QJsonValue &value, QJsonTreeItem *parent = 0);
protected:
private:
QString mKey;
QString mValue;
QJsonValue::Type mType;
QList<QJsonTreeItem *> mChilds;
QJsonTreeItem *mParent;
public:
QJsonTreeItem(QJsonTreeItem *parent = nullptr);
~QJsonTreeItem();
void appendChild(QJsonTreeItem *item);
QJsonTreeItem *child(int row);
QJsonTreeItem *parent();
int childCount() const;
int row() const;
void setKey(const QString &key);
void setValue(const QString &value);
void setType(const QJsonValue::Type &type);
QString key() const;
QString value() const;
QJsonValue::Type type() const;
static QJsonTreeItem *load(const QJsonValue &value, QJsonTreeItem *parent = 0);
protected:
private:
QString mKey;
QString mValue;
QJsonValue::Type mType;
QList<QJsonTreeItem *> mChilds;
QJsonTreeItem *mParent;
};
//---------------------------------------------------
class QJsonModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit QJsonModel(QObject *parent = nullptr);
QJsonModel(const QString &fileName, QObject *parent = nullptr);
QJsonModel(QIODevice *device, QObject *parent = nullptr);
QJsonModel(const QByteArray &json, QObject *parent = nullptr);
~QJsonModel();
bool load(const QString &fileName);
bool load(QIODevice *device);
bool loadJson(const QByteArray &json);
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QJsonDocument json() const;
private:
QJsonValue genJson(QJsonTreeItem *) const;
QJsonTreeItem *mRootItem;
QStringList mHeaders;
Q_OBJECT
public:
explicit QJsonModel(QObject *parent = nullptr);
QJsonModel(const QString &fileName, QObject *parent = nullptr);
QJsonModel(QIODevice *device, QObject *parent = nullptr);
QJsonModel(const QByteArray &json, QObject *parent = nullptr);
~QJsonModel();
bool load(const QString &fileName);
bool load(QIODevice *device);
bool loadJson(const QByteArray &json);
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QJsonDocument json() const;
private:
QJsonValue genJson(QJsonTreeItem *) const;
QJsonTreeItem *mRootItem;
QStringList mHeaders;
};

View File

@ -1,4 +1,5 @@
#include "common/QvHelpers.hpp"
#include <QQueue>
namespace Qv2ray::common
@ -8,7 +9,8 @@ namespace Qv2ray::common
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString randomString;
for (int i = 0; i < len; ++i) {
for (int i = 0; i < len; ++i)
{
uint rand = QRandomGenerator::system()->generate();
uint max = static_cast<uint>(possibleCharacters.length());
QChar nextChar = possibleCharacters[rand % max];
@ -73,9 +75,9 @@ namespace Qv2ray::common
QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error);
Q_UNUSED(doc)
if (error.error == QJsonParseError::NoError) {
return "";
} else {
if (error.error == QJsonParseError::NoError) { return ""; }
else
{
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString())
return error.errorString();
}
@ -108,16 +110,16 @@ namespace Qv2ray::common
{
list<string> list;
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) {
list.push_back(line.toStdString());
}
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) { list.push_back(line.toStdString()); }
return list;
}
QStringList GetFileList(QDir dir)
{
return dir.entryList(QStringList() << "*" << "*.*", QDir::Hidden | QDir::Files);
return dir.entryList(QStringList() << "*"
<< "*.*",
QDir::Hidden | QDir::Files);
}
bool FileExistsIn(QDir dir, QString fileName)
@ -147,8 +149,7 @@ namespace Qv2ray::common
int i;
double dblByte = bytes;
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024)
dblByte = bytes / 1024.0;
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024) dblByte = bytes / 1024.0;
sprintf(str, "%.2f", dblByte);
return QString(str) + " " + QString(sizes[i]);
@ -163,9 +164,8 @@ namespace Qv2ray::common
QString RemoveInvalidFileName(const QString &fileName)
{
std::string _name = fileName.toStdString();
std::replace_if(_name.begin(), _name.end(), [](char c) {
return std::string::npos != string(R"("/\?%&^*;:|><)").find(c);
}, '_');
std::replace_if(
_name.begin(), _name.end(), [](char c) { return std::string::npos != string(R"("/\?%&^*;:|><)").find(c); }, '_');
return QString::fromStdString(_name);
}
@ -174,20 +174,25 @@ namespace Qv2ray::common
{
int i = 1;
if (!QDir(baseDir).exists()) {
if (!QDir(baseDir).exists())
{
QDir(baseDir).mkpath(baseDir);
LOG(MODULE_FILEIO, "Making path: " + baseDir)
}
while (true) {
if (!QFile(baseDir + "/" + fileName + "_" + QSTRN(i) + extension).exists()) {
while (true)
{
if (!QFile(baseDir + "/" + fileName + "_" + QSTRN(i) + extension).exists())
{
*fileName = *fileName + "_" + QSTRN(i);
return;
} else {
}
else
{
DEBUG(MODULE_FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists")
}
i++;
}
}
}
} // namespace Qv2ray::common

View File

@ -1,10 +1,13 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include <QMessageBox>
#define REGEX_IPV6_ADDR R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])"
#define REGEX_IPV4_ADDR R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))"
#define REGEX_IPV6_ADDR \
R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])"
#define REGEX_IPV4_ADDR \
R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))"
#define REGEX_PORT_NUMBER R"(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])*)"
namespace Qv2ray::common
@ -19,7 +22,8 @@ namespace Qv2ray::common
//
void QvMessageBoxWarn(QWidget *parent, QString title, QString text);
void QvMessageBoxInfo(QWidget *parent, QString title, QString text);
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons = QMessageBox::NoButton);
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, QString title, QString text,
QMessageBox::StandardButton extraButtons = QMessageBox::NoButton);
//
QString StringFromFile(const QString &filePath);
QString StringFromFile(QFile *source);
@ -40,16 +44,16 @@ namespace Qv2ray::common
inline QString GenerateUuid()
{
return GenerateRandomString().toLower();
//return QUuid::createUuid().toString(QUuid::WithoutBraces);
// return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
//
template <typename TYPE>
template<typename TYPE>
QString StructToJsonString(const TYPE t)
{
return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' '));
}
//
template <typename TYPE>
template<typename TYPE>
TYPE StructFromJsonString(const QString &str)
{
TYPE v;
@ -68,9 +72,7 @@ namespace Qv2ray::common
{
QString t = str;
t.truncate(limit);
return (limit == -1 || str.length() < limit)
? str
: (t + suffix);
return (limit == -1 || str.length() < limit) ? str : (t + suffix);
}
namespace validation
@ -92,7 +94,7 @@ namespace Qv2ray::common
{
return IsIPv4Address(addr) || IsIPv6Address(addr);
}
}
} // namespace validation
inline QString timeToString(const time_t &t)
{
@ -102,6 +104,6 @@ namespace Qv2ray::common
strftime(MY_TIME, sizeof(MY_TIME), "%x - %I:%M%p", _tm);
return QString(MY_TIME);
}
}
} // namespace Qv2ray::common
using namespace Qv2ray::common;

View File

@ -7,15 +7,15 @@ namespace Qv2ray::common
{
class QvTranslator
{
public:
QvTranslator(const QString &lang)
{
QTranslator *translator = new QTranslator();
translator->load(lang + ".qm", ":/translations/");
this->pTranslator.reset(translator);
}
public:
QvTranslator(const QString &lang)
{
QTranslator *translator = new QTranslator();
translator->load(lang + ".qm", ":/translations/");
this->pTranslator.reset(translator);
}
public:
std::unique_ptr<QTranslator> pTranslator;
public:
std::unique_ptr<QTranslator> pTranslator;
};
} // namespace Qv2ray::common

View File

@ -1,13 +1,14 @@
#include "QvAutoLaunch.hpp"
#include <QSettings>
#include <QApplication>
#include <QDir>
#include <QSettings>
#include <QStandardPaths>
#include <QTextStream>
// macOS headers (possibly OBJ-c)
#if defined(Q_OS_MAC)
#include <CoreServices/CoreServices.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#endif
namespace Qv2ray::components::autolaunch
{
@ -34,8 +35,10 @@ namespace Qv2ray::components::autolaunch
}
#elif defined Q_OS_MAC
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
// this is quite some duplicate code with setLaunchOnStartup, at some point we should fix this FIXME.
// From
// https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
// this is quite some duplicate code with setLaunchOnStartup, at some
// point we should fix this FIXME.
bool returnValue = false;
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
@ -49,16 +52,16 @@ namespace Qv2ray::components::autolaunch
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
CFStringRef appUrlRefString = CFURLGetString(urlRef); // no need for release
for (int i = 0; i < CFArrayGetCount(itemsArray); i++) {
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(itemsArray, i);
for (int i = 0; i < CFArrayGetCount(itemsArray); i++)
{
LSSharedFileListItemRef item = (LSSharedFileListItemRef) CFArrayGetValueAtIndex(itemsArray, i);
CFURLRef itemUrlRef = NULL;
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef) {
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef)
{
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) {
returnValue = true;
}
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) { returnValue = true; }
CFRelease(itemUrlRef);
}
@ -86,16 +89,20 @@ namespace Qv2ray::components::autolaunch
QString appName = QApplication::applicationName();
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
if (enable) {
if (enable)
{
QString strAppPath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
reg.setValue(appName, strAppPath);
} else {
}
else
{
reg.remove(appName);
}
}
#elif defined Q_OS_MAC
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
// From
// https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
CFURLRef urlRef = CFURLCreateWithFileSystemPath(0, folderCFStr, kCFURLPOSIXPathStyle, true);
@ -103,30 +110,31 @@ namespace Qv2ray::components::autolaunch
if (loginItems && enable)
{
//Insert an item to the list.
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems,
kLSSharedFileListItemLast, 0, 0,
urlRef, 0, 0);
// Insert an item to the list.
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, 0, 0, urlRef, 0, 0);
if (item)
CFRelease(item);
if (item) CFRelease(item);
CFRelease(loginItems);
} else if (loginItems && !enable)
}
else if (loginItems && !enable)
{
// We need to iterate over the items and check which one is "ours".
UInt32 seedValue;
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
CFStringRef appUrlRefString = CFURLGetString(urlRef);
for (int i = 0; i < CFArrayGetCount(itemsArray); i++) {
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(itemsArray, i);
for (int i = 0; i < CFArrayGetCount(itemsArray); i++)
{
LSSharedFileListItemRef item = (LSSharedFileListItemRef) CFArrayGetValueAtIndex(itemsArray, i);
CFURLRef itemUrlRef = NULL;
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef) {
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef)
{
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) {
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo)
{
LSSharedFileListItemRemove(loginItems, item); // remove it!
}
@ -143,22 +151,27 @@ namespace Qv2ray::components::autolaunch
}
#elif defined Q_OS_LINUX
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_unix.cpp
// From
// https://github.com/nextcloud/desktop/blob/master/src/common/utility_unix.cpp
QString appName = QApplication::applicationName();
QString userAutoStartPath = getUserAutostartDir_private();
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
if (enable)
{
if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath)) {
// qCWarning(lcUtility) << "Could not create autostart folder" << userAutoStartPath;
if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath))
{
// qCWarning(lcUtility) << "Could not create autostart folder"
// << userAutoStartPath;
return;
}
QFile iniFile(desktopFileLocation);
if (!iniFile.open(QIODevice::WriteOnly)) {
// qCWarning(lcUtility) << "Could not write auto start entry" << desktopFileLocation;
if (!iniFile.open(QIODevice::WriteOnly))
{
// qCWarning(lcUtility) << "Could not write auto start entry" <<
// desktopFileLocation;
return;
}
@ -174,13 +187,15 @@ namespace Qv2ray::components::autolaunch
<< QLatin1String("Type=") << "Application" << endl
<< QLatin1String("StartupNotify=") << "false" << endl
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl;
} else
}
else
{
if (!QFile::remove(desktopFileLocation)) {
// qCWarning(lcUtility) << "Could not remove autostart desktop file";
if (!QFile::remove(desktopFileLocation))
{
// qCWarning(lcUtility) << "Could not remove autostart desktop
// file";
}
}
}
#endif
}
} // namespace Qv2ray::components::autolaunch

View File

@ -4,7 +4,7 @@ namespace Qv2ray::components::autolaunch
{
bool GetLaunchAtLoginStatus();
void SetLaunchAtLoginStatus(bool enable);
}
} // namespace Qv2ray::components::autolaunch
using namespace Qv2ray::components;
using namespace Qv2ray::components::autolaunch;

View File

@ -1,4 +1,5 @@
#include "QvGeositeReader.hpp"
#include "libs/gen/v2ray_geosite.pb.h"
namespace Qv2ray::components::geosite
@ -13,7 +14,8 @@ namespace Qv2ray::components::geosite
QFile f(filepath);
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
if (!opened) {
if (!opened)
{
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
return list;
}
@ -24,7 +26,8 @@ namespace Qv2ray::components::geosite
GeoSiteList sites;
sites.ParseFromArray(content.data(), content.size());
for (auto e : sites.entry()) {
for (auto e : sites.entry())
{
// We want to use lower string.
list << QString::fromStdString(e.country_code()).toLower();
}
@ -34,4 +37,4 @@ namespace Qv2ray::components::geosite
google::protobuf::ShutdownProtobufLibrary();
return list;
}
}
} // namespace Qv2ray::components::geosite

View File

@ -1,41 +1,38 @@
#include "ICMPPinger.hpp"
ICMPPinger::ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT) {
ICMPPinger::ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT)
{
// create icmp handle
if ((this->hIcmpFile = IcmpCreateFile()) == INVALID_HANDLE_VALUE) {
throw "IcmpCreateFile failed";
}
if ((this->hIcmpFile = IcmpCreateFile()) == INVALID_HANDLE_VALUE) { throw "IcmpCreateFile failed"; }
// remember the timeout
this->timeout = timeout;
}
ICMPPinger::~ICMPPinger() {
ICMPPinger::~ICMPPinger()
{
// release the handle on destruction
IcmpCloseHandle(this->hIcmpFile);
}
std::pair<std::optional<UINT64>, std::optional<std::string>> ICMPPinger::ping(const std::string& ipAddr) {
std::pair<std::optional<UINT64>, std::optional<std::string>> ICMPPinger::ping(const std::string &ipAddr)
{
// convert network address
const auto addr = inet_addr(ipAddr.c_str());
if (addr == INADDR_NONE) {
return std::pair(std::nullopt, "invalid ip address: " + ipAddr);
}
if (addr == INADDR_NONE) { return std::pair(std::nullopt, "invalid ip address: " + ipAddr); }
// request buffer
const static char bufRequest[] = "echo test";
// response buffer
const auto responseSize = sizeof(ICMP_ECHO_REPLY) + sizeof(bufRequest);
const std::unique_ptr<char> bufRecv(new(char[responseSize]));
const std::unique_ptr<char> bufRecv(new (char[responseSize]));
// send echo
auto ret = IcmpSendEcho(this->hIcmpFile, addr, (LPVOID)bufRequest, sizeof(bufRequest), NULL, bufRecv.get(), responseSize, this->timeout);
auto ret = IcmpSendEcho(this->hIcmpFile, addr, (LPVOID) bufRequest, sizeof(bufRequest), NULL, bufRecv.get(), responseSize, this->timeout);
// ret == 0: failed
if (ret == 0) {
return std::pair(std::nullopt, "IcmpSendEcho returned error");
}
if (ret == 0) { return std::pair(std::nullopt, "IcmpSendEcho returned error"); }
// read round-trip time
PICMP_ECHO_REPLY pReply = (PICMP_ECHO_REPLY) bufRecv.get();

View File

@ -6,27 +6,26 @@
* License: WTFPL
*/
#include<winsock2.h>
#include<iphlpapi.h>
#include<icmpapi.h>
#include <icmpapi.h>
#include <iphlpapi.h>
#include <memory>
#include <optional>
#include <utility>
#include <winsock2.h>
#include<utility>
#include<optional>
#include<memory>
class ICMPPinger
{
public:
ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT);
~ICMPPinger();
public:
static const UINT64 DEFAULT_TIMEOUT = 10000U;
class ICMPPinger {
public:
ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT);
~ICMPPinger();
public:
std::pair<std::optional<UINT64>, std::optional<std::string>> ping(const std::string &ipAddr);
public:
static const UINT64 DEFAULT_TIMEOUT = 10000U;
public:
std::pair<std::optional<UINT64>, std::optional<std::string>> ping(const std::string& ipAddr);
private:
HANDLE hIcmpFile;
UINT64 timeout = DEFAULT_TIMEOUT;
private:
HANDLE hIcmpFile;
UINT64 timeout = DEFAULT_TIMEOUT;
};

View File

@ -21,29 +21,23 @@ namespace Qv2ray::components::pac
bool passRule1 = originLine.find("|") != string::npos; // Proxy Lines
bool passRule2 = originLine.find(".") != string::npos; // Link-Contained Lines
if (originLine[endPosition] == '\n') {
endPosition -= 1;
}
if (originLine[endPosition] == '\n') { endPosition -= 1; }
if (originLine.find("http://") != string::npos) {
startPosition += 8;
} else if (originLine.find("https://") != string::npos) {
if (originLine.find("http://") != string::npos) { startPosition += 8; }
else if (originLine.find("https://") != string::npos)
{
startPosition += 9;
}
// Skip unrelated lines
if (skipRule1 || skipRule2 || skipRule3 || skipRule4) {
return "";
} else if (passRule2) {
if (passRule1) {
startPosition += originLine.find_last_of("|") + 1;
}
if (skipRule1 || skipRule2 || skipRule3 || skipRule4) { return ""; }
else if (passRule2)
{
if (passRule1) { startPosition += originLine.find_last_of("|") + 1; }
if (originLine[startPosition] == '\n') startPosition += 1;
for (size_t i = startPosition; i < endPosition; ++i) {
returnBuffer += originLine[i];
}
for (size_t i = startPosition; i < endPosition; ++i) { returnBuffer += originLine[i]; }
}
return returnBuffer;
@ -52,19 +46,19 @@ namespace Qv2ray::components::pac
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString)
{
auto rawFileContent = Base64Decode(rawContent).toStdString();
string readBuffer = ""; //cleanup
string readBuffer = ""; // cleanup
string writeBuffer;
string domainListCache = "";
for (size_t i = 0; i < rawFileContent.size(); ++i) {
for (size_t i = 0; i < rawFileContent.size(); ++i)
{
readBuffer += rawFileContent[i];
if (rawFileContent[i + 1] == '\n') {
if (rawFileContent[i + 1] == '\n')
{
writeBuffer = getRawDomain(readBuffer);
if (writeBuffer != "") {
domainListCache += writeBuffer + "\n";
}
if (writeBuffer != "") { domainListCache += writeBuffer + "\n"; }
readBuffer = "";
i += 1;
@ -72,19 +66,22 @@ namespace Qv2ray::components::pac
}
size_t rotatorTwo = 0;
string readDomainBuffer = "";
string readDomainBuffer = "";
bool isFirstLine = true;
string outputContent = "";
//Header
// Header
outputContent += "var domains = {\n";
//Read and process output content line by line
while (rotatorTwo < domainListCache.size()) {
while (true) {
//Get Domain
// Read and process output content line by line
while (rotatorTwo < domainListCache.size())
{
while (true)
{
// Get Domain
readDomainBuffer += domainListCache[rotatorTwo];
if (domainListCache[rotatorTwo + 1] == '\n') {
if (domainListCache[rotatorTwo + 1] == '\n')
{
rotatorTwo += 2;
break;
}
@ -92,9 +89,10 @@ namespace Qv2ray::components::pac
rotatorTwo++;
}
//Format
// Format
if (!isFirstLine) outputContent += ",\n";
else isFirstLine = false;
else
isFirstLine = false;
outputContent += "\t\"";
outputContent += readDomainBuffer;
@ -102,32 +100,18 @@ namespace Qv2ray::components::pac
readDomainBuffer = "";
}
//End Message
outputContent +=
NEWLINE "};"
NEWLINE ""
NEWLINE " var proxy = \"" + customProxyString.toStdString() + ";\";" +
NEWLINE " var direct = 'DIRECT;';"
NEWLINE " function FindProxyForURL(url, host) {"
NEWLINE " var suffix;"
NEWLINE " var pos = host.lastIndexOf('.');"
NEWLINE " pos = host.lastIndexOf('.', pos - 1);"
NEWLINE " //"
NEWLINE " while (1) {"
NEWLINE " if (domains[host] != undefined) {"
NEWLINE " return proxy;"
NEWLINE " }"
NEWLINE " else if (pos <= 0) {"
NEWLINE " return domains['.' + host] != undefined ? proxy : direct;"
NEWLINE " }"
NEWLINE " suffix = host.substring(pos);"
NEWLINE " if (domains[suffix] != undefined) {"
NEWLINE " return proxy;"
NEWLINE " }"
NEWLINE " pos = host.lastIndexOf('.', pos - 1);"
NEWLINE " }"
NEWLINE " }";
// End Message
outputContent += NEWLINE "};" NEWLINE "" NEWLINE " var proxy = \"" + customProxyString.toStdString() + ";\";" +
NEWLINE " var direct = 'DIRECT;';" NEWLINE " function FindProxyForURL(url, host) {" NEWLINE
" var suffix;" NEWLINE " var pos = host.lastIndexOf('.');" NEWLINE
" pos = host.lastIndexOf('.', pos - 1);" NEWLINE " //" NEWLINE " while (1) {" NEWLINE
" if (domains[host] != undefined) {" NEWLINE " return proxy;" NEWLINE
" }" NEWLINE " else if (pos <= 0) {" NEWLINE
" return domains['.' + host] != undefined ? proxy : direct;" NEWLINE " }" NEWLINE
" suffix = host.substring(pos);" NEWLINE " if (domains[suffix] != undefined) {" NEWLINE
" return proxy;" NEWLINE " }" NEWLINE
" pos = host.lastIndexOf('.', pos - 1);" NEWLINE " }" NEWLINE " }";
//
return QString::fromStdString(outputContent);
}
}
} // namespace Qv2ray::components::pac

View File

@ -1,8 +1,9 @@
#include "QvPACHandler.hpp"
#include "common/QvHelpers.hpp"
#include "core/CoreUtils.hpp"
#include "qhttprequest.h"
#include "qhttpresponse.h"
#include "core/CoreUtils.hpp"
#include "common/QvHelpers.hpp"
namespace Qv2ray::components::pac
{
@ -13,9 +14,7 @@ namespace Qv2ray::components::pac
}
PACServer::~PACServer()
{
if (isStarted) {
pacServer.close();
}
if (isStarted) { pacServer.close(); }
}
void PACServer::SetProxyString(const QString &proxyString)
{
@ -36,10 +35,13 @@ namespace Qv2ray::components::pac
//
auto result = pacServer.listen(QHostAddress(address), static_cast<ushort>(port));
if (result) {
if (result)
{
isStarted = true;
DEBUG(MODULE_PROXY, "Started PAC handler")
} else {
}
else
{
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"));
}
@ -47,7 +49,8 @@ namespace Qv2ray::components::pac
void PACServer::StopServer()
{
if (isStarted) {
if (isStarted)
{
pacServer.close();
DEBUG(MODULE_PROXY, "PAC Handler stopped.")
isStarted = false;
@ -58,22 +61,28 @@ namespace Qv2ray::components::pac
{
rsp->setHeader("Server", "Qv2ray/" QV2RAY_VERSION_STRING " PAC_Handler");
if (req->method() == QHttpRequest::HTTP_GET) {
if (req->method() == QHttpRequest::HTTP_GET)
{
//
if (req->path() == "/pac") {
if (req->path() == "/pac")
{
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(MODULE_PROXY, "Serving a pac file...")
} else {
}
else
{
rsp->writeHead(QHttpResponse::StatusCode::STATUS_NOT_FOUND);
rsp->end("NOT FOUND");
}
} else {
}
else
{
rsp->writeHead(QHttpResponse::StatusCode::STATUS_METHOD_NOT_ALLOWED);
rsp->end("PAC ONLY SUPPORT GET");
}
}
}
} // namespace Qv2ray::components::pac

View File

@ -1,5 +1,6 @@
#pragma once
#include "qhttpserver.h"
#include <QObject>
#include <memory>
@ -8,26 +9,26 @@ namespace Qv2ray::components::pac
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString);
class PACServer : public QObject
{
Q_OBJECT
public:
explicit PACServer();
~PACServer();
void SetProxyString(const QString &proxyString);
void StartListen();
void StopServer();
Q_OBJECT
public:
explicit PACServer();
~PACServer();
void SetProxyString(const QString &proxyString);
void StartListen();
void StopServer();
QString gfwFilePath;
QString gfwFilePath;
public slots:
void onNewRequest(QHttpRequest *request, QHttpResponse *response);
public slots:
void onNewRequest(QHttpRequest *request, QHttpResponse *response);
private:
bool isStarted;
QHttpServer pacServer;
QString pacContent;
QString proxyString;
private:
bool isStarted;
QHttpServer pacServer;
QString pacContent;
QString proxyString;
};
}
} // namespace Qv2ray::components::pac
using namespace Qv2ray::components;
using namespace Qv2ray::components::pac;

View File

@ -1,7 +1,8 @@
#include <QThread>
#include "ui/w_MainWindow.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "common/QvHelpers.hpp"
#include "ui/w_MainWindow.hpp"
namespace Qv2ray::components::plugins
{
@ -31,118 +32,137 @@ namespace Qv2ray::components::plugins
QString GetAnswerToRequest(const QString &pchRequest)
{
auto instance = MainWindow::mwInstance;
//if (instance == nullptr || instance->vinstance == nullptr) {
// if (instance == nullptr || instance->vinstance == nullptr) {
// LOG(PLUGIN, "MainWindow != nullptr Assertion failed!")
// return "{}";
//}
//
//auto vinstance = instance->vinstance;
// auto vinstance = instance->vinstance;
//
auto req = pchRequest.trimmed();
QString reply = "{}";
if (req == "START") {
emit instance->Connect();
} else if (req == "STOP") {
if (req == "START") { emit instance->Connect(); }
else if (req == "STOP")
{
emit instance->DisConnect();
} else if (req == "RESTART") {
}
else if (req == "RESTART")
{
emit instance->ReConnect();
}
auto BarConfig = GlobalConfig.toolBarConfig;
for (auto i = 0; i < BarConfig.Pages.size(); i++) {
for (auto j = 0; j < BarConfig.Pages[i].Lines.size(); j++) {
for (auto i = 0; i < BarConfig.Pages.size(); i++)
{
for (auto j = 0; j < BarConfig.Pages[i].Lines.size(); j++)
{
#define CL BarConfig.Pages[i].Lines[j]
switch (CL.ContentType) {
case 0: {
switch (CL.ContentType)
{
case 0:
{
// Custom Text
// We do nothing...
break;
}
case 101: {
case 101:
{
// Current Time
CL.Message = QTime().currentTime().toString("hh:mm:ss");
break;
}
case 102: {
case 102:
{
// Current Date
CL.Message = QDate().currentDate().toString("yyyy-MM-dd");
break;
}
case 103: {
case 103:
{
// Current Qv2ray Version
CL.Message = QV2RAY_VERSION_STRING;
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: {
default:
{
CL.Message = "Not Supported?";
break;
}
@ -153,5 +173,5 @@ namespace Qv2ray::components::plugins
reply = StructToJsonString(BarConfig);
return reply;
}
}
}
} // namespace Toolbar
} // namespace Qv2ray::components::plugins

View File

@ -9,25 +9,23 @@ namespace Qv2ray::components::plugins
namespace Toolbar
{
/// NO NOT CHANGE THE ORDER
static const QMap<int, QString> NetSpeedPluginMessages {
{ 0, QObject::tr("Custom Text")},
// Current Status
{ 101, QObject::tr("Current Time") },
{ 102, QObject::tr("Current Date") },
{ 103, QObject::tr("Current Qv2ray Version") },
{ 104, QObject::tr("Current Connection Name") },
{ 105, QObject::tr("Current Connection Status") },
// Speeds
{ 201, QObject::tr("Total Upload Speed") },
{ 202, QObject::tr("Total Download Speed") },
{ 203, QObject::tr("Upload Speed for Specific Tag") },
{ 204, QObject::tr("Download Speed for Specific Tag") },
// Datas
{ 301, QObject::tr("Total Uploaded Data") },
{ 302, QObject::tr("Total Downloaded Data") },
{ 303, QObject::tr("Uploaded Data for Specific Tag") },
{ 304, QObject::tr("Downloaded Data for Specific Tag") }
};
static const QMap<int, QString> NetSpeedPluginMessages{ { 0, QObject::tr("Custom Text") },
// Current Status
{ 101, QObject::tr("Current Time") },
{ 102, QObject::tr("Current Date") },
{ 103, QObject::tr("Current Qv2ray Version") },
{ 104, QObject::tr("Current Connection Name") },
{ 105, QObject::tr("Current Connection Status") },
// Speeds
{ 201, QObject::tr("Total Upload Speed") },
{ 202, QObject::tr("Total Download Speed") },
{ 203, QObject::tr("Upload Speed for Specific Tag") },
{ 204, QObject::tr("Download Speed for Specific Tag") },
// Datas
{ 301, QObject::tr("Total Uploaded Data") },
{ 302, QObject::tr("Total Downloaded Data") },
{ 303, QObject::tr("Uploaded Data for Specific Tag") },
{ 304, QObject::tr("Downloaded Data for Specific Tag") } };
void StartProcessingPlugins();
void StopProcessingPlugins();
#ifdef Q_OS_WIN
@ -35,7 +33,7 @@ namespace Qv2ray::components::plugins
{
void StartNamedPipeThread();
void KillNamedPipeThread();
}
} // namespace _win
#endif
#ifdef Q_OS_LINUX
namespace _linux
@ -45,13 +43,12 @@ namespace Qv2ray::components::plugins
void StartMessageQThread();
void StopMessageQThread();
}
} // namespace _linux
#endif
QString GetAnswerToRequest(const QString &pchRequest);
}
}
} // namespace Toolbar
} // namespace Qv2ray::components::plugins
using namespace Qv2ray::components;
using namespace Qv2ray::components::plugins::Toolbar;

View File

@ -1,9 +1,10 @@
#include <QtCore>
#ifdef Q_OS_LINUX
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "common/QvHelpers.hpp"
#include <QLocalSocket>
#include <QLocalServer>
#include "common/QvHelpers.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include <QLocalServer>
#include <QLocalSocket>
namespace Qv2ray::components::plugins::Toolbar
{
namespace _linux
@ -16,35 +17,43 @@ namespace Qv2ray::components::plugins::Toolbar
{
QLocalSocket *socket = server->nextPendingConnection();
if (!socket->waitForConnected() || !socket->waitForReadyRead())
return;
if (!socket->waitForConnected() || !socket->waitForReadyRead()) return;
try {
while (!isExiting && socket->isOpen() && socket->isValid() && socket->waitForReadyRead()) {
try
{
while (!isExiting && socket->isOpen() && socket->isValid() && socket->waitForReadyRead())
{
// CANNOT PROPERLY READ...
// Temp-ly fixed (but why and how?)
auto in = QString(socket->readAll());
if (!isExiting && !in.isEmpty()) {
if (!isExiting && !in.isEmpty())
{
auto out = GetAnswerToRequest(in);
//
socket->write(out.toUtf8());
socket->flush();
} else {
}
else
{
QThread::msleep(200);
}
}
} catch (...) {
}
catch (...)
{
LOG(MODULE_PLUGIN, "Closing a broken socket.")
}
}
void DataMessageQThread()
{
server = new QLocalServer();
// BUG Sometimes failed to listen due to improper close of last session.
// BUG Sometimes failed to listen due to improper close of last
// session.
bool listening = server->listen(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_LINUX);
while (!isExiting && !listening) {
while (!isExiting && !listening)
{
QThread::msleep(500);
listening = server->listen(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_LINUX);
}
@ -53,7 +62,8 @@ namespace Qv2ray::components::plugins::Toolbar
server->setSocketOptions(QLocalServer::WorldAccessOption);
QObject::connect(server, &QLocalServer::newConnection, &qobject_proxy);
while (!isExiting) {
while (!isExiting)
{
bool result = server->waitForNewConnection(5000, &timeOut);
DEBUG(MODULE_PLUGIN, "Plugin thread listening failed: " + server->errorString())
DEBUG(MODULE_PLUGIN, "waitForNewConnection: " + QString(result ? "true" : "false") + ", " + QString(timeOut ? "true" : "false"))
@ -72,13 +82,14 @@ namespace Qv2ray::components::plugins::Toolbar
{
isExiting = true;
if (linuxWorkerThread->isRunning()) {
if (linuxWorkerThread->isRunning())
{
LOG(MODULE_PLUGIN, "Waiting for linuxWorkerThread to stop.")
linuxWorkerThread->wait();
}
delete _linux::linuxWorkerThread;
}
}
}
} // namespace _linux
} // namespace Qv2ray::components::plugins::Toolbar
#endif

View File

@ -1,8 +1,9 @@
#include <QtCore>
#ifdef Q_OS_WIN
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "common/QvHelpers.hpp"
#include <windows.h>
#include "common/QvHelpers.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include <windows.h>
namespace Qv2ray::components::plugins::Toolbar
{
namespace _win
@ -25,40 +26,53 @@ namespace Qv2ray::components::plugins::Toolbar
{
auto hThread = CreateThread(nullptr, 0, NamedPipeMasterThread, nullptr, 0, nullptr);
if (hThread == nullptr) {
if (hThread == nullptr)
{
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
return;
} else CloseHandle(hThread);
}
else
CloseHandle(hThread);
}
DWORD WINAPI NamedPipeMasterThread(LPVOID lpvParam)
{
Q_UNUSED(lpvParam)
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE;
auto lpszPipename = QString(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_WIN).toStdWString();
while (!isExiting) {
//printf("Pipe Server: Main thread awaiting client connection on %s\n", lpszPipename.c_str());
hPipe = CreateNamedPipe(lpszPipename.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, nullptr);
while (!isExiting)
{
// printf("Pipe Server: Main thread awaiting client connection
// on %s\n", lpszPipename.c_str());
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) {
if (hPipe == INVALID_HANDLE_VALUE)
{
LOG(MODULE_PLUGIN, "CreateNamedPipe failed, GLE=" + QSTRN(GetLastError()))
return static_cast<DWORD>(-1);
}
fConnected = ConnectNamedPipe(hPipe, nullptr) ? true : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected) {
if (fConnected)
{
LOG(MODULE_PLUGIN, "Client connected, creating a processing thread")
ThreadHandle = CreateThread(nullptr, 0, InstanceThread, hPipe, 0, &dwThreadId);
if (ThreadHandle == nullptr) {
if (ThreadHandle == nullptr)
{
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
return static_cast<DWORD>(-1);
} else CloseHandle(ThreadHandle);
} else CloseHandle(hPipe);
}
else
CloseHandle(ThreadHandle);
}
else
CloseHandle(hPipe);
}
return 0;
@ -71,13 +85,16 @@ namespace Qv2ray::components::plugins::Toolbar
HANDLE hPipe = static_cast<HANDLE>(lpvParam);
TCHAR pchRequest[BUFSIZE] = { 0 };
while (!isExiting) {
while (!isExiting)
{
fSuccess = ReadFile(hPipe, pchRequest, BUFSIZE * sizeof(TCHAR), &cbBytesRead, nullptr);
if (!fSuccess || cbBytesRead == 0) {
if (GetLastError() == ERROR_BROKEN_PIPE) {
LOG(MODULE_PLUGIN, "InstanceThread: client disconnected, GLE=" + QSTRN(GetLastError()))
} else {
if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{ LOG(MODULE_PLUGIN, "InstanceThread: client disconnected, GLE=" + QSTRN(GetLastError())) }
else
{
LOG(MODULE_PLUGIN, "InstanceThread ReadFile failed, GLE=" + QSTRN(GetLastError()))
}
@ -87,17 +104,20 @@ namespace Qv2ray::components::plugins::Toolbar
auto req = QString::fromStdWString(pchRequest);
QString replyQString = "{}";
if (!isExiting) {
if (!isExiting)
{
replyQString = GetAnswerToRequest(req);
//
// REPLY as std::string
std::string pchReply = replyQString.toUtf8().constData();
cbReplyBytes = static_cast<DWORD>(pchReply.length() + 1) * sizeof(CHAR);
//cbReplyBytes = static_cast<DWORD>(replyQString.length() + 1) * sizeof(TCHAR);
// cbReplyBytes = static_cast<DWORD>(replyQString.length() +
// 1) * sizeof(TCHAR);
//
fSuccess = WriteFile(hPipe, pchReply.c_str(), cbReplyBytes, &cbWritten, nullptr);
if (!fSuccess || cbReplyBytes != cbWritten) {
if (!fSuccess || cbReplyBytes != cbWritten)
{
LOG(MODULE_PLUGIN, "InstanceThread WriteFile failed, GLE=" + QSTRN(GetLastError()))
break;
}
@ -109,6 +129,6 @@ namespace Qv2ray::components::plugins::Toolbar
CloseHandle(hPipe);
return 1;
}
}
}
} // namespace _win
} // namespace Qv2ray::components::plugins::Toolbar
#endif

View File

@ -1,8 +1,10 @@
#include "QvProxyConfigurator.hpp"
#include "common/QvHelpers.hpp"
#ifdef Q_OS_WIN
#include "wininet.h"
#include <windows.h>
#include "wininet.h"
#include <windows.h>
#endif
namespace Qv2ray::components::proxy
@ -23,11 +25,10 @@ namespace Qv2ray::components::proxy
QStringList result;
// Start from 1 since first line is unneeded.
for (auto i = 1; i < lines.count(); i++) {
for (auto i = 1; i < lines.count(); i++)
{
// * means disabled.
if (!lines[i].contains("*")) {
result << (lines[i].contains(" ") ? "\"" + lines[i] + "\"" : lines[i]);
}
if (!lines[i].contains("*")) { result << (lines[i].contains(" ") ? "\"" + lines[i] + "\"" : lines[i]); }
}
LOG(MODULE_PROXY, "Found " + QSTRN(result.size()) + " network services: " + result.join(";"))
@ -35,8 +36,9 @@ namespace Qv2ray::components::proxy
}
#endif
#ifdef Q_OS_WIN
#define NO_CONST(expr) const_cast<wchar_t *>(expr)
//static auto DEFAULT_CONNECTION_NAME = NO_CONST(L"DefaultConnectionSettings");
#define NO_CONST(expr) const_cast<wchar_t *>(expr)
// static auto DEFAULT_CONNECTION_NAME =
// NO_CONST(L"DefaultConnectionSettings");
///
/// INTERNAL FUNCTION
bool __QueryProxyOptions()
@ -52,81 +54,64 @@ namespace Qv2ray::components::proxy
Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
//
List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
List.pszConnection = nullptr;// NO_CONST(DEFAULT_CONNECTION_NAME);
List.pszConnection = nullptr; // NO_CONST(DEFAULT_CONNECTION_NAME);
List.dwOptionCount = 5;
List.dwOptionError = 0;
List.pOptions = Option;
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
LOG(MODULE_PROXY, "InternetQueryOption failed, GLE=" + QSTRN(GetLastError()))
}
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
{ LOG(MODULE_PROXY, "InternetQueryOption failed, GLE=" + QSTRN(GetLastError())) }
LOG(MODULE_PROXY, "System default proxy info:")
if (Option[0].Value.pszValue != nullptr) {
LOG(MODULE_PROXY, QString::fromWCharArray(Option[0].Value.pszValue))
}
if (Option[0].Value.pszValue != nullptr) { LOG(MODULE_PROXY, QString::fromWCharArray(Option[0].Value.pszValue)) }
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL) {
LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_PROXY_URL")
}
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL)
{ LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_PROXY_URL") }
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) {
LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_DETECT")
}
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) { LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_DETECT") }
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) {
LOG(MODULE_PROXY, "PROXY_TYPE_DIRECT")
}
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) { LOG(MODULE_PROXY, "PROXY_TYPE_DIRECT") }
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) {
LOG(MODULE_PROXY, "PROXY_TYPE_PROXY")
}
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) { LOG(MODULE_PROXY, "PROXY_TYPE_PROXY") }
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
LOG(MODULE_PROXY, "InternetQueryOption failed,GLE=" + QSTRN(GetLastError()))
}
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
{ LOG(MODULE_PROXY, "InternetQueryOption failed,GLE=" + QSTRN(GetLastError())) }
if (Option[4].Value.pszValue != nullptr) {
LOG(MODULE_PROXY, QString::fromStdWString(Option[4].Value.pszValue))
}
if (Option[4].Value.pszValue != nullptr) { LOG(MODULE_PROXY, QString::fromStdWString(Option[4].Value.pszValue)) }
INTERNET_VERSION_INFO Version;
nSize = sizeof(INTERNET_VERSION_INFO);
InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize);
if (Option[0].Value.pszValue != nullptr) {
GlobalFree(Option[0].Value.pszValue);
}
if (Option[0].Value.pszValue != nullptr) { GlobalFree(Option[0].Value.pszValue); }
if (Option[3].Value.pszValue != nullptr) {
GlobalFree(Option[3].Value.pszValue);
}
if (Option[3].Value.pszValue != nullptr) { GlobalFree(Option[3].Value.pszValue); }
if (Option[4].Value.pszValue != nullptr) {
GlobalFree(Option[4].Value.pszValue);
}
if (Option[4].Value.pszValue != nullptr) { GlobalFree(Option[4].Value.pszValue); }
return false;
}
bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC)
{
INTERNET_PER_CONN_OPTION_LIST list;
BOOL bReturn;
DWORD dwBufSize = sizeof(list);
BOOL bReturn;
DWORD dwBufSize = sizeof(list);
// Fill the list structure.
list.dwSize = sizeof(list);
// NULL == LAN, otherwise connectoid name.
list.pszConnection = nullptr;
if (isPAC) {
if (isPAC)
{
LOG(MODULE_PROXY, "Setting system proxy for PAC")
//
list.dwOptionCount = 2;
list.pOptions = new INTERNET_PER_CONN_OPTION[2];
// Ensure that the memory was allocated.
if (nullptr == list.pOptions) {
if (nullptr == list.pOptions)
{
// Return FALSE if the memory wasn't allocated.
return FALSE;
}
@ -137,15 +122,15 @@ namespace Qv2ray::components::proxy
// Set proxy name.
list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
list.pOptions[1].Value.pszValue = proxy_full_addr;
} else {
}
else
{
LOG(MODULE_PROXY, "Setting system proxy for Global Proxy")
//
list.dwOptionCount = 3;
list.pOptions = new INTERNET_PER_CONN_OPTION[3];
if (nullptr == list.pOptions) {
return false;
}
if (nullptr == list.pOptions) { return false; }
// Set flags.
list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
@ -161,7 +146,7 @@ namespace Qv2ray::components::proxy
// Set the options on the connection.
bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
delete [] list.pOptions;
delete[] list.pOptions;
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
return bReturn;
@ -173,29 +158,26 @@ namespace Qv2ray::components::proxy
bool hasHTTP = (httpPort != 0);
bool hasSOCKS = (socksPort != 0);
if (!(hasHTTP || hasSOCKS || usePAC)) {
if (!(hasHTTP || hasSOCKS || usePAC))
{
LOG(MODULE_PROXY, "Nothing?")
return;
}
if (usePAC) {
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use PAC file")
} else {
if (hasHTTP) {
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use HTTP")
}
if (usePAC) { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use PAC file") }
else
{
if (hasHTTP) { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use HTTP") }
if (hasSOCKS) {
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use SOCKS")
}
if (hasSOCKS) { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use SOCKS") }
}
#ifdef Q_OS_WIN
QString __a;
if (usePAC) {
__a = address;
} else {
if (usePAC) { __a = address; }
else
{
__a = (hasHTTP ? "http://" : "socks5://") + address + ":" + QSTRN(httpPort);
}
@ -205,9 +187,7 @@ namespace Qv2ray::components::proxy
//
__QueryProxyOptions();
if (!__SetProxyOptions(proxyStrW, usePAC)) {
LOG(MODULE_PROXY, "Failed to set proxy.")
}
if (!__SetProxyOptions(proxyStrW, usePAC)) { LOG(MODULE_PROXY, "Failed to set proxy.") }
__QueryProxyOptions();
#elif defined(Q_OS_LINUX)
@ -215,18 +195,21 @@ namespace Qv2ray::components::proxy
auto proxyMode = usePAC ? "auto" : "manual";
actions << QString("gsettings set org.gnome.system.proxy mode '%1'").arg(proxyMode);
if (usePAC) {
actions << QString("gsettings set org.gnome.system.proxy autoconfig-url '%1'").arg(address);
} else {
if (hasHTTP) {
if (usePAC) { actions << QString("gsettings set org.gnome.system.proxy autoconfig-url '%1'").arg(address); }
else
{
if (hasHTTP)
{
actions << QString("gsettings set org.gnome.system.proxy.http host '%1'").arg(address);
actions << QString("gsettings set org.gnome.system.proxy.http port %1").arg(httpPort);
//
actions << QString("gsettings set org.gnome.system.proxy.https host '%1'").arg(address);
actions << QString("gsettings set org.gnome.system.proxy.https port %1").arg(httpPort);;
actions << QString("gsettings set org.gnome.system.proxy.https port %1").arg(httpPort);
;
}
if (hasSOCKS) {
if (hasSOCKS)
{
actions << QString("gsettings set org.gnome.system.proxy.socks host '%1'").arg(address);
actions << QString("gsettings set org.gnome.system.proxy.socks port %1").arg(socksPort);
}
@ -234,12 +217,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(MODULE_PROXY, action)
return QProcess::execute(action) == QProcess::NormalExit;
}) == actions.size();
auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString &action) {
DEBUG(MODULE_PROXY, action)
return QProcess::execute(action) == QProcess::NormalExit;
}) == actions.size();
if (!result) {
if (!result)
{
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.")
}
@ -247,21 +231,27 @@ namespace Qv2ray::components::proxy
Q_UNUSED(result);
#else
for (auto service : macOSgetNetworkServices()) {
for (auto service : macOSgetNetworkServices())
{
LOG(MODULE_PROXY, "Setting proxy for interface: " + service)
if (usePAC) {
if (usePAC)
{
QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setautoproxyurl " + service + " " + address);
} else {
if (hasHTTP) {
}
else
{
if (hasHTTP)
{
QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setwebproxy " + service + " " + address + " " + QSTRN(httpPort));
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxy " + service + " " + address + " " + QSTRN(httpPort));
}
if (hasSOCKS) {
if (hasSOCKS)
{
QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxy " + service + " " + address + " " + QSTRN(socksPort));
}
@ -287,7 +277,8 @@ namespace Qv2ray::components::proxy
list.pOptions = new INTERNET_PER_CONN_OPTION[list.dwOptionCount];
// Make sure the memory was allocated.
if (nullptr == list.pOptions) {
if (nullptr == list.pOptions)
{
// Return FALSE if the memory wasn't allocated.
LOG(MODULE_PROXY, "Failed to allocat memory in DisableConnectionProxy()")
}
@ -298,14 +289,15 @@ namespace Qv2ray::components::proxy
//
// Set the options on the connection.
bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
delete [] list.pOptions;
delete[] list.pOptions;
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
#elif defined(Q_OS_LINUX)
QProcess::execute("gsettings set org.gnome.system.proxy mode 'none'");
#else
for (auto service : macOSgetNetworkServices()) {
for (auto service : macOSgetNetworkServices())
{
LOG(MODULE_PROXY, "Clearing proxy for interface: " + service)
QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " off");
QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " off");
@ -315,4 +307,4 @@ namespace Qv2ray::components::proxy
#endif
}
}
} // namespace Qv2ray::components::proxy

View File

@ -1,12 +1,12 @@
#pragma once
#include <QString>
#include <QObject>
#include <QString>
//
namespace Qv2ray::components::proxy
{
void ClearSystemProxy();
void SetSystemProxy(const QString &address, int http_port, int socks_port, bool usePAC);
}
} // namespace Qv2ray::components::proxy
using namespace Qv2ray::components;
using namespace Qv2ray::components::proxy;

View File

@ -14,39 +14,40 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
* License in all respects for all of the code used other than "OpenSSL". If
* you modify file(s), you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*/
#include "speedplotview.hpp"
#include <QCoreApplication>
#include <QLocale>
#include <QPainter>
#include <QPen>
#include <list>
#include <QCoreApplication>
#define VIEWABLE 120
// use binary prefix standards from IEC 60027-2
// see http://en.wikipedia.org/wiki/Kilobyte
enum class SizeUnit {
Byte, // 1024^0,
KibiByte, // 1024^1,
MebiByte, // 1024^2,
GibiByte, // 1024^3,
TebiByte, // 1024^4,
PebiByte, // 1024^5,
ExbiByte // 1024^6,
enum class SizeUnit
{
Byte, // 1024^0,
KibiByte, // 1024^1,
MebiByte, // 1024^2,
GibiByte, // 1024^3,
TebiByte, // 1024^4,
PebiByte, // 1024^5,
ExbiByte // 1024^6,
// int64 is used for sizes and thus the next units can not be handled
// ZebiByte, // 1024^7,
// YobiByte, // 1024^8
@ -54,27 +55,25 @@ enum class SizeUnit {
namespace
{
const struct {
const struct
{
const char *source;
const char *comment;
} units[] = {
QT_TRANSLATE_NOOP3("misc", "B", "bytes"),
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
QT_TRANSLATE_NOOP3("misc", "GiB", "gibibytes (1024 mibibytes)"),
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)"),
QT_TRANSLATE_NOOP3("misc", "PiB", "pebibytes (1024 tebibytes)"),
QT_TRANSLATE_NOOP3("misc", "EiB", "exbibytes (1024 pebibytes)")
};
}
} units[] = { QT_TRANSLATE_NOOP3("misc", "B", "bytes"),
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
QT_TRANSLATE_NOOP3("misc", "GiB", "gibibytes (1024 mibibytes)"),
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)"),
QT_TRANSLATE_NOOP3("misc", "PiB", "pebibytes (1024 tebibytes)"),
QT_TRANSLATE_NOOP3("misc", "EiB", "exbibytes (1024 pebibytes)") };
} // namespace
QString unitString(const SizeUnit unit, const bool isSpeed)
{
const auto &unitString = units[static_cast<int>(unit)];
QString ret = QCoreApplication::translate("misc", unitString.source, unitString.comment);
if (isSpeed)
ret += QCoreApplication::translate("misc", "/s", "per second");
if (isSpeed) ret += QCoreApplication::translate("misc", "/s", "per second");
return ret;
}
@ -82,36 +81,34 @@ QString unitString(const SizeUnit unit, const bool isSpeed)
int friendlyUnitPrecision(const SizeUnit unit)
{
// friendlyUnit's number of digits after the decimal point
switch (unit) {
case SizeUnit::Byte:
return 0;
switch (unit)
{
case SizeUnit::Byte: return 0;
case SizeUnit::KibiByte:
case SizeUnit::MebiByte:
return 1;
case SizeUnit::MebiByte: return 1;
case SizeUnit::GibiByte:
return 2;
case SizeUnit::GibiByte: return 2;
default:
return 3;
default: return 3;
}
}
qlonglong sizeInBytes(qreal size, const SizeUnit unit)
{
for (int i = 0; i < static_cast<int>(unit); ++i)
size *= 1024;
for (int i = 0; i < static_cast<int>(unit); ++i) size *= 1024;
return size;
}
namespace
{
// table of supposed nice steps for grid marks to get nice looking quarters of scale
const double roundingTable[] = {1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8};
// table of supposed nice steps for grid marks to get nice looking quarters
// of scale
const double roundingTable[] = { 1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8 };
struct SplittedValue {
struct SplittedValue
{
double arg;
SizeUnit unit;
qint64 sizeInBytes() const
@ -122,56 +119,53 @@ namespace
SplittedValue getRoundedYScale(double value)
{
if (value == 0.0) return {0, SizeUnit::Byte};
if (value == 0.0) return { 0, SizeUnit::Byte };
if (value <= 12.0) return {12, SizeUnit::Byte};
if (value <= 12.0) return { 12, SizeUnit::Byte };
SizeUnit calculatedUnit = SizeUnit::Byte;
while (value > 1024) {
while (value > 1024)
{
value /= 1024;
calculatedUnit = static_cast<SizeUnit>(static_cast<int>(calculatedUnit) + 1);
}
if (value > 100.0) {
if (value > 100.0)
{
int roundedValue = static_cast<int>(value / 40) * 40;
while (roundedValue < value)
roundedValue += 40;
while (roundedValue < value) roundedValue += 40;
return {static_cast<double>(roundedValue), calculatedUnit};
return { static_cast<double>(roundedValue), calculatedUnit };
}
if (value > 10.0) {
if (value > 10.0)
{
int roundedValue = static_cast<int>(value / 4) * 4;
while (roundedValue < value)
roundedValue += 4;
while (roundedValue < value) roundedValue += 4;
return {static_cast<double>(roundedValue), calculatedUnit};
return { static_cast<double>(roundedValue), calculatedUnit };
}
for (const auto &roundedValue : roundingTable) {
if (value <= roundedValue)
return {roundedValue, calculatedUnit};
for (const auto &roundedValue : roundingTable)
{
if (value <= roundedValue) return { roundedValue, calculatedUnit };
}
return {10.0, calculatedUnit};
return { 10.0, calculatedUnit };
}
QString formatLabel(const double argValue, const SizeUnit unit)
{
// check is there need for digits after decimal separator
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
return QLocale::system().toString(argValue, 'f', precision)
+ QString::fromUtf8(" ")
+ unitString(unit, true);
return QLocale::system().toString(argValue, 'f', precision) + QString::fromUtf8(" ") + unitString(unit, true);
}
}
} // namespace
SpeedPlotView::SpeedPlotView(QWidget *parent)
: QGraphicsView(parent)
, m_currentData(&m_datahalfMin)
SpeedPlotView::SpeedPlotView(QWidget *parent) : QGraphicsView(parent), m_currentData(&m_datahalfMin)
{
QPen greenPen;
greenPen.setWidthF(1.5);
@ -193,9 +187,7 @@ void SpeedPlotView::pushPoint(const SpeedPlotView::PointData &point)
{
m_datahalfMin.push_back(point);
while (m_datahalfMin.length() > VIEWABLE) {
m_datahalfMin.removeFirst();
}
while (m_datahalfMin.length() > VIEWABLE) { m_datahalfMin.removeFirst(); }
}
void SpeedPlotView::replot()
@ -213,11 +205,12 @@ quint64 SpeedPlotView::maxYValue()
auto &queue = getCurrentData();
quint64 maxYValue = 0;
for (int id = UP; id < NB_GRAPHS; ++id) {
for (int id = UP; id < NB_GRAPHS; ++id)
{
// 30 is half min
for (int i = queue.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j) {
if (queue[i].y[id] > maxYValue)
maxYValue = queue[i].y[id];
for (int i = queue.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
{
if (queue[i].y[id] > maxYValue) maxYValue = queue[i].y[id];
}
}
@ -244,12 +237,12 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
int yAxisWidth = 0;
for (const QString &label : speedLabels)
if (fontMetrics.horizontalAdvance(label) > yAxisWidth)
yAxisWidth = fontMetrics.horizontalAdvance(label);
if (fontMetrics.horizontalAdvance(label) > yAxisWidth) yAxisWidth = fontMetrics.horizontalAdvance(label);
int i = 0;
for (const QString &label : speedLabels) {
for (const QString &label : speedLabels)
{
QRectF labelRect(rect.topLeft() + QPointF(-yAxisWidth, (i++) * 0.25 * rect.height() - fontMetrics.height()),
QSizeF(2 * yAxisWidth, fontMetrics.height()));
painter.drawText(labelRect, label, Qt::AlignRight | Qt::AlignTop);
@ -269,7 +262,8 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
painter.drawLine(fullRect.left(), rect.bottom(), rect.right(), rect.bottom());
const int TIME_AXIS_DIVISIONS = 6;
for (int i = 0; i < TIME_AXIS_DIVISIONS; ++i) {
for (int i = 0; i < TIME_AXIS_DIVISIONS; ++i)
{
const int x = rect.left() + (i * rect.width()) / TIME_AXIS_DIVISIONS;
painter.drawLine(x, fullRect.top(), x, fullRect.bottom());
}
@ -282,10 +276,12 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
const double xTickSize = static_cast<double>(rect.width()) / VIEWABLE;
auto &queue = getCurrentData();
for (int id = UP; id < NB_GRAPHS; ++id) {
for (int id = UP; id < NB_GRAPHS; ++id)
{
QVector<QPoint> points;
for (int i = static_cast<int>(queue.size()) - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j) {
for (int i = static_cast<int>(queue.size()) - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
{
int newX = rect.right() - j * xTickSize;
int newY = rect.bottom() - queue[i].y[id] * yMultiplier;
points.push_back(QPoint(newX, newY));
@ -300,27 +296,28 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
double legendHeight = 0;
int legendWidth = 0;
for (const auto &property : m_properties) {
if (fontMetrics.horizontalAdvance(property.name) > legendWidth)
legendWidth = fontMetrics.horizontalAdvance(property.name);
for (const auto &property : m_properties)
{
if (fontMetrics.horizontalAdvance(property.name) > legendWidth) legendWidth = fontMetrics.horizontalAdvance(property.name);
legendHeight += 1.5 * fontMetrics.height();
}
QRectF legendBackgroundRect(QPoint(legendTopLeft.x() - 4, legendTopLeft.y() - 4), QSizeF(legendWidth + 8, legendHeight + 8));
QColor legendBackgroundColor = QWidget::palette().color(QWidget::backgroundRole());
legendBackgroundColor.setAlpha(128); // 50% transparent
legendBackgroundColor.setAlpha(128); // 50% transparent
painter.fillRect(legendBackgroundRect, legendBackgroundColor);
i = 0;
for (const auto &property : m_properties) {
for (const auto &property : m_properties)
{
int nameSize = fontMetrics.horizontalAdvance(property.name);
double indent = 1.5 * (i++) * fontMetrics.height();
painter.setPen(property.pen);
painter.drawLine(legendTopLeft + QPointF(0, indent + fontMetrics.height()),
legendTopLeft + QPointF(nameSize, indent + fontMetrics.height()));
painter.drawText(QRectF(legendTopLeft + QPointF(0, indent), QSizeF(2 * nameSize, fontMetrics.height())),
property.name, QTextOption(Qt::AlignVCenter));
painter.drawText(QRectF(legendTopLeft + QPointF(0, indent), QSizeF(2 * nameSize, fontMetrics.height())), property.name,
QTextOption(Qt::AlignVCenter));
}
}
@ -328,8 +325,6 @@ SpeedPlotView::GraphProperties::GraphProperties()
{
}
SpeedPlotView::GraphProperties::GraphProperties(const QString &name, const QPen &pen)
: name(name)
, pen(pen)
SpeedPlotView::GraphProperties::GraphProperties(const QString &name, const QPen &pen) : name(name), pen(pen)
{
}

View File

@ -36,43 +36,46 @@ class QPen;
class SpeedPlotView : public QGraphicsView
{
Q_OBJECT
Q_OBJECT
public:
enum GraphID {
UP = 0,
DOWN,
NB_GRAPHS
};
public:
enum GraphID
{
UP = 0,
DOWN,
NB_GRAPHS
};
struct PointData {
qint64 x;
quint64 y[NB_GRAPHS];
};
struct PointData
{
qint64 x;
quint64 y[NB_GRAPHS];
};
explicit SpeedPlotView(QWidget *parent = nullptr);
void pushPoint(const PointData &point);
void Clear();
void replot();
explicit SpeedPlotView(QWidget *parent = nullptr);
void pushPoint(const PointData &point);
void Clear();
void replot();
protected:
void paintEvent(QPaintEvent *event) override;
protected:
void paintEvent(QPaintEvent *event) override;
private:
struct GraphProperties {
GraphProperties();
GraphProperties(const QString &name, const QPen &pen);
private:
struct GraphProperties
{
GraphProperties();
GraphProperties(const QString &name, const QPen &pen);
QString name;
QPen pen;
};
QString name;
QPen pen;
};
quint64 maxYValue();
QList<PointData> &getCurrentData();
QList<PointData> m_datahalfMin;
QList<PointData> *m_currentData;
quint64 maxYValue();
QList<PointData> &getCurrentData();
QList<PointData> m_datahalfMin;
QList<PointData> *m_currentData;
QMap<GraphID, GraphProperties> m_properties;
QMap<GraphID, GraphProperties> m_properties;
};
#endif // SPEEDPLOTVIEW_H

View File

@ -14,20 +14,23 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
* License in all respects for all of the code used other than "OpenSSL". If
* you modify file(s), you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*/
#include "speedwidget.hpp"
#include "speedplotview.hpp"
#include <QDateTime>
#include <QHBoxLayout>
#include <QLabel>
@ -35,10 +38,7 @@
#include <QTimer>
#include <QVBoxLayout>
#include "speedplotview.hpp"
SpeedWidget::SpeedWidget(QWidget *parent)
: QWidget(parent)
SpeedWidget::SpeedWidget(QWidget *parent) : QWidget(parent)
{
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
@ -52,7 +52,9 @@ SpeedWidget::SpeedWidget(QWidget *parent)
m_plot->show();
}
SpeedWidget::~SpeedWidget() {}
SpeedWidget::~SpeedWidget()
{
}
void SpeedWidget::AddPointData(long up, long down)
{

View File

@ -41,17 +41,18 @@ class SpeedPlotView;
class SpeedWidget : public QWidget
{
Q_OBJECT
Q_OBJECT
public:
explicit SpeedWidget(QWidget *parent);
~SpeedWidget();
void AddPointData(long up, long down);
void Clear();
private:
QVBoxLayout *m_layout;
QHBoxLayout *m_hlayout;
SpeedPlotView *m_plot;
public:
explicit SpeedWidget(QWidget *parent);
~SpeedWidget();
void AddPointData(long up, long down);
void Clear();
private:
QVBoxLayout *m_layout;
QHBoxLayout *m_hlayout;
SpeedPlotView *m_plot;
};
#endif // SPEEDWIDGET_H

View File

@ -1,38 +1,43 @@
#pragma once
#include <QString>
#include <QHash>
#include <QHashFunctions>
#include "base/models/QvConfigIdentifier.hpp"
#include <QHash>
#include <QHashFunctions>
#include <QString>
namespace Qv2ray::core
{
template <typename T>
template<typename T>
class IDType
{
public:
explicit 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;
}
friend bool operator!=(const IDType<T> &lhs, const IDType<T> &rhs)
{
return lhs.toString() != rhs.toString();
}
const QString &toString() const
{
return m_id;
}
uint qHash(uint seed) const
{
return ::qHash(m_id, seed);
}
private:
QString m_id;
};
public:
explicit IDType() : m_id("null")
{
}
explicit 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;
}
friend bool operator!=(const IDType<T> &lhs, const IDType<T> &rhs)
{
return lhs.toString() != rhs.toString();
}
const QString &toString() const
{
return m_id;
}
uint qHash(uint seed) const
{
return ::qHash(m_id, seed);
}
private:
QString m_id;
};
// Define several safetypes to prevent misuse of QString.
class __QvGroup;
@ -48,9 +53,7 @@ namespace Qv2ray::core
{
QList<IDType> list;
for (auto str : strings) {
list << IDType(str);
}
for (auto str : strings) { list << IDType(str); }
return list;
}
@ -60,21 +63,23 @@ namespace Qv2ray::core
{
QList<QString> list;
for (auto id : ids) {
list << id.toString();
}
for (auto id : ids) { list << id.toString(); }
return list;
}
template <typename T> uint qHash(const IDType<T> &key, uint seed = 0)
template<typename T>
uint qHash(const IDType<T> &key, uint seed = 0)
{
return key.qHash(seed);
}
//
/// Metadata object representing a connection.
struct ConnectionMetaObject : ConnectionObject_Config {
struct ConnectionMetaObject : ConnectionObject_Config
{
GroupId groupId = NullGroupId;
ConnectionMetaObject(): ConnectionObject_Config() { }
ConnectionMetaObject() : ConnectionObject_Config()
{
}
// Suger for down casting.
ConnectionMetaObject(const ConnectionObject_Config &base) : ConnectionMetaObject()
{
@ -88,13 +93,16 @@ namespace Qv2ray::core
};
/// Metadata object representing a group.
struct GroupMetaObject: SubscriptionObject_Config {
struct GroupMetaObject : SubscriptionObject_Config
{
// Implicit base of two types, since group object is actually the group base object.
bool isSubscription;
QList<ConnectionId> connections;
// Suger for down casting.
GroupMetaObject(): connections() {}
GroupMetaObject(const GroupObject_Config &base): GroupMetaObject()
GroupMetaObject() : connections()
{
}
GroupMetaObject(const GroupObject_Config &base) : GroupMetaObject()
{
this->isSubscription = false;
this->displayName = base.displayName;
@ -102,7 +110,7 @@ namespace Qv2ray::core
this->connections = StringsToIdList<ConnectionId>(base.connections);
}
// Suger for down casting.
GroupMetaObject(const SubscriptionObject_Config &base): GroupMetaObject((GroupObject_Config)base)
GroupMetaObject(const SubscriptionObject_Config &base) : GroupMetaObject((GroupObject_Config) base)
{
this->address = base.address;
this->lastUpdated = base.lastUpdated;
@ -110,6 +118,6 @@ namespace Qv2ray::core
this->isSubscription = true;
}
};
}
} // namespace Qv2ray::core
using namespace Qv2ray::core;

View File

@ -24,26 +24,33 @@ namespace Qv2ray::core
*port = 0;
*protocol = out["protocol"].toString(QObject::tr("N/A")).toLower();
if (*protocol == "vmess") {
auto Server = StructFromJsonString<VMessServerObject>(JsonToString(out["settings"].toObject()["vnext"].toArray().first().toObject()));
if (*protocol == "vmess")
{
auto Server =
StructFromJsonString<VMessServerObject>(JsonToString(out["settings"].toObject()["vnext"].toArray().first().toObject()));
*host = Server.address;
*port = Server.port;
return true;
} else if (*protocol == "shadowsocks") {
}
else if (*protocol == "shadowsocks")
{
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
auto Server = StructFromJsonString<ShadowSocksServerObject>(x);
*host = Server.address;
*port = Server.port;
return true;
} else if (*protocol == "socks") {
}
else if (*protocol == "socks")
{
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
auto Server = StructFromJsonString<SocksServerObject>(x);
*host = Server.address;
*port = Server.port;
return true;
} else {
}
else
{
return false;
}
}
}
} // namespace Qv2ray::core

View File

@ -1,7 +1,7 @@
#pragma once
#include <QString>
#include <base/models/QvSafeType.hpp>
#include <base/models/CoreObjectModels.hpp>
#include <base/models/QvSafeType.hpp>
namespace Qv2ray::core
{
@ -26,6 +26,6 @@ namespace Qv2ray::core
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol);
bool IsComplexConfig(const CONFIGROOT &root);
}
} // namespace Qv2ray::core
using namespace Qv2ray::core;

View File

@ -1,4 +1,5 @@
#include "ConfigBackend.hpp"
#include "common/QvHelpers.hpp"
namespace Qv2ray::core::config
@ -14,10 +15,8 @@ namespace Qv2ray::core::config
{
Qv2rayConfigPath = path;
if (!path.endsWith("/")) {
Qv2rayConfigPath += "/";
}
if (!path.endsWith("/")) { Qv2rayConfigPath += "/"; }
}
}
} // namespace Qv2ray::core::config
using namespace Qv2ray::core::config;

View File

@ -4,7 +4,7 @@ namespace Qv2ray::core::config
{
void SaveGlobalConfig(const Qv2rayConfig &conf);
void SetConfigDirPath(const QString &path);
}
} // namespace Qv2ray::core::config
using namespace Qv2ray::core;
using namespace Qv2ray::core::config;

View File

@ -13,11 +13,14 @@ namespace Qv2ray
// Private member
QJsonObject UpgradeConfig_Inc(int fromVersion, QJsonObject root)
{
switch (fromVersion) {
switch (fromVersion)
{
// --------------------------------------------------------------------------------------
// Below is for Qv2ray version 2
case 4: {
// We changed the "proxyCN" to "bypassCN" as it's easier to understand....
case 4:
{
// We changed the "proxyCN" to "bypassCN" as it's easier to
// understand....
auto v2_oldProxyCN = root["proxyCN"].toBool();
//
// From 3 to 4, we changed 'runAsRoot' to 'tProxySupport'
@ -38,7 +41,7 @@ namespace Qv2ray
root.remove("inBoundSettings");
UPGRADELOG("Renamed inBoundSettings to inboundConfig.")
//
//connectionConfig
// connectionConfig
QJsonObject o;
o["dnsList"] = root["dnsList"];
o["withLocalDNS"] = root["withLocalDNS"];
@ -66,13 +69,15 @@ namespace Qv2ray
}
// Qv2ray version 2, RC 2
case 5: {
case 5:
{
// Added subscription auto update
auto subs = root["subscribes"].toObject();
root.remove("subscribes");
QJsonObject newSubscriptions;
for (auto item = subs.begin(); item != subs.end(); item++) {
for (auto item = subs.begin(); item != subs.end(); item++)
{
auto key = item.key();
SubscriptionObject_Config _conf;
_conf.address = item.value().toString();
@ -88,7 +93,8 @@ namespace Qv2ray
}
// Qv2ray version 2, RC 4
case 6: {
case 6:
{
// Moved API Stats port from connectionConfig to apiConfig
QJsonObject apiConfig;
apiConfig["enableAPI"] = true;
@ -97,7 +103,8 @@ namespace Qv2ray
break;
}
case 7: {
case 7:
{
auto lang = root["uiConfig"].toObject()["language"].toString().replace("-", "_");
auto uiConfig = root["uiConfig"].toObject();
uiConfig["language"] = lang;
@ -106,23 +113,24 @@ namespace Qv2ray
break;
}
// From version 8 to 9, we introduced a lot of new connection metainfo(s)
case 8: {
// 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);
}
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()) {
for (auto config : root["configs"].toArray())
{
UPGRADELOG("Migrating: " + config.toString())
//
// MOVE FILES.
@ -133,17 +141,19 @@ namespace Qv2ray
DEBUG(MODULE_SETTINGS, "Generated new UUID: " + newUuid);
// Check Autostart Id
if (root["autoStartConfig"].toObject()["subscriptionName"].toString().isEmpty()) {
if (root["autoStartConfig"].toObject()["connectionName"].toString() == config.toString()) {
autoStartId = newUuid;
}
if (root["autoStartConfig"].toObject()["subscriptionName"].toString().isEmpty())
{
if (root["autoStartConfig"].toObject()["connectionName"].toString() == config.toString()) { autoStartId = newUuid; }
}
if (configFile.exists()) {
if (configFile.exists())
{
auto newPath = QV2RAY_CONNECTIONS_DIR + defaultGroupId + "/" + newUuid + QV2RAY_CONFIG_FILE_EXTENSION;
configFile.rename(newPath);
UPGRADELOG("Moved: " + filePath + " to " + newPath);
} else {
}
else
{
UPGRADELOG("WARNING! This file is not found, possible loss of data!")
continue;
}
@ -159,7 +169,8 @@ namespace Qv2ray
QJsonObject rootSubscriptions = root.take("subscriptions").toObject();
QJsonObject newSubscriptions;
for (auto i = 0; i < rootSubscriptions.count(); i++) {
for (auto i = 0; i < rootSubscriptions.count(); i++)
{
auto key = rootSubscriptions.keys()[i];
auto value = rootSubscriptions.value(key);
//
@ -176,15 +187,14 @@ namespace Qv2ray
auto newDirPath = QV2RAY_SUBSCRIPTION_DIR + subsUuid;
QDir newDir(newDirPath);
if (!newDir.exists()) {
newDir.mkpath(newDirPath);
}
if (!newDir.exists()) { newDir.mkpath(newDirPath); }
// With extensions
auto fileList = GetFileList(baseDirPath);
// Copy every file within a subscription.
for (auto fileName : fileList) {
for (auto fileName : fileList)
{
auto subsConnectionId = GenerateUuid();
auto baseFilePath = baseDirPath + "/" + fileName;
auto newFilePath = newDirPath + "/" + subsConnectionId + QV2RAY_CONFIG_FILE_EXTENSION;
@ -199,10 +209,10 @@ namespace Qv2ray
//
// Check Autostart Id
if (root["autoStartConfig"].toObject()["subscriptionName"].toString() == key) {
if (root["autoStartConfig"].toObject()["connectionName"].toString() == subsConnection["displayName"].toString()) {
autoStartId = subsConnectionId;
}
if (root["autoStartConfig"].toObject()["subscriptionName"].toString() == key)
{
if (root["autoStartConfig"].toObject()["connectionName"].toString() == subsConnection["displayName"].toString())
{ autoStartId = subsConnectionId; }
}
}
@ -222,12 +232,15 @@ namespace Qv2ray
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
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."));
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.");
}
@ -242,10 +255,8 @@ namespace Qv2ray
{
LOG(MODULE_SETTINGS, "Migrating config from version " + QSTRN(fromVersion) + " to " + QSTRN(toVersion))
for (int i = fromVersion; i < toVersion; i++) {
root = UpgradeConfig_Inc(i, root);
}
for (int i = fromVersion; i < toVersion; i++) { root = UpgradeConfig_Inc(i, root); }
return root;
}
}
} // namespace Qv2ray

View File

@ -1,4 +1,5 @@
#include "ConnectionIO.hpp"
#include "common/QvHelpers.hpp"
namespace Qv2ray::core::connection
@ -8,16 +9,19 @@ namespace Qv2ray::core::connection
////
//// 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)
// bool SaveConnectionConfig(CONFIGROOT obj, QString *alias, bool
// canOverrideExisting)
//{
// auto str = JsonToString(obj);
// auto fullPath = QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION;
// 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;
// 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)
@ -25,7 +29,8 @@ namespace Qv2ray::core::connection
// return StringToFile(&str, &config);
//}
//
//bool SaveSubscriptionConfig(CONFIGROOT obj, const QString &subscription, QString *name)
// bool SaveSubscriptionConfig(CONFIGROOT obj, const QString
// &subscription, QString *name)
//{
// auto str = JsonToString(obj);
// auto fName = *name;
@ -34,27 +39,31 @@ namespace Qv2ray::core::connection
// fName = RemoveInvalidFileName(fName);
// }
//
// QFile config(QV2RAY_SUBSCRIPTION_DIR + subscription + "/" + fName + QV2RAY_CONFIG_FILE_EXTENSION);
// 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_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)
// LOG(MODULE_FILEIO, "Failed to save a connection config from
// subscription: " + subscription + ", name: " + fName)
// }
//
// *name = fName;
// return result;
//}
//
//bool RemoveConnection(const QString &alias)
// bool RemoveConnection(const QString &alias)
//{
// QFile config(QV2RAY_CONFIG_DIR + alias + QV2RAY_CONFIG_FILE_EXTENSION);
// QFile config(QV2RAY_CONFIG_DIR + alias +
// QV2RAY_CONFIG_FILE_EXTENSION);
//
// if (!config.exists()) {
// LOG(MODULE_FILEIO, "Trying to remove a non-existing file?")
@ -64,9 +73,11 @@ namespace Qv2ray::core::connection
// }
//}
//
//bool RemoveSubscriptionConnection(const QString &subsName, const QString &name)
// bool RemoveSubscriptionConnection(const QString &subsName, const
// QString &name)
//{
// QFile config(QV2RAY_SUBSCRIPTION_DIR + subsName + "/" + name + QV2RAY_CONFIG_FILE_EXTENSION);
// QFile config(QV2RAY_SUBSCRIPTION_DIR + subsName + "/" + name +
// QV2RAY_CONFIG_FILE_EXTENSION);
//
// if (!config.exists()) {
// LOG(MODULE_FILEIO, "Trying to remove a non-existing file?")
@ -76,25 +87,32 @@ namespace Qv2ray::core::connection
// }
//}
//
//bool RenameConnection(const QString &originalName, const QString &newName)
// 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);
// 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)
// 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);
// 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)
// 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();
// LOG(MODULE_FILEIO, "Trying to import from an non-existing
// file.") return CONFIGROOT();
// }
//
// auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
@ -111,4 +129,4 @@ namespace Qv2ray::core::connection
// return root;
//}
}
}
} // namespace Qv2ray::core::connection

View File

@ -7,8 +7,8 @@ namespace Qv2ray::core::connection
{
// File Protocol
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex);
}
}
} // namespace ConnectionIO
} // namespace Qv2ray::core::connection
using namespace Qv2ray::core::connection;
using namespace Qv2ray::core::connection::ConnectionIO;

View File

@ -1,12 +1,14 @@
#include "Generation.hpp"
#include "core/CoreUtils.hpp"
#include "common/QvHelpers.hpp"
#include "core/CoreUtils.hpp"
namespace Qv2ray::core::connection
{
namespace Generation
{
// -------------------------- BEGIN CONFIG GENERATIONS ----------------------------------------------------------------------------
// -------------------------- BEGIN CONFIG GENERATIONS
// ----------------------------------------------------------------------------
ROUTING GenerateRoutes(bool enableProxy, bool proxyCN)
{
ROUTING root;
@ -15,8 +17,10 @@ namespace Qv2ray::core::connection
// For Rules list
ROUTERULELIST rulesList;
if (!enableProxy) {
// This is added to disable all proxies, as a alternative influence of #64
if (!enableProxy)
{
// This is added to disable all proxies, as a alternative
// influence of #64
rulesList.append(GenerateSingleRouteRule(QStringList() << "regexp:.*", true, OUTBOUND_TAG_DIRECT));
}
@ -28,7 +32,8 @@ namespace Qv2ray::core::connection
rulesList.append(GenerateSingleRouteRule(QStringList() << "geosite:cn", true, proxyCN ? OUTBOUND_TAG_DIRECT : OUTBOUND_TAG_PROXY));
//
// As a bug fix of #64, this default rule has been disabled.
//rulesList.append(GenerateSingleRouteRule(QStringList({"regexp:.*"}), true, globalProxy ? OUTBOUND_TAG_PROXY : OUTBOUND_TAG_DIRECT));
// rulesList.append(GenerateSingleRouteRule(QStringList({"regexp:.*"}),
// true, globalProxy ? OUTBOUND_TAG_PROXY : OUTBOUND_TAG_DIRECT));
root.insert("rules", rulesList);
RROOT
}
@ -56,20 +61,24 @@ namespace Qv2ray::core::connection
RROOT
}
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers)
OUTBOUNDSETTING
GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers)
{
OUTBOUNDSETTING root;
QJsonArray x;
foreach (auto server, servers) {
x.append(GenerateShadowSocksServerOUT(server.email, server.address, server.port, server.method, server.password, server.ota, server.level));
foreach (auto server, servers)
{
x.append(GenerateShadowSocksServerOUT(server.email, server.address, server.port, server.method, server.password, server.ota,
server.level));
}
root.insert("servers", x);
RROOT
}
OUTBOUNDSETTING GenerateShadowSocksServerOUT(QString email, QString address, int port, QString method, QString password, bool ota, int level)
OUTBOUNDSETTING GenerateShadowSocksServerOUT(QString email, QString address, int port, QString method, QString password, bool ota,
int level)
{
OUTBOUNDSETTING root;
JADD(email, address, port, method, password, level, ota)
@ -81,7 +90,8 @@ namespace Qv2ray::core::connection
QJsonObject root;
QJsonArray servers(QJsonArray::fromStringList(dnsServers));
if (withLocalhost) {
if (withLocalhost)
{
// https://github.com/lhy0403/Qv2ray/issues/64
// The fix patch didn't touch this line below.
//
@ -93,7 +103,7 @@ namespace Qv2ray::core::connection
RROOT
}
INBOUNDSETTING GenerateDokodemoIN(QString address, int port, QString network, int timeout, bool followRedirect, int userLevel)
INBOUNDSETTING GenerateDokodemoIN(QString address, int port, QString network, int timeout, bool followRedirect, int userLevel)
{
INBOUNDSETTING root;
JADD(address, port, network, timeout, followRedirect, userLevel)
@ -105,17 +115,14 @@ namespace Qv2ray::core::connection
INBOUNDSETTING root;
QJsonArray accounts;
foreach (auto account, _accounts) {
if (account.user.isEmpty() && account.pass.isEmpty()) {
continue;
}
foreach (auto account, _accounts)
{
if (account.user.isEmpty() && account.pass.isEmpty()) { continue; }
accounts.append(GetRootObject(account));
}
if (!accounts.isEmpty()) {
JADD(accounts)
}
if (!accounts.isEmpty()) { JADD(accounts) }
JADD(timeout, allowTransparent, userLevel)
RROOT
@ -130,7 +137,8 @@ namespace Qv2ray::core::connection
oneServer["address"] = address;
oneServer["port"] = port;
if (useAuth) {
if (useAuth)
{
QJsonArray users;
QJsonObject oneUser;
oneUser["user"] = username;
@ -150,35 +158,34 @@ namespace Qv2ray::core::connection
INBOUNDSETTING root;
QJsonArray accounts;
foreach (auto acc, _accounts) {
if (acc.user.isEmpty() && acc.pass.isEmpty()) {
continue;
}
foreach (auto acc, _accounts)
{
if (acc.user.isEmpty() && acc.pass.isEmpty()) { continue; }
accounts.append(GetRootObject(acc));
}
if (!accounts.isEmpty()) {
JADD(accounts)
}
if (!accounts.isEmpty()) { JADD(accounts) }
if (udp) {
JADD(auth, udp, ip, userLevel)
} else {
if (udp) { JADD(auth, udp, ip, userLevel) }
else
{
JADD(auth, userLevel)
}
RROOT
}
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux, QString sendThrough, QString tag)
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux,
QString sendThrough, QString tag)
{
OUTBOUND root;
JADD(sendThrough, protocol, settings, tag, streamSettings, mux)
RROOT
}
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing, QJsonObject allocate)
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing,
QJsonObject allocate)
{
INBOUND root;
LOG(MODULE_CONNECTION, "allocation is not used here.")
@ -192,20 +199,18 @@ namespace Qv2ray::core::connection
QJsonObject root;
QJsonArray services;
if (withHandler)
services << "HandlerService";
if (withHandler) services << "HandlerService";
if (withLogger)
services << "LoggerService";
if (withLogger) services << "LoggerService";
if (withStats)
services << "StatsService";
if (withStats) services << "StatsService";
JADD(services, tag)
RROOT
}
// -------------------------- END CONFIG GENERATIONS ------------------------------------------------------------------------------
// -------------------------- END CONFIG GENERATIONS
// ------------------------------------------------------------------------------
// BEGIN RUNTIME CONFIG GENERATION
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root)
@ -213,8 +218,10 @@ namespace Qv2ray::core::connection
bool isComplex = IsComplexConfig(root);
QJsonObject logObject;
//
//logObject.insert("access", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ACCESS_LOG_FILENAME);
//logObject.insert("error", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME);
// logObject.insert("access", QV2RAY_CONFIG_PATH +
// QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ACCESS_LOG_FILENAME);
// logObject.insert("error", QV2RAY_CONFIG_PATH +
// QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME);
//
logObject.insert("loglevel", vLogLevels[GlobalConfig.logLevel]);
root.insert("log", logObject);
@ -225,20 +232,24 @@ namespace Qv2ray::core::connection
//
//
// If inbounds list is empty we append our global configured inbounds to the config.
if (!root.contains("inbounds") || root["inbounds"].toArray().empty()) {
// If inbounds list is empty we append our global configured
// inbounds to the config.
if (!root.contains("inbounds") || root["inbounds"].toArray().empty())
{
INBOUNDS inboundsList;
// HTTP Inbound
if (GlobalConfig.inboundConfig.useHTTP) {
if (GlobalConfig.inboundConfig.useHTTP)
{
INBOUND httpInBoundObject;
httpInBoundObject.insert("listen", GlobalConfig.inboundConfig.listenip);
httpInBoundObject.insert("port", GlobalConfig.inboundConfig.http_port);
httpInBoundObject.insert("protocol", "http");
httpInBoundObject.insert("tag", "http_IN");
if (GlobalConfig.inboundConfig.http_useAuth) {
auto httpInSettings = GenerateHTTPIN(QList<AccountObject>() << GlobalConfig.inboundConfig.httpAccount);
if (GlobalConfig.inboundConfig.http_useAuth)
{
auto httpInSettings = GenerateHTTPIN(QList<AccountObject>() << GlobalConfig.inboundConfig.httpAccount);
httpInBoundObject.insert("settings", httpInSettings);
}
@ -246,7 +257,8 @@ namespace Qv2ray::core::connection
}
// SOCKS Inbound
if (GlobalConfig.inboundConfig.useSocks) {
if (GlobalConfig.inboundConfig.useSocks)
{
INBOUND socksInBoundObject;
socksInBoundObject.insert("listen", GlobalConfig.inboundConfig.listenip);
socksInBoundObject.insert("port", GlobalConfig.inboundConfig.socks_port);
@ -254,8 +266,7 @@ namespace Qv2ray::core::connection
socksInBoundObject.insert("tag", "socks_IN");
auto socksInSettings = GenerateSocksIN(GlobalConfig.inboundConfig.socks_useAuth ? "password" : "noauth",
QList<AccountObject>() << GlobalConfig.inboundConfig.socksAccount,
GlobalConfig.inboundConfig.socksUDP,
GlobalConfig.inboundConfig.socksLocalIP);
GlobalConfig.inboundConfig.socksUDP, GlobalConfig.inboundConfig.socksLocalIP);
socksInBoundObject.insert("settings", socksInSettings);
inboundsList.append(socksInBoundObject);
}
@ -264,14 +275,16 @@ namespace Qv2ray::core::connection
DEBUG(MODULE_CONNECTION, "Added global config inbounds to the config")
}
// Process every inbounds to make sure a tag is configured, fixed API 0 speed
// issue when no tag is configured.
// Process every inbounds to make sure a tag is configured, fixed
// API 0 speed issue when no tag is configured.
INBOUNDS newTaggedInbounds = INBOUNDS(root["inbounds"].toArray());
for (auto i = 0; i < newTaggedInbounds.count(); i++) {
for (auto i = 0; i < newTaggedInbounds.count(); i++)
{
auto _inboundItem = newTaggedInbounds[i].toObject();
if (!_inboundItem.contains("tag") || _inboundItem["tag"].toString().isEmpty()) {
if (!_inboundItem.contains("tag") || _inboundItem["tag"].toString().isEmpty())
{
LOG(MODULE_SETTINGS, "Adding a tag to an inbound.")
_inboundItem["tag"] = GenerateRandomString(8);
newTaggedInbounds[i] = _inboundItem;
@ -281,52 +294,66 @@ namespace Qv2ray::core::connection
root["inbounds"] = newTaggedInbounds;
//
//
// Note: The part below always makes the whole functionality in trouble......
// BE EXTREME CAREFUL when changing these code below...
// See: https://github.com/lhy0403/Qv2ray/issues/129
// routeCountLabel in Mainwindow makes here failed to ENOUGH-ly check the routing tables
// Note: The part below always makes the whole functionality in
// trouble...... BE EXTREME CAREFUL when changing these code
// below... See: https://github.com/lhy0403/Qv2ray/issues/129
// routeCountLabel in Mainwindow makes here failed to ENOUGH-ly
// check the routing tables
if (isComplex) {
if (isComplex)
{
// For some config files that has routing entries already.
// We DO NOT add extra routings.
//
// HOWEVER, we need to verify the QV2RAY_RULE_ENABLED entry.
// And what's more, process (by removing unused items) from a rule object.
// And what's more, process (by removing unused items) from a
// rule object.
ROUTING routing = ROUTING(root["routing"].toObject());
ROUTERULELIST rules;
LOG(MODULE_CONNECTION, "Processing an existing routing table.")
for (auto _rule : routing["rules"].toArray()) {
for (auto _rule : routing["rules"].toArray())
{
auto _b = _rule.toObject();
if (_b.contains("QV2RAY_RULE_USE_BALANCER")) {
if (_b["QV2RAY_RULE_USE_BALANCER"].toBool()) {
if (_b.contains("QV2RAY_RULE_USE_BALANCER"))
{
if (_b["QV2RAY_RULE_USE_BALANCER"].toBool())
{
// We use balancer
_b.remove("outboundTag");
} else {
}
else
{
// We only use the normal outbound
_b.remove("balancerTag");
}
} else {
}
else
{
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 {
if (_b.contains("QV2RAY_RULE_ENABLED") && _b["QV2RAY_RULE_ENABLED"].toBool() == true) { rules.append(_b); }
else
{
LOG(MODULE_SETTINGS, "Discarded a rule as it's been set DISABLED")
}
}
routing["rules"] = rules;
root["routing"] = routing;
} else {
}
else
{
//
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.
if (root["outbounds"].toArray().count() != 1)
{
// There are no ROUTING but 2 or more outbounds.... This is
// rare, but possible.
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.")
}
@ -337,11 +364,13 @@ namespace Qv2ray::core::connection
// Process forward proxy
#define fpConf GlobalConfig.connectionConfig.forwardProxyConfig
if (fpConf.enableForwardProxy) {
if (fpConf.enableForwardProxy)
{
auto outboundArray = root["outbounds"].toArray();
auto firstOutbound = outboundArray.first().toObject();
if (firstOutbound[QV2RAY_USE_FPROXY_KEY].toBool(false)) {
if (firstOutbound[QV2RAY_USE_FPROXY_KEY].toBool(false))
{
LOG(MODULE_CONNECTION, "Applying forward proxy to current connection.")
auto proxy = PROXYSETTING();
proxy["tag"] = OUTBOUND_TAG_FORWARD_PROXY;
@ -349,13 +378,20 @@ namespace Qv2ray::core::connection
// FP Outbound.
OUTBOUNDSETTING fpOutbound;
if (fpConf.type.toLower() == "http" || fpConf.type.toLower() == "socks") {
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 {
if (fpConf.type.toLower() == "http" || fpConf.type.toLower() == "socks")
{
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(MODULE_CONNECTION, "WARNING: Unsupported outbound type: " + fpConf.type)
}
} else {
}
else
{
// Remove proxySettings from firstOutbound
firstOutbound.remove("proxySettings");
}
@ -366,7 +402,8 @@ namespace Qv2ray::core::connection
#undef fpConf
OUTBOUNDS outbounds = OUTBOUNDS(root["outbounds"].toArray());
outbounds.append(GenerateOutboundEntry("freedom", GenerateFreedomOUT("AsIs", ":0", 0), QJsonObject(), QJsonObject(), "0.0.0.0", OUTBOUND_TAG_DIRECT));
outbounds.append(GenerateOutboundEntry("freedom", GenerateFreedomOUT("AsIs", ":0", 0), QJsonObject(), QJsonObject(), "0.0.0.0",
OUTBOUND_TAG_DIRECT));
root["outbounds"] = outbounds;
}
@ -407,7 +444,8 @@ namespace Qv2ray::core::connection
INBOUNDS inbounds = INBOUNDS(root["inbounds"].toArray());
INBOUNDSETTING fakeDocodemoDoor;
fakeDocodemoDoor["address"] = "127.0.0.1";
QJsonObject apiInboundsRoot = GenerateInboundEntry("127.0.0.1", GlobalConfig.apiConfig.statsPort, "dokodemo-door", fakeDocodemoDoor, API_TAG_INBOUND);
QJsonObject apiInboundsRoot =
GenerateInboundEntry("127.0.0.1", GlobalConfig.apiConfig.statsPort, "dokodemo-door", fakeDocodemoDoor, API_TAG_INBOUND);
inbounds.push_front(apiInboundsRoot);
root["inbounds"] = inbounds;
//
@ -417,5 +455,5 @@ namespace Qv2ray::core::connection
}
return root;
}
}
}
} // namespace Generation
} // namespace Qv2ray::core::connection

View File

@ -5,7 +5,7 @@ namespace Qv2ray::core::connection
namespace Generation
{
// Important config generation algorithms.
const QStringList vLogLevels = {"none", "debug", "info", "warning", "error"};
const QStringList vLogLevels = { "none", "debug", "info", "warning", "error" };
ROUTING GenerateRoutes(bool enableProxy, bool cnProxy);
ROUTERULE GenerateSingleRouteRule(QStringList list, bool isDomain, QString outboundTag, QString type = "field");
QJsonObject GenerateDNS(bool withLocalhost, QStringList dnsServers);
@ -15,20 +15,24 @@ namespace Qv2ray::core::connection
OUTBOUNDSETTING GenerateFreedomOUT(QString domainStrategy, QString redirect, int userLevel);
OUTBOUNDSETTING GenerateBlackHoleOUT(bool useHTTP);
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers);
OUTBOUNDSETTING GenerateShadowSocksServerOUT(QString email, QString address, int port, QString method, QString password, bool ota, int level);
OUTBOUNDSETTING GenerateShadowSocksServerOUT(QString email, QString address, int port, QString method, QString password, bool ota,
int level);
OUTBOUNDSETTING GenerateHTTPSOCKSOut(QString address, int port, bool useAuth, QString username, QString password);
//
// Inbounds Protocols
INBOUNDSETTING GenerateDokodemoIN(QString address, int port, QString network, int timeout, bool followRedirect, int userLevel);
INBOUNDSETTING GenerateDokodemoIN(QString address, int port, QString network, int timeout, bool followRedirect, int userLevel);
INBOUNDSETTING GenerateHTTPIN(QList<AccountObject> accounts, int timeout = 300, bool allowTransparent = true, int userLevel = 0);
INBOUNDSETTING GenerateSocksIN(QString auth, QList<AccountObject> _accounts, bool udp = false, QString ip = "127.0.0.1", int userLevel = 0);
INBOUNDSETTING GenerateSocksIN(QString auth, QList<AccountObject> _accounts, bool udp = false, QString ip = "127.0.0.1",
int userLevel = 0);
//
// Generate FINAL Configs
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root);
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux = QJsonObject(), QString sendThrough = "0.0.0.0", QString tag = OUTBOUND_TAG_PROXY);
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing = QJsonObject(), QJsonObject allocate = QJsonObject());
}
}
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux = QJsonObject(),
QString sendThrough = "0.0.0.0", QString tag = OUTBOUND_TAG_PROXY);
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag,
QJsonObject sniffing = QJsonObject(), QJsonObject allocate = QJsonObject());
} // namespace Generation
} // namespace Qv2ray::core::connection
using namespace Qv2ray::core;
using namespace Qv2ray::core::connection;

View File

@ -33,57 +33,68 @@ namespace Qv2ray::core::handlers
* - log list
* in case of error, no objects will be returned.
*/
std::pair <std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList>
decodeSSD(const QString &uri, const QString &pattern = DEFAULT_NAME_PATTERN);
}
}
std::pair<std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList> decodeSSD(
const QString &uri, const QString &pattern = DEFAULT_NAME_PATTERN);
} // namespace ssd
} // namespace Qv2ray::core::handlers
#define MUST_EXIST(fieldName) \
if (obj[(fieldName)].isUndefined()) {\
logList << QObject::tr("invalid ssd link: json: field %1 must exist").arg(fieldName);\
return std::make_pair(std::nullopt, logList);\
#define MUST_EXIST(fieldName) \
if (obj[(fieldName)].isUndefined()) \
{ \
logList << QObject::tr("invalid ssd link: json: field %1 must exist").arg(fieldName); \
return std::make_pair(std::nullopt, logList); \
}
#define MUST_PORT(fieldName) MUST_EXIST(fieldName);\
if (int value = obj[(fieldName)].toInt(-1); value < 0 || value > 65535) { \
logList << QObject::tr("invalid ssd link: json: field %1 must be valid port number");\
return std::make_pair(std::nullopt, logList);\
#define MUST_PORT(fieldName) \
MUST_EXIST(fieldName); \
if (int value = obj[(fieldName)].toInt(-1); value < 0 || value > 65535) \
{ \
logList << QObject::tr("invalid ssd link: json: field %1 must be valid port number"); \
return std::make_pair(std::nullopt, logList); \
}
#define MUST_STRING(fieldName) MUST_EXIST(fieldName);\
if (!obj[(fieldName)].isString()) {\
logList << QObject::tr("invalid ssd link: json: field %1 must be of type 'string'").arg(fieldName);\
return std::make_pair(std::nullopt, logList);\
#define MUST_STRING(fieldName) \
MUST_EXIST(fieldName); \
if (!obj[(fieldName)].isString()) \
{ \
logList << QObject::tr("invalid ssd link: json: field %1 must be of type 'string'").arg(fieldName); \
return std::make_pair(std::nullopt, logList); \
}
#define MUST_ARRAY(fieldName) MUST_EXIST(fieldName);\
if (!obj[(fieldName)].isArray()) {\
logList << QObject::tr("invalid ssd link: json: field %1 must be an array").arg(fieldName);\
return std::make_pair(std::nullopt, logList);\
#define MUST_ARRAY(fieldName) \
MUST_EXIST(fieldName); \
if (!obj[(fieldName)].isArray()) \
{ \
logList << QObject::tr("invalid ssd link: json: field %1 must be an array").arg(fieldName); \
return std::make_pair(std::nullopt, logList); \
}
#define SERVER_SHOULD_BE_OBJECT(server) \
if (!server.isObject()) {\
logList << QObject::tr("skipping invalid ssd server: server must be an object");\
continue;\
#define SERVER_SHOULD_BE_OBJECT(server) \
if (!server.isObject()) \
{ \
logList << QObject::tr("skipping invalid ssd server: server must be an object"); \
continue; \
}
#define SHOULD_EXIST(fieldName) \
if (serverObject[(fieldName)].isUndefined()) { \
logList << QObject::tr("skipping invalid ssd server: missing required field %1").arg(fieldName);\
continue;\
#define SHOULD_EXIST(fieldName) \
if (serverObject[(fieldName)].isUndefined()) \
{ \
logList << QObject::tr("skipping invalid ssd server: missing required field %1").arg(fieldName); \
continue; \
}
#define SHOULD_STRING(fieldName) SHOULD_EXIST(fieldName); \
if (!serverObject[(fieldName)].isString()) { \
logList << QObject::tr("skipping invalid ssd server: field %1 should be of type 'string'").arg(fieldName);\
continue; \
#define SHOULD_STRING(fieldName) \
SHOULD_EXIST(fieldName); \
if (!serverObject[(fieldName)].isString()) \
{ \
logList << QObject::tr("skipping invalid ssd server: field %1 should be of type 'string'").arg(fieldName); \
continue; \
}
std::pair <std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList>
Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &pattern)
std::pair<std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList> Qv2ray::core::handlers::ssd::
decodeSSD(const QString &uri, const QString &pattern)
{
// The list for the parsing log.
QStringList logList;
// ssd links should begin with "ssd://"
if (!uri.startsWith("ssd://")) {
if (!uri.startsWith("ssd://"))
{
logList << QObject::tr("invalid ssd link: should begin with ssd://");
return std::make_pair(std::nullopt, logList);
}
@ -92,7 +103,8 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
const auto ssdURIBody = QStringRef(&uri, 5, uri.length() - 6);
const auto decodedJSON = QByteArray::fromBase64(ssdURIBody.toUtf8());
if (decodedJSON.length() == 0) {
if (decodedJSON.length() == 0)
{
logList << QObject::tr("invalid ssd link: base64 parse failed");
return std::make_pair(std::nullopt, logList);
}
@ -101,13 +113,15 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
QJsonParseError err;
QJsonDocument document = QJsonDocument::fromJson(decodedJSON, &err);
if (document.isNull()) {
if (document.isNull())
{
logList << QObject::tr("invalid ssd link: json parse failed: ") % err.errorString();
return std::make_pair(std::nullopt, logList);
}
// json should be an object
if (!document.isObject()) {
if (!document.isObject())
{
logList << QObject::tr("invalid ssd link: found non-object json, aborting");
return std::make_pair(std::nullopt, logList);
}
@ -127,7 +141,8 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
// check: rc4-md5 is not supported by v2ray-core
// TODO: more checks, including all algorithms
if (encryption == "rc4-md5") {
if (encryption == "rc4-md5")
{
logList << QObject::tr("invalid ssd link: rc4-md5 encryption is not supported by v2ray-core");
return std::make_pair(std::nullopt, logList);
}
@ -142,7 +157,8 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
//
// iterate through the servers
for (QJsonValueRef server : obj["servers"].toArray()) {
for (QJsonValueRef server : obj["servers"].toArray())
{
SERVER_SHOULD_BE_OBJECT(server);
QJsonObject serverObject = server.toObject();
ShadowSocksServerObject ssObject;
@ -158,11 +174,13 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
// port selection:
// normal: use global settings
// overriding: use current config
if (serverObject["port"].isUndefined()) {
ssObject.port = port;
} else if (auto currPort = serverObject["port"].toInt(-1); port >= 0 && port <= 65535) {
if (serverObject["port"].isUndefined()) { ssObject.port = port; }
else if (auto currPort = serverObject["port"].toInt(-1); port >= 0 && port <= 65535)
{
ssObject.port = currPort;
} else {
}
else
{
logList << QObject::tr("warning: invalid port encountered. using fallback value.");
ssObject.port = port;
}
@ -172,11 +190,13 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
// entitled: using given name
QString nodeName;
if (serverObject["remarks"].isUndefined()) {
nodeName = QString("%1:%2").arg(ssObject.address).arg(ssObject.port);
} else if (serverObject["remarks"].isString()) {
if (serverObject["remarks"].isUndefined()) { nodeName = QString("%1:%2").arg(ssObject.address).arg(ssObject.port); }
else if (serverObject["remarks"].isString())
{
nodeName = serverObject["remarks"].toString();
} else {
}
else
{
logList << QObject::tr("warning: invalid name encountered. using fallback value.");
nodeName = QString("%1:%2").arg(ssObject.address).arg(ssObject.port);
}
@ -186,9 +206,9 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
// specified: use given value
double ratio = 1.0;
if (auto currRatio = serverObject["ratio"].toDouble(-1.0); currRatio != -1.0) {
ratio = currRatio;
} else if (!serverObject["ratio"].isUndefined()) {
if (auto currRatio = serverObject["ratio"].toDouble(-1.0); currRatio != -1.0) { ratio = currRatio; }
else if (!serverObject["ratio"].isUndefined())
{
logList << QObject::tr("warning: invalid ratio encountered. using fallback value.");
}

View File

@ -1,4 +1,5 @@
#include "Serialization.hpp"
#include "Generation.hpp"
#include "common/QvHelpers.hpp"
#include "core/CoreUtils.hpp"
@ -12,11 +13,13 @@ namespace Qv2ray::core::connection
{
CONFIGROOT config;
if (link.startsWith("vmess://")) {
config = ConvertConfigFromVMessString(link, alias, errMessage);
} else if (link.startsWith("ss://")) {
if (link.startsWith("vmess://")) { config = ConvertConfigFromVMessString(link, alias, errMessage); }
else if (link.startsWith("ss://"))
{
config = ConvertConfigFromSSString(link, alias, errMessage);
} else {
}
else
{
*errMessage = QObject::tr("Unsupported share link format.");
}
@ -31,21 +34,29 @@ namespace Qv2ray::core::connection
auto type = outbound["protocol"].toString();
QString sharelink = "";
if (type == "vmess") {
auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outbound["settings"].toObject()["vnext"].toArray().first().toObject()));
if (type == "vmess")
{
auto vmessServer =
StructFromJsonString<VMessServerObject>(JsonToString(outbound["settings"].toObject()["vnext"].toArray().first().toObject()));
auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outbound["streamSettings"].toObject()));
sharelink = ConvertConfigToVMessString(transport, vmessServer, alias);
} else if (type == "shadowsocks") {
auto ssServer = StructFromJsonString<ShadowSocksServerObject>(JsonToString(outbound["settings"].toObject()["servers"].toArray().first().toObject()));
}
else if (type == "shadowsocks")
{
auto ssServer = StructFromJsonString<ShadowSocksServerObject>(
JsonToString(outbound["settings"].toObject()["servers"].toArray().first().toObject()));
sharelink = ConvertConfigToSSString(ssServer, alias, isSip002);
} else {
}
else
{
LOG(MODULE_CONNECTION, "Unsupported outbound type: " + type)
}
return sharelink;
}
// From https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
// From
// https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias)
{
QJsonObject vmessUriRoot;
@ -59,15 +70,19 @@ namespace Qv2ray::core::connection
vmessUriRoot["net"] = transfer.network;
vmessUriRoot["tls"] = transfer.security;
if (transfer.network == "tcp") {
vmessUriRoot["type"] = transfer.tcpSettings.header.type;
} else if (transfer.network == "kcp") {
if (transfer.network == "tcp") { vmessUriRoot["type"] = transfer.tcpSettings.header.type; }
else if (transfer.network == "kcp")
{
vmessUriRoot["type"] = transfer.kcpSettings.header.type;
} else if (transfer.network == "quic") {
}
else if (transfer.network == "quic")
{
vmessUriRoot["type"] = transfer.quicSettings.header.type;
vmessUriRoot["host"] = transfer.quicSettings.security;
vmessUriRoot["path"] = transfer.quicSettings.key;
} else if (transfer.network == "ws") {
}
else if (transfer.network == "ws")
{
auto x = transfer.wsSettings.headers;
auto host = x.contains("host");
auto CapHost = x.contains("Host");
@ -75,7 +90,9 @@ namespace Qv2ray::core::connection
//
vmessUriRoot["host"] = realHost;
vmessUriRoot["path"] = transfer.wsSettings.path;
} else if (transfer.network == "h2" || transfer.network == "http") {
}
else if (transfer.network == "h2" || transfer.network == "http")
{
vmessUriRoot["host"] = transfer.httpSettings.host.join(",");
vmessUriRoot["path"] = transfer.httpSettings.path;
}
@ -89,8 +106,8 @@ namespace Qv2ray::core::connection
{
// String may start with: vmess:// and ss://
// We only process vmess:// here
// Some subscription providers may use plain vmess:// saperated by lines
// But others may use base64 of above.
// Some subscription providers may use plain vmess:// saperated by
// lines But others may use base64 of above.
auto result = QString::fromUtf8(arr).trimmed();
return result.startsWith("vmess://") ? result : Base64Decode(result);
}
@ -100,8 +117,9 @@ namespace Qv2ray::core::connection
ShadowSocksServerObject server;
QString d_name;
//auto ssUri = _ssUri.toStdString();
if (ssUri.length() < 5) {
// auto ssUri = _ssUri.toStdString();
if (ssUri.length() < 5)
{
LOG(MODULE_CONNECTION, "ss:// string too short")
*errMessage = QObject::tr("SS URI is too short");
}
@ -110,53 +128,51 @@ namespace Qv2ray::core::connection
auto hashPos = uri.lastIndexOf("#");
DEBUG(MODULE_CONNECTION, "Hash sign position: " + QSTRN(hashPos))
if (hashPos >= 0) {
if (hashPos >= 0)
{
// Get the name/remark
d_name = uri.mid(uri.lastIndexOf("#") + 1);
uri.truncate(hashPos);
}
// No plugins for Qv2ray so disable those lnes.i
//size_t pluginPos = uri.find_first_of('/');
// size_t pluginPos = uri.find_first_of('/');
//
//if (pluginPos != std::string::npos) {
// if (pluginPos != std::string::npos) {
// // TODO: support plugins. For now, just ignore them
// uri.erase(pluginPos);
//}
auto atPos = uri.indexOf('@');
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
if (atPos < 0) {
if (atPos < 0)
{
// Old URI scheme
QString decoded = QByteArray::fromBase64(uri.toUtf8(), QByteArray::Base64Option::OmitTrailingEquals);
auto colonPos = decoded.indexOf(':');
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
if (colonPos < 0) {
*errMessage = QObject::tr("Can't find the colon separator between method and password");
}
if (colonPos < 0) { *errMessage = QObject::tr("Can't find the colon separator between method and password"); }
server.method = decoded.left(colonPos);
decoded.remove(0, colonPos + 1);
atPos = decoded.lastIndexOf('@');
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
if (atPos < 0) {
*errMessage = QObject::tr("Can't find the at separator between password and hostname");
}
if (atPos < 0) { *errMessage = QObject::tr("Can't find the at separator between password and hostname"); }
server.password = decoded.mid(0, atPos);
decoded.remove(0, atPos + 1);
colonPos = decoded.lastIndexOf(':');
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
if (colonPos < 0) {
*errMessage = QObject::tr("Can't find the colon separator between hostname and port");
}
if (colonPos < 0) { *errMessage = QObject::tr("Can't find the colon separator between hostname and port"); }
server.address = decoded.mid(0, colonPos);
server.port = decoded.mid(colonPos + 1).toInt();
} else {
}
else
{
// SIP002 URI scheme
auto x = QUrl::fromUserInput(uri);
server.address = x.host();
@ -166,9 +182,7 @@ namespace Qv2ray::core::connection
//
DEBUG(MODULE_CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
if (userInfoSp < 0) {
*errMessage = QObject::tr("Can't find the colon separator between method and password");
}
if (userInfoSp < 0) { *errMessage = QObject::tr("Can't find the colon separator between method and password"); }
QString method = userInfo.mid(0, userInfoSp);
server.method = method;
@ -178,7 +192,8 @@ namespace Qv2ray::core::connection
d_name = QUrl::fromPercentEncoding(d_name.toUtf8());
CONFIGROOT root;
OUTBOUNDS outbounds;
outbounds.append(GenerateOutboundEntry("shadowsocks", GenerateShadowSocksOUT(QList<ShadowSocksServerObject>() << server), QJsonObject()));
outbounds.append(
GenerateOutboundEntry("shadowsocks", GenerateShadowSocksOUT(QList<ShadowSocksServerObject>() << server), QJsonObject()));
JADD(outbounds)
*alias = alias->isEmpty() ? d_name : *alias + "_" + d_name;
LOG(MODULE_CONNECTION, "Deduced alias: " + *alias)
@ -189,12 +204,15 @@ namespace Qv2ray::core::connection
{
auto myAlias = QUrl::toPercentEncoding(alias);
if (isSip002) {
if (isSip002)
{
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 {
}
else
{
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;
@ -209,7 +227,8 @@ namespace Qv2ray::core::connection
LOG(MODULE_SETTINGS, "Trying to convert from a vmess string.")
QString vmess = vmessStr;
if (vmess.trimmed() != vmess) {
if (vmess.trimmed() != vmess)
{
LOG(MODULE_SETTINGS, "VMess string has some prefix/postfix spaces, trimming.")
vmess = vmessStr.trimmed();
}
@ -217,16 +236,19 @@ namespace Qv2ray::core::connection
// Reset errMessage
*errMessage = "";
if (!vmess.toLower().startsWith("vmess://")) {
if (!vmess.toLower().startsWith("vmess://"))
{
*errMessage = QObject::tr("VMess string should start with 'vmess://'");
return default;
}
try {
try
{
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8);
auto b64Str = vmessJsonB64.toString();
if (b64Str.isEmpty()) {
if (b64Str.isEmpty())
{
*errMessage = QObject::tr("VMess string should be a valid base64 string");
return default;
}
@ -234,14 +256,16 @@ namespace Qv2ray::core::connection
auto vmessString = Base64Decode(b64Str);
auto jsonErr = VerifyJsonString(vmessString);
if (!jsonErr.isEmpty()) {
if (!jsonErr.isEmpty())
{
*errMessage = jsonErr;
return default;
}
auto vmessConf = JsonFromString(vmessString);
if (vmessConf.isEmpty()) {
if (vmessConf.isEmpty())
{
*errMessage = QObject::tr("JSON should not be empty");
return default;
}
@ -249,21 +273,23 @@ namespace Qv2ray::core::connection
bool flag = true;
// C is a quick hack...
#define C(k) vmessConf.contains(k)
// id, aid, port and add are mandatory fields of a vmess:// link.
// id, aid, port and add are mandatory fields of a vmess://
// link.
flag = flag && C("id") && C("aid") && C("port") && C("add");
// Stream Settings
auto net = C("net") ? vmessConf["net"].toString() : "tcp";
if (net == "http" || net == "ws")
flag = flag && C("host") && C("path");
if (net == "http" || net == "ws") flag = flag && C("host") && C("path");
else if (net == "domainsocket")
flag = flag && C("path");
else if (net == "quic")
flag = flag && C("host") && C("type") && C("path");
#undef C
//return flag ? 0 : 1;
} catch (exception *e) {
// return flag ? 0 : 1;
}
catch (exception *e)
{
*errMessage = e->what();
LOG(MODULE_IMPORT, "Failed to decode vmess string: " + *errMessage)
delete e;
@ -279,44 +305,62 @@ namespace Qv2ray::core::connection
int port, aid;
//
// key = key in JSON and the variable name.
// values = Candidate variable list, if not match, the first one is used as default.
// [[val.size() <= 1]] is used when only the default value exists.
// - It can be empty, if so, if the key is not in the JSON, or the value is empty, it'll report an error.
// - Else if it contains one thing. if the key is not in the JSON, or the value is empty, it'll use that one.
// - Else if it contains many things, when the key IS in the JSON but not in those THINGS, it'll use the first one in the THINGS
// values = Candidate variable list, if not match, the first one is
// used as default.
// [[val.size() <= 1]] is used when only the default value
// exists.
// - It can be empty, if so, if the key is not in
// the JSON, or the value is empty, it'll report an error.
// - Else if it contains one thing. if the key is not in
// the JSON, or the value is empty, it'll use that one.
// - Else if it contains many things, when the key IS in
// the JSON but not in those THINGS, it'll use the first
// one in the THINGS
// - Else, it'll use the value found from the JSON object.
//
#define empty_arg
#define __vmess_checker__func(key, values) \
{\
auto val = QStringList() values;\
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(MODULE_IMPORT, "Found key \"" #key "\" within the vmess object.")\
} else if (!val.isEmpty()) {\
key = val.first(); \
DEBUG(MODULE_IMPORT, "Using key \"" #key "\" from the first candidate list: " + key)\
} else{\
*errMessage = QObject::tr(#key " does not exist."); \
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) \
}\
#define __vmess_checker__func(key, values) \
{ \
auto val = QStringList() values; \
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(MODULE_IMPORT, "Found key \"" #key "\" within the vmess object.") \
} \
else if (!val.isEmpty()) \
{ \
key = val.first(); \
DEBUG(MODULE_IMPORT, "Using key \"" #key "\" from the first candidate list: " + key) \
} \
else \
{ \
*errMessage = QObject::tr(#key " does not exist."); \
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.
// Strict check of VMess protocol, to check if the specified value
// is in the correct range.
//
// Get Alias (AKA ps) from address and port.
__vmess_checker__func(ps, << vmessConf["add"].toVariant().toString() + ":" + vmessConf["port"].toVariant().toString());
__vmess_checker__func(add, empty_arg)
__vmess_checker__func(id, empty_arg)
__vmess_checker__func(net, << "tcp" << "http" << "h2" << "ws" << "kcp" << "domainsocket" << "quic")
__vmess_checker__func(type, << "none" << "http" << "srtp" << "utp" << "wechat-video")
__vmess_checker__func(path, << "")
__vmess_checker__func(host, << "")
__vmess_checker__func(tls, << "")
//
port = vmessConf["port"].toVariant().toInt();
__vmess_checker__func(add, empty_arg) __vmess_checker__func(id, empty_arg) __vmess_checker__func(net, << "tcp"
<< "http"
<< "h2"
<< "ws"
<< "kcp"
<< "domainsocket"
<< "quic")
__vmess_checker__func(type, << "none"
<< "http"
<< "srtp"
<< "utp"
<< "wechat-video") __vmess_checker__func(path, << "") __vmess_checker__func(host, << "")
__vmess_checker__func(tls, << "")
//
port = vmessConf["port"].toVariant().toInt();
aid = vmessConf["aid"].toVariant().toInt();
// Apply the settings.
//
@ -340,23 +384,29 @@ namespace Qv2ray::core::connection
// Stream Settings
StreamSettingsObject streaming;
if (net == "tcp") {
streaming.tcpSettings.header.type = type;
} else if (net == "http" || net == "h2") {
if (net == "tcp") { streaming.tcpSettings.header.type = type; }
else if (net == "http" || net == "h2")
{
// Fill hosts for HTTP
for (auto _host : host.split(',')) {
streaming.httpSettings.host.push_back(_host.trimmed());
}
for (auto _host : host.split(',')) { streaming.httpSettings.host.push_back(_host.trimmed()); }
streaming.httpSettings.path = path;
} else if (net == "ws") {
}
else if (net == "ws")
{
streaming.wsSettings.headers["Host"] = host;
streaming.wsSettings.path = path;
} else if (net == "kcp") {
}
else if (net == "kcp")
{
streaming.kcpSettings.header.type = type;
} else if (net == "domainsocket") {
}
else if (net == "domainsocket")
{
streaming.dsSettings.path = path;
} else if (net == "quic") {
}
else if (net == "quic")
{
streaming.quicSettings.security = host;
streaming.quicSettings.header.type = type;
streaming.quicSettings.key = path;
@ -364,7 +414,8 @@ namespace Qv2ray::core::connection
// FIXME: makeshift patch for #290.
// to be rewritten after refactoring.
if (tls == "tls" && host != "" && (net == "tcp" || net == "ws")) {
if (tls == "tls" && host != "" && (net == "tcp" || net == "ws"))
{
streaming.tlsSettings.serverName = host;
streaming.tlsSettings.allowInsecure = false;
}
@ -378,10 +429,11 @@ namespace Qv2ray::core::connection
auto outbound = GenerateOutboundEntry("vmess", vConf, GetRootObject(streaming), QJsonObject(), "0.0.0.0", OUTBOUND_TAG_PROXY);
//
root["outbounds"] = QJsonArray() << outbound;
// If previous alias is empty, just the PS is needed, else, append a "_"
// If previous alias is empty, just the PS is needed, else, append a
// "_"
*alias = alias->trimmed().isEmpty() ? ps : *alias + "_" + ps;
#undef default
return root;
}
}
}
} // namespace Serialization
} // namespace Qv2ray::core::connection

View File

@ -5,7 +5,7 @@ namespace Qv2ray::core::connection
{
namespace Serialization
{
//int VerifyVMessProtocolString(QString vmess);
// int VerifyVMessProtocolString(QString vmess);
QString DecodeSubscriptionString(QByteArray arr);
// General
@ -19,8 +19,8 @@ namespace Qv2ray::core::connection
// SS URI Protocol
CONFIGROOT ConvertConfigFromSSString(const QString &ss, QString *alias, QString *errMessage);
QString ConvertConfigToSSString(const ShadowSocksServerObject &server, const QString &alias, bool isSip002);
}
}
} // namespace Serialization
} // namespace Qv2ray::core::connection
using namespace Qv2ray::core;
using namespace Qv2ray::core::connection;

View File

@ -1,6 +1,8 @@
#include "ConnectionHandler.hpp"
#include "common/QvHelpers.hpp"
#include "core/config/ConfigBackend.hpp"
#include "core/connection/Serialization.hpp"
namespace Qv2ray::core::handlers
{
@ -10,26 +12,23 @@ namespace Qv2ray::core::handlers
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.connections.count(); i++)
{ connections[ConnectionId(GlobalConfig.connections.keys()[i])] = GlobalConfig.connections.values()[i]; }
for (auto key : GlobalConfig.subscriptions.keys()) {
for (auto key : GlobalConfig.subscriptions.keys())
{
auto val = GlobalConfig.subscriptions[key];
groups[GroupId(key)] = val;
for (auto conn : val.connections) {
connections[ConnectionId(conn)].groupId = GroupId(key);
}
for (auto conn : val.connections) { connections[ConnectionId(conn)].groupId = GroupId(key); }
}
for (auto key : GlobalConfig.groups.keys()) {
for (auto key : GlobalConfig.groups.keys())
{
auto val = GlobalConfig.groups[key];
groups[GroupId(key)] = val;
for (auto conn : val.connections) {
connections[ConnectionId(conn)].groupId = GroupId(key);
}
for (auto conn : val.connections) { connections[ConnectionId(conn)].groupId = GroupId(key); }
}
vCoreInstance = new V2rayKernelInstance();
@ -47,7 +46,7 @@ namespace Qv2ray::core::handlers
pingConnectionTimerId = startTimer(60 * 1000);
}
void QvConnectionHandler::CHSaveConnectionData_p()
void QvConnectionHandler::CHSaveConfigData_p()
{
// Copy
auto newGlobalConfig = GlobalConfig;
@ -55,18 +54,21 @@ namespace Qv2ray::core::handlers
newGlobalConfig.groups.clear();
newGlobalConfig.subscriptions.clear();
for (auto i = 0; i < connections.count(); i++) {
newGlobalConfig.connections[connections.keys()[i].toString()] = connections.values()[i];
}
for (auto i = 0; i < connections.count(); i++)
{ newGlobalConfig.connections[connections.keys()[i].toString()] = connections.values()[i]; }
for (auto i = 0; i < groups.count(); i++) {
for (auto i = 0; i < groups.count(); i++)
{
QStringList connections = IdListToStrings(groups.values()[i].connections);
if (groups.values()[i].isSubscription) {
if (groups.values()[i].isSubscription)
{
SubscriptionObject_Config o = groups.values()[i];
o.connections = connections;
newGlobalConfig.subscriptions[groups.keys()[i].toString()] = o;
} else {
}
else
{
GroupObject_Config o = groups.values()[i];
o.connections = connections;
newGlobalConfig.groups[groups.keys()[i].toString()] = o;
@ -78,29 +80,25 @@ namespace Qv2ray::core::handlers
void QvConnectionHandler::timerEvent(QTimerEvent *event)
{
if (event->timerId() == saveTimerId) {
CHSaveConnectionData_p();
} else if (event->timerId() == pingAllTimerId) {
if (event->timerId() == saveTimerId) { CHSaveConfigData_p(); }
else if (event->timerId() == pingAllTimerId)
{
StartLatencyTest();
} else if (event->timerId() == pingConnectionTimerId) {
if (currentConnectionId != NullConnectionId) {
StartLatencyTest(currentConnectionId);
}
}
else if (event->timerId() == pingConnectionTimerId)
{
if (currentConnectionId != NullConnectionId) { StartLatencyTest(currentConnectionId); }
}
}
void QvConnectionHandler::StartLatencyTest()
{
for (auto connection : connections.keys()) {
StartLatencyTest(connection);
}
for (auto connection : connections.keys()) { StartLatencyTest(connection); }
}
void QvConnectionHandler::StartLatencyTest(const GroupId &id)
{
for (auto connection : groups[id].connections) {
StartLatencyTest(connection);
}
for (auto connection : groups[id].connections) { StartLatencyTest(connection); }
}
void QvConnectionHandler::StartLatencyTest(const ConnectionId &id)
@ -123,10 +121,9 @@ namespace Qv2ray::core::handlers
{
QList<GroupId> subsList;
for (auto group : groups.keys()) {
if (groups[group].isSubscription) {
subsList.push_back(group);
}
for (auto group : groups.keys())
{
if (groups[group].isSubscription) { subsList.push_back(group); }
}
return subsList;
@ -149,10 +146,9 @@ namespace Qv2ray::core::handlers
const ConnectionId QvConnectionHandler::GetConnectionIdByDisplayName(const QString &displayName) const
{
for (auto conn : connections.keys()) {
if (connections[conn].displayName == displayName) {
return conn;
}
for (auto conn : connections.keys())
{
if (connections[conn].displayName == displayName) { return conn; }
}
return NullConnectionId;
@ -160,10 +156,9 @@ namespace Qv2ray::core::handlers
const GroupId QvConnectionHandler::GetGroupIdByDisplayName(const QString &displayName) const
{
for (auto group : groups.keys()) {
if (groups[group].displayName == displayName) {
return group;
}
for (auto group : groups.keys())
{
if (groups[group].displayName == displayName) { return group; }
}
return NullGroupId;
@ -171,48 +166,57 @@ namespace Qv2ray::core::handlers
const GroupId QvConnectionHandler::GetConnectionGroupId(const ConnectionId &id) const
{
if (!connections.contains(id)) {
LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString());
}
if (!connections.contains(id)) { LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString()); }
return connections[id].groupId;
}
double QvConnectionHandler::GetConnectionLatency(const ConnectionId &id) const
{
if (!connections.contains(id)) {
LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString());
}
if (!connections.contains(id)) { LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString()); }
return connections[id].latency;
}
const optional<QString> QvConnectionHandler::DeleteConnection(const ConnectionId &id)
{
// TODO
Q_UNUSED(id)
return "";
//
auto groupId = connections[id].groupId;
QFile connectionFile((groups[groupId].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR) + groupId.toString() + "/" +
id.toString() + QV2RAY_CONFIG_FILE_EXTENSION);
//
bool exists = connectionFile.exists();
if (exists)
{
bool removed = connectionFile.remove();
if (removed)
{
connections.remove(id);
groups[groupId].connections.removeAll(id);
return {};
}
else
return "Failed to remove file";
}
else
return tr("File does not exist.");
}
const optional<QString> QvConnectionHandler::StartConnection(const ConnectionId &identifier)
{
if (!connections.contains(identifier)) {
return tr("No connection selected!") + NEWLINE + tr("Please select a config from the list.");
}
if (!connections.contains(identifier)) { return tr("No connection selected!") + NEWLINE + tr("Please select a config from the list."); }
if (currentConnectionId != NullConnectionId) {
StopConnection();
}
if (currentConnectionId != NullConnectionId) { StopConnection(); }
CONFIGROOT root = GetConnectionRoot(connections[identifier].groupId, identifier);
return CHStartConnection_p(identifier, root);
}
void QvConnectionHandler::StopConnection() //const ConnectionId &id
void QvConnectionHandler::StopConnection() // const ConnectionId &id
{
// Currently just simply stop it.
//_UNUSED(id)
//if (currentConnectionId == id) {
// if (currentConnectionId == id) {
//}
CHStopConnection_p();
}
@ -226,9 +230,7 @@ namespace Qv2ray::core::handlers
{
QString result;
if (!connections.contains(id)) {
result = tr("N/A");
}
if (!connections.contains(id)) { result = tr("N/A"); }
CONFIGROOT root = GetConnectionRoot(connections[id].groupId, id);
QStringList protocols;
@ -236,12 +238,12 @@ namespace Qv2ray::core::handlers
auto outbound = root["outbounds"].toArray().first().toObject();
result.append(outbound["protocol"].toString());
if (outbound.contains("streamSettings")) {
result.append(" + " + outbound["streamSettings"].toObject()["network"].toString());
if (outbound.contains("streamSettings"))
{
result.append(" / " + outbound["streamSettings"].toObject()["network"].toString());
if (outbound["streamSettings"].toObject().contains("tls")) {
result.append(outbound["streamSettings"].toObject()["tls"].toBool() ? " + tls" : "");
}
if (outbound["streamSettings"].toObject().contains("tls"))
{ result.append(outbound["streamSettings"].toObject()["tls"].toBool() ? " / tls" : ""); }
}
return result;
@ -249,23 +251,23 @@ namespace Qv2ray::core::handlers
const tuple<quint64, quint64> QvConnectionHandler::GetConnectionUsageAmount(const ConnectionId &id) const
{
if (!connections.contains(id)) {
return make_tuple(0, 0);
}
if (!connections.contains(id)) { return make_tuple(0, 0); }
return make_tuple(connections[id].upLinkData, connections[id].downLinkData);
}
//const GroupMetaObject QvConnectionHandler::GetGroup(const GroupId &id) const
// const GroupMetaObject QvConnectionHandler::GetGroup(const GroupId &id)
// const
//{
// return groups[id];
//}
QvConnectionHandler::~QvConnectionHandler()
{
CHSaveConnectionData_p();
CHSaveConfigData_p();
if (vCoreInstance->KernelStarted) {
if (vCoreInstance->KernelStarted)
{
vCoreInstance->StopConnection();
LOG(MODULE_CORE_HANDLER, "Stopped connection from destructor.")
}
@ -285,36 +287,49 @@ namespace Qv2ray::core::handlers
return CONFIGROOT(JsonFromString(StringFromFile(path)));
}
const tuple<QString, int> QvConnectionHandler::GetConnectionInfo(const ConnectionId &id) const
const tuple<QString, QString, int> QvConnectionHandler::GetConnectionData(const ConnectionId &id) const
{
// TODO, what if is complex?
auto root = GetConnectionRoot(id);
bool validOutboundFound = false;
QString host;
int port;
for (auto item : root["outbounds"].toArray()) {
OUTBOUND outBoundRoot = OUTBOUND(item.toObject());
QString outboundType = "";
validOutboundFound = GetOutboundData(outBoundRoot, &host, &port, &outboundType);
if (validOutboundFound) {
return make_tuple(host, port);
} else {
LOG(MODULE_CORE_HANDLER, "Unknown outbound entry: " + outboundType + ", cannot deduce host and port.")
}
}
return make_tuple(QObject::tr("N/A"), 0);
bool isSucceed = false;
auto result = CHGetOutboundData_p(root, &isSucceed);
return result;
}
const tuple<QString, QString, int> QvConnectionHandler::CHGetOutboundData_p(const CONFIGROOT &root, bool *ok) const
{
*ok = false;
for (auto item : root["outbounds"].toArray())
{
OUTBOUND outBoundRoot = OUTBOUND(item.toObject());
QString host;
int port;
QString outboundType = "";
if (GetOutboundData(outBoundRoot, &host, &port, &outboundType))
{
*ok = true;
return make_tuple(outboundType, host, port);
}
else
{
LOG(MODULE_CORE_HANDLER, "Unknown outbound type: " + outboundType + ", cannot deduce host and port.")
}
}
return make_tuple(tr("N/A"), tr("N/A"), 0);
}
void QvConnectionHandler::OnLatencyDataArrived(const QvTCPingResultObject &result)
{
if (connections.contains(result.connectionId)) {
if (connections.contains(result.connectionId))
{
connections[result.connectionId].latency = result.avg;
emit OnLatencyTestFinished(result.connectionId, result.avg);
} else {
}
else
{
LOG(MODULE_CORE_HANDLER, "Received a latecy result with non-exist connection id.")
}
}
@ -322,8 +337,8 @@ namespace Qv2ray::core::handlers
bool QvConnectionHandler::UpdateConnection(const ConnectionId &id, const CONFIGROOT &root)
{
auto groupId = connections[id].groupId;
auto path = (groups[groupId].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR)
+ groupId.toString() + "/" + id.toString() + QV2RAY_CONFIG_FILE_EXTENSION;
auto path = (groups[groupId].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR) + groupId.toString() + "/" +
id.toString() + QV2RAY_CONFIG_FILE_EXTENSION;
auto content = JsonToString(root);
emit OnConnectionChanged(id);
return StringToFile(content, path);
@ -333,10 +348,101 @@ namespace Qv2ray::core::handlers
{
tuple<QString, int64_t, float> result;
if (!groups[id].isSubscription) {
return result;
}
if (!groups[id].isSubscription) { return result; }
return make_tuple(groups[id].address, groups[id].lastUpdated, groups[id].updateInterval);
}
}
bool QvConnectionHandler::UpdateSubscription(const GroupId &id, bool useSystemProxy)
{
if (isHttpRequestInProgress) { return false; }
isHttpRequestInProgress = true;
auto data = httpHelper->syncget(groups[id].address, useSystemProxy);
isHttpRequestInProgress = false;
return CHUpdateSubscription_p(id, data);
}
bool QvConnectionHandler::CHUpdateSubscription_p(const GroupId &id, const QByteArray &subscriptionData)
{
if (!groups.contains(id)) { return false; }
bool isAutoConnectionContainedWithin = groups[id].connections.contains(ConnectionId(GlobalConfig.autoStartId));
Q_UNUSED(isAutoConnectionContainedWithin)
//
// Anyway, we try our best to preserve the connection id.
QMap<QString, ConnectionId> nameMap;
QMap<tuple<QString, QString, int>, ConnectionId> typeMap;
for (auto conn : groups[id].connections)
{
nameMap[GetDisplayName(conn)] = conn;
auto [protocol, host, port] = GetConnectionData(conn);
if (port != 0) { typeMap[make_tuple(protocol, host, port)] = conn; }
}
//
/// List that is holding connection IDs to be updated.
auto connectionsOrig = groups[id].connections;
auto str = DecodeSubscriptionString(subscriptionData);
if (str.isEmpty()) return false;
//
auto subsList = SplitLines(str);
QDir(QV2RAY_SUBSCRIPTION_DIR + id.toString()).removeRecursively();
QDir().mkpath(QV2RAY_SUBSCRIPTION_DIR + id.toString());
bool hasErrorOccured = false;
for (auto vmess : subsList)
{
QString errMessage;
QString _alias;
auto config = ConvertConfigFromString(vmess.trimmed(), &_alias, &errMessage);
if (!errMessage.isEmpty())
{
LOG(MODULE_SUBSCRIPTION, "Processing a subscription with following error: " + errMessage)
hasErrorOccured = true;
continue;
}
bool canGetOutboundData = false;
auto outboundData = CHGetOutboundData_p(config, &canGetOutboundData);
//
// Begin guessing new ConnectionId
if (nameMap.contains(_alias))
{
// Just go and save the connection...
LOG(MODULE_CORE_HANDLER, "Guessed id from name: " + _alias + ", connectionId: " + nameMap[_alias].toString())
UpdateConnection(nameMap[_alias], config);
// Remove Connection Id from the list.
connectionsOrig.removeAll(nameMap[_alias]);
}
else if (canGetOutboundData && typeMap.contains(outboundData))
{
LOG(MODULE_CORE_HANDLER, "Guessed id from protocol/host/port pair for connectionId: " + typeMap[outboundData].toString())
UpdateConnection(typeMap[outboundData], config);
// Update displayName
connections[typeMap[outboundData]].displayName = _alias;
// Remove Connection Id from the list.
connectionsOrig.removeAll(typeMap[outboundData]);
}
else
{
// New connection id is required since nothing matched found...
ConnectionId newId(GenerateUuid());
connections[newId].groupId = id;
connections[newId].importDate = system_clock::to_time_t(system_clock::now());
connections[newId].displayName = _alias;
LOG(MODULE_CORE_HANDLER, "Generated new connectionId.")
UpdateConnection(newId, config);
}
// End guessing connectionId
}
// Check if anything left behind (not being updated or changed significantly)
LOG(MODULE_CORE_HANDLER, "Removed old connections not have been matched.")
for (auto conn : connectionsOrig)
{
LOG(MODULE_CORE_HANDLER, "Removing: " + conn.toString())
DeleteConnection(conn);
}
return hasErrorOccured;
}
} // namespace Qv2ray::core::handlers

View File

@ -1,134 +1,136 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include "common/HTTPRequestHelper.hpp"
#include "core/CoreSafeTypes.hpp"
#include "core/CoreUtils.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include "core/tcping/QvTCPing.hpp"
#include "core/CoreSafeTypes.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/CoreUtils.hpp"
#include "common/HTTPRequestHelper.hpp"
namespace Qv2ray::core::handlers
{
class QvConnectionHandler : public QObject
{
Q_OBJECT
public:
explicit QvConnectionHandler();
~QvConnectionHandler();
//
const QList<ConnectionId> Connections() const;
//
const QList<GroupId> AllGroups() const;
const QList<GroupId> Subscriptions() const;
const QList<ConnectionId> Connections(const GroupId &groupId) const;
//
// Generic Get Options
const QString GetDisplayName(const GroupId &id, int limit = -1) const;
const QString GetDisplayName(const ConnectionId &id, int limit = -1) const;
const GroupId GetGroupIdByDisplayName(const QString &displayName) const;
const ConnectionId GetConnectionIdByDisplayName(const QString &displayName) const;
//
// Connectivity Operationss
bool IsConnected(const ConnectionId &id) const;
const optional<QString> StartConnection(const ConnectionId &identifier);
void StopConnection(); //const ConnectionId &id
//
// Connection Operations.
const GroupId GetConnectionGroupId(const ConnectionId &id) const;
double GetConnectionLatency(const ConnectionId &id) const;
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
const optional<QString> DeleteConnection(const ConnectionId &id);
bool UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
const optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
const ConnectionId DuplicateConnection(const ConnectionId &id);
const optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
//
const CONFIGROOT GetConnectionRoot(const ConnectionId &id) const;
const CONFIGROOT GetConnectionRoot(const GroupId &group, const ConnectionId &id) const;
//
// Get Conncetion Property
const QString GetConnectionProtocolString(const ConnectionId &id) const;
const tuple<QString, int> GetConnectionInfo(const ConnectionId &connectionId) const;
const tuple<quint64, quint64> GetConnectionUsageAmount(const ConnectionId &id) const;
//
// Misc Connection Operations
void StartLatencyTest();
void StartLatencyTest(const GroupId &id);
void StartLatencyTest(const ConnectionId &id);
//
// Group Operations
const optional<QString> DeleteGroup(const GroupId &id);
const optional<QString> DuplicateGroup(const GroupId &id);
const GroupId &CreateGroup(const QString displayName, bool isSubscription);
const optional<QString> RenameGroup(const GroupId &id, const QString &newName);
//
// Subscriptions
const optional<QString> UpdateSubscription(const GroupId &id, bool useSystemProxy);
const optional<QString> UpdateSubscriptionASync(const GroupId &id, bool useSystemProxy);
const tuple<QString, int64_t, float> GetSubscriptionData(const GroupId &id);
Q_OBJECT
public:
explicit QvConnectionHandler();
~QvConnectionHandler();
//
const QList<ConnectionId> Connections() const;
//
const QList<GroupId> AllGroups() const;
const QList<GroupId> Subscriptions() const;
const QList<ConnectionId> Connections(const GroupId &groupId) const;
//
// Generic Get Options
const QString GetDisplayName(const GroupId &id, int limit = -1) const;
const QString GetDisplayName(const ConnectionId &id, int limit = -1) const;
const GroupId GetGroupIdByDisplayName(const QString &displayName) const;
const ConnectionId GetConnectionIdByDisplayName(const QString &displayName) const;
//
// Connectivity Operationss
bool IsConnected(const ConnectionId &id) const;
const optional<QString> StartConnection(const ConnectionId &identifier);
void StopConnection(); // const ConnectionId &id
//
// Connection Operations.
const GroupId GetConnectionGroupId(const ConnectionId &id) const;
double GetConnectionLatency(const ConnectionId &id) const;
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
const optional<QString> DeleteConnection(const ConnectionId &id);
bool UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
const optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
const ConnectionId DuplicateConnection(const ConnectionId &id);
const optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
//
const CONFIGROOT GetConnectionRoot(const ConnectionId &id) const;
const CONFIGROOT GetConnectionRoot(const GroupId &group, const ConnectionId &id) const;
//
// Get Conncetion Property
const QString GetConnectionProtocolString(const ConnectionId &id) const;
const tuple<QString, QString, int> GetConnectionData(const ConnectionId &connectionId) const;
const tuple<quint64, quint64> GetConnectionUsageAmount(const ConnectionId &id) const;
//
// Misc Connection Operations
void StartLatencyTest();
void StartLatencyTest(const GroupId &id);
void StartLatencyTest(const ConnectionId &id);
//
// Group Operations
const optional<QString> DeleteGroup(const GroupId &id);
const optional<QString> DuplicateGroup(const GroupId &id);
const GroupId &CreateGroup(const QString displayName, bool isSubscription);
const optional<QString> RenameGroup(const GroupId &id, const QString &newName);
//
// Subscriptions
bool UpdateSubscription(const GroupId &id, bool useSystemProxy);
bool UpdateSubscriptionASync(const GroupId &id, bool useSystemProxy);
const tuple<QString, int64_t, float> GetSubscriptionData(const GroupId &id);
signals:
void OnCrashed();
void OnConnected(const ConnectionId &id);
void OnDisConnected(const ConnectionId &id);
void OnVCoreLogAvailable(const ConnectionId &id, const QString &log);
void OnStatsAvailable(const ConnectionId &id,
const quint64 uploadSpeed, const quint64 downloadSpeed,
const quint64 totalUpload, const quint64 totalDownload);
//
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 OnLatencyTestStarted(const ConnectionId &id);
void OnLatencyTestFinished(const ConnectionId &id, const uint average);
//
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 GroupId &id, const QString &displayName, const QString &address);
//void OnSubscriptionDeleted(const GroupId &id, const QString &oldName, const QString &newName);
void OnSubscriptionUpdateFinished(const GroupId &id);
signals:
void OnCrashed();
void OnConnected(const ConnectionId &id);
void OnDisConnected(const ConnectionId &id);
void OnVCoreLogAvailable(const ConnectionId &id, const QString &log);
void OnStatsAvailable(const ConnectionId &id, const quint64 uploadSpeed, const quint64 downloadSpeed, const quint64 totalUpload,
const quint64 totalDownload);
//
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 OnLatencyTestStarted(const ConnectionId &id);
void OnLatencyTestFinished(const ConnectionId &id, const uint average);
//
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 GroupId &id, const QString &displayName, const QString &address);
// void OnSubscriptionDeleted(const GroupId &id, const QString &oldName, const QString &newName);
void OnSubscriptionUpdateFinished(const GroupId &id);
private slots:
void OnStatsDataArrived(const ConnectionId &id, const quint64 uploadSpeed, const quint64 downloadSpeed);
void OnVCoreCrashed(const ConnectionId &id);
void OnLatencyDataArrived(const QvTCPingResultObject &data);
private slots:
void OnStatsDataArrived(const ConnectionId &id, const quint64 uploadSpeed, const quint64 downloadSpeed);
void OnVCoreCrashed(const ConnectionId &id);
void OnLatencyDataArrived(const QvTCPingResultObject &data);
protected:
void timerEvent(QTimerEvent *event) override;
protected:
void timerEvent(QTimerEvent *event) override;
private:
void CHSaveConnectionData_p();
//
optional<QString> CHStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
void CHStopConnection_p();
bool CHSaveConnectionConfig_p(CONFIGROOT obj, const ConnectionId &id, bool override);
private:
void CHSaveConfigData_p();
//
optional<QString> CHStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
void CHStopConnection_p();
bool CHUpdateSubscription_p(const GroupId &id, const QByteArray &subscriptionData);
// bool CHSaveConnectionConfig_p(CONFIGROOT obj, const ConnectionId &id, bool override);
const tuple<QString, QString, int> CHGetOutboundData_p(const CONFIGROOT &obj, bool *succeed) const;
private:
int saveTimerId;
int pingAllTimerId;
int pingConnectionTimerId;
QHash<GroupId, GroupMetaObject> groups;
QHash<ConnectionId, ConnectionMetaObject> connections;
//QHash<ConnectionId, CONFIGROOT> connectionRootCache;
private:
int saveTimerId;
int pingAllTimerId;
int pingConnectionTimerId;
QHash<GroupId, GroupMetaObject> groups;
QHash<ConnectionId, ConnectionMetaObject> connections;
// QHash<ConnectionId, CONFIGROOT> connectionRootCache;
private:
QvHttpRequestHelper *httpHelper;
QvTCPingHelper *tcpingHelper;
// We only support one cuncurrent connection currently.
private:
QvHttpRequestHelper *httpHelper;
bool isHttpRequestInProgress = false;
QvTCPingHelper *tcpingHelper;
// We only support one cuncurrent connection currently.
#ifdef QV2RAY_MULTIPlE_ONNECTION
QHash<ConnectionId, *V2rayKernelInstance> kernelInstances;
QHash<ConnectionId, *V2rayKernelInstance> kernelInstances;
#else
ConnectionId currentConnectionId = NullConnectionId;
V2rayKernelInstance *vCoreInstance = nullptr;
ConnectionId currentConnectionId = NullConnectionId;
V2rayKernelInstance *vCoreInstance = nullptr;
#endif
};
inline ::Qv2ray::core::handlers::QvConnectionHandler *ConnectionManager = nullptr;
}
} // namespace Qv2ray::core::handlers
using namespace Qv2ray::core::handlers;

View File

@ -8,7 +8,8 @@ optional<QString> QvConnectionHandler::CHStartConnection_p(const ConnectionId &i
auto fullConfig = GenerateRuntimeConfig(root);
auto result = vCoreInstance->StartConnection(id, fullConfig);
if (!result.has_value()) {
if (!result.has_value())
{
currentConnectionId = id;
emit OnConnected(currentConnectionId);
}
@ -18,13 +19,16 @@ optional<QString> QvConnectionHandler::CHStartConnection_p(const ConnectionId &i
void QvConnectionHandler::CHStopConnection_p()
{
if (vCoreInstance->KernelStarted) {
if (vCoreInstance->KernelStarted)
{
vCoreInstance->StopConnection();
// Copy
ConnectionId id = currentConnectionId;
currentConnectionId = NullConnectionId;
emit OnDisConnected(id);
} else {
}
else
{
LOG(MODULE_CORE_HANDLER, "VCore is not started, not disconnecting")
}
}

View File

@ -6,7 +6,7 @@ using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
#else
#include "libs/libqvb/build/libqvb.h"
#include "libs/libqvb/build/libqvb.h"
#endif
namespace Qv2ray::core::kernel
@ -22,9 +22,7 @@ namespace Qv2ray::core::kernel
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(MODULE_VCORE, "API thread stopped")
});
connect(thread, &QThread::finished, []() { LOG(MODULE_VCORE, "API thread stopped") });
started = true;
thread->start();
DEBUG(MODULE_VCORE, "API Worker started.")
@ -52,21 +50,22 @@ namespace Qv2ray::core::kernel
thread->wait();
// Although thread shouldnot be null, we'll add this check to be safe.
if (thread) {
delete thread;
}
if (thread) { delete thread; }
}
// API Core Operations
// Start processing data.
void APIWorker::process()
{
while (started) {
while (started)
{
QThread::msleep(1000);
bool dialed = false;
while (running) {
if (!dialed) {
while (running)
{
if (!dialed)
{
auto channelAddress = "127.0.0.1:" + QString::number(GlobalConfig.apiConfig.statsPort);
#ifdef WITH_LIB_GRPCPP
Channel = grpc::CreateChannel(channelAddress.toStdString(), grpc::InsecureChannelCredentials());
@ -85,36 +84,44 @@ namespace Qv2ray::core::kernel
qint64 value_up = 0;
qint64 value_down = 0;
for (auto tag : inboundTags) {
for (auto tag : inboundTags)
{
value_up += CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>uplink");
value_down += CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>downlink");
}
if (value_up < 0 || value_down < 0) {
if (value_up < 0 || value_down < 0)
{
dialed = false;
break;
}
if (running) {
if (running)
{
apiFailedCounter = 0;
emit OnDataReady(value_up, value_down);
}
#else
for (auto tag : inboundTags) {
for (auto tag : inboundTags)
{
auto valup = CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>uplink");
auto valdown = CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>downlink");
if (valup < 0 || valdown < 0) {
if (valup < 0 || valdown < 0)
{
dialed = false;
break;
}
if (running) {
if (running)
{
apiFailedCounter = 0;
emit OnDataReady(tag, valup, valdown);
} else {
}
else
{
// If the connection has stopped, just quit.
break;
}
@ -123,19 +130,22 @@ namespace Qv2ray::core::kernel
#endif
QThread::msleep(1000);
} // end while running
} // end while started
} // end while started
thread->exit();
}
qint64 APIWorker::CallStatsAPIByName(const QString &name)
{
if (apiFailedCounter == QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD) {
if (apiFailedCounter == QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD)
{
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;
} else if (apiFailedCounter > QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD) {
}
else if (apiFailedCounter > QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD)
{
return 0;
}
@ -147,7 +157,8 @@ namespace Qv2ray::core::kernel
ClientContext context;
Status status = Stub->GetStats(&context, request, &response);
if (!status.ok()) {
if (!status.ok())
{
LOG(MODULE_VCORE, "API call returns: " + QSTRN(status.error_code()) + " (" + QString::fromStdString(status.error_message()) + ")")
apiFailedCounter++;
}
@ -157,7 +168,8 @@ namespace Qv2ray::core::kernel
qint64 data = GetStats(const_cast<char *>(name.toStdString().c_str()), 1000);
#endif
if (data < 0) {
if (data < 0)
{
LOG(MODULE_VCORE, "API call returns: " + QSTRN(data))
apiFailedCounter++;
return 0;
@ -165,4 +177,4 @@ namespace Qv2ray::core::kernel
return data;
}
}
} // namespace Qv2ray::core::kernel

View File

@ -1,9 +1,10 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#ifdef WITH_LIB_GRPCPP
#include <grpc++/grpc++.h>
#include "libs/gen/v2ray_api.pb.h"
#include "libs/gen/v2ray_api.grpc.pb.h"
#include "libs/gen/v2ray_api.grpc.pb.h"
#include "libs/gen/v2ray_api.pb.h"
#include <grpc++/grpc++.h>
#endif
// Check 10 times before telling user that API has failed.
@ -13,34 +14,34 @@ namespace Qv2ray::core::kernel
{
class APIWorker : public QObject
{
Q_OBJECT
Q_OBJECT
public:
APIWorker();
~APIWorker();
void StartAPI(const QStringList &tags);
void StopAPI();
public:
APIWorker();
~APIWorker();
void StartAPI(const QStringList &tags);
void StopAPI();
public slots:
void process();
public slots:
void process();
signals:
void OnDataReady(const quint64 _totalUp, const quint64 _totalDown);
void error(const QString &err);
signals:
void OnDataReady(const quint64 _totalUp, const quint64 _totalDown);
void error(const QString &err);
private:
qint64 CallStatsAPIByName(const QString &name);
QStringList inboundTags;
QThread *thread;
//
bool started = false;
bool running = false;
uint apiFailedCounter = 0;
private:
qint64 CallStatsAPIByName(const QString &name);
QStringList inboundTags;
QThread *thread;
//
bool started = false;
bool running = false;
uint apiFailedCounter = 0;
#ifdef WITH_LIB_GRPCPP
std::shared_ptr<::grpc::Channel> Channel;
std::unique_ptr<::v2ray::core::app::stats::command::StatsService::Stub> Stub;
std::shared_ptr<::grpc::Channel> Channel;
std::unique_ptr<::v2ray::core::app::stats::command::StatsService::Stub> Stub;
#endif
};
}
} // namespace Qv2ray::core::kernel
using namespace Qv2ray::core::kernel;

View File

@ -1,10 +1,12 @@
#include "KernelInteractions.hpp"
#include "APIBackend.hpp"
#include "common/QvHelpers.hpp"
#include "core/connection/ConnectionIO.hpp"
#include <QDesktopServices>
#include <QObject>
#include <QWidget>
#include <QDesktopServices>
#include "common/QvHelpers.hpp"
#include "KernelInteractions.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "APIBackend.hpp"
namespace Qv2ray::core::kernel
{
@ -12,14 +14,17 @@ namespace Qv2ray::core::kernel
{
QFile coreFile(vCorePath);
if (!coreFile.exists()) {
if (!coreFile.exists())
{
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)) {
// Use open() here to prevent `executing` a folder, which may have the
// same name as the V2ray core.
if (!coreFile.open(QFile::ReadOnly))
{
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,28 +38,32 @@ namespace Qv2ray::core::kernel
bool hasGeoIP = FileExistsIn(QDir(vAssetsPath), "geoip.dat");
bool hasGeoSite = FileExistsIn(QDir(vAssetsPath), "geosite.dat");
if (!hasGeoIP && !hasGeoSite) {
if (!hasGeoIP && !hasGeoSite)
{
DEBUG(MODULE_VCORE, "V2ray assets path contains none of those two files.")
*message = tr("V2ray assets path is not valid.");
return false;
}
if (!hasGeoIP) {
if (!hasGeoIP)
{
DEBUG(MODULE_VCORE, "No geoip.dat in assets path, aborting.")
*message = tr("No geoip.dat in assets path.");
*message = tr("No geoip.dat in assets path.");
return false;
}
if (!hasGeoSite) {
if (!hasGeoSite)
{
DEBUG(MODULE_VCORE, "No geosite.dat in assets path, aborting.")
*message = tr("No geosite.dat in assets path.");
*message = tr("No geosite.dat in assets path.");
return false;
}
// Check if V2ray core returns a version number correctly.
QProcess proc;
#ifdef Q_OS_WIN32
// nativeArguments are required for Windows platform, without a reason...
// nativeArguments are required for Windows platform, without a
// reason...
proc.setProcessChannelMode(QProcess::MergedChannels);
proc.setProgram(vCorePath);
proc.setNativeArguments("--version");
@ -66,7 +75,8 @@ namespace Qv2ray::core::kernel
proc.waitForFinished();
auto exitCode = proc.exitCode();
if (exitCode != 0) {
if (exitCode != 0)
{
DEBUG(MODULE_VCORE, "VCore failed with an exit code: " + QSTRN(exitCode))
*message = tr("V2ray core failed with an exit code: ") + QSTRN(exitCode);
return false;
@ -75,7 +85,8 @@ namespace Qv2ray::core::kernel
QString output = proc.readAllStandardOutput();
LOG(MODULE_VCORE, "V2ray output: " + SplitLines(output).join(";"))
if (SplitLines(output).isEmpty()) {
if (SplitLines(output).isEmpty())
{
*message = tr("V2ray core returns empty string.");
return false;
}
@ -84,12 +95,12 @@ namespace Qv2ray::core::kernel
return true;
}
bool V2rayKernelInstance::ValidateConfig(const QString &path)
{
QString v2rayCheckResult;
if (ValidateKernel(GlobalConfig.v2CorePath, GlobalConfig.v2AssetsPath, &v2rayCheckResult)) {
if (ValidateKernel(GlobalConfig.v2CorePath, GlobalConfig.v2AssetsPath, &v2rayCheckResult))
{
DEBUG(MODULE_VCORE, "V2ray version: " + v2rayCheckResult)
// Append assets location env.
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
@ -98,21 +109,28 @@ namespace Qv2ray::core::kernel
QProcess process;
process.setProcessEnvironment(env);
DEBUG(MODULE_VCORE, "Starting V2ray core with test options")
process.start(GlobalConfig.v2CorePath, QStringList() << "-test" << "-config" << path, QIODevice::ReadWrite | QIODevice::Text);
process.start(GlobalConfig.v2CorePath,
QStringList() << "-test"
<< "-config" << path,
QIODevice::ReadWrite | QIODevice::Text);
process.waitForFinished();
if (process.exitCode() != 0) {
if (process.exitCode() != 0)
{
QString output = QString(process.readAllStandardOutput());
QvMessageBoxWarn(nullptr, tr("Configuration Error"), output.mid(output.indexOf("anti-censorship.") + 17));
return false;
} else {
}
else
{
DEBUG(MODULE_VCORE, "Config file check passed.")
return true;
}
} else {
}
else
{
QvMessageBoxWarn(nullptr, tr("Cannot start V2ray"),
tr("V2ray core settings is incorrect.") + NEWLINE + NEWLINE +
tr("The error is: ") + NEWLINE + v2rayCheckResult);
tr("V2ray core settings is incorrect.") + NEWLINE + NEWLINE + tr("The error is: ") + NEWLINE + v2rayCheckResult);
return false;
}
}
@ -120,14 +138,14 @@ namespace Qv2ray::core::kernel
V2rayKernelInstance::V2rayKernelInstance()
{
vProcess = new QProcess();
connect(vProcess, &QProcess::readyReadStandardOutput, this, [&]() {
emit OnProcessOutputReadyRead(id, vProcess->readAllStandardOutput().trimmed());
});
connect(vProcess, &QProcess::readyReadStandardOutput, this,
[&]() { emit OnProcessOutputReadyRead(id, vProcess->readAllStandardOutput().trimmed()); });
connect(vProcess, &QProcess::stateChanged, [&](QProcess::ProcessState state) {
DEBUG(MODULE_VCORE, "V2ray kernel process status changed: " + QVariant::fromValue(state).toString())
// If V2ray crashed AFTER we start it.
if (KernelStarted && state == QProcess::NotRunning) {
if (KernelStarted && state == QProcess::NotRunning)
{
LOG(MODULE_VCORE, "V2ray kernel crashed.")
StopConnection();
emit OnProcessErrored(id);
@ -140,7 +158,8 @@ namespace Qv2ray::core::kernel
optional<QString> V2rayKernelInstance::StartConnection(const ConnectionId &id, const CONFIGROOT &root)
{
if (KernelStarted) {
if (KernelStarted)
{
LOG(MODULE_VCORE, "Status is invalid, expect STOPPED when calling StartConnection")
return tr("Invalid V2ray Instance Status.");
}
@ -151,7 +170,8 @@ namespace Qv2ray::core::kernel
//
auto filePath = QV2RAY_GENERATED_FILE_PATH;
if (ValidateConfig(filePath)) {
if (ValidateConfig(filePath))
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("V2RAY_LOCATION_ASSET", GlobalConfig.v2AssetsPath);
vProcess->setProcessEnvironment(env);
@ -163,10 +183,12 @@ namespace Qv2ray::core::kernel
this->id = id;
QStringList inboundTags;
for (auto item : root["inbounds"].toArray()) {
for (auto item : root["inbounds"].toArray())
{
auto tag = item.toObject()["tag"].toString("");
if (tag.isEmpty() || tag == API_TAG_INBOUND) {
if (tag.isEmpty() || tag == API_TAG_INBOUND)
{
// Ignore API tag and empty tags.
continue;
}
@ -178,20 +200,26 @@ namespace Qv2ray::core::kernel
apiEnabled = false;
//
if (StartupOption.noAPI) {
LOG(MODULE_VCORE, "API has been disabled by the command line argument \"-noAPI\"")
} else if (!GlobalConfig.apiConfig.enableAPI) {
if (StartupOption.noAPI) { LOG(MODULE_VCORE, "API has been disabled by the command line argument \"-noAPI\"") }
else if (!GlobalConfig.apiConfig.enableAPI)
{
LOG(MODULE_VCORE, "API has been disabled by the global config option")
} else if (inboundTags.isEmpty()) {
}
else if (inboundTags.isEmpty())
{
LOG(MODULE_VCORE, "API is disabled since no inbound tags configured. This is probably caused by a bad complex config.")
} else {
}
else
{
apiWorker->StartAPI(inboundTags);
apiEnabled = true;
DEBUG(MODULE_VCORE, "Qv2ray API started")
}
return { };
} else {
return {};
}
else
{
KernelStarted = false;
return tr("V2ray kernel failed to start.");
}
@ -199,12 +227,14 @@ namespace Qv2ray::core::kernel
void V2rayKernelInstance::StopConnection()
{
if (apiEnabled) {
if (apiEnabled)
{
apiWorker->StopAPI();
apiEnabled = false;
}
// Set this to false BEFORE close the Process, since we need this flag to capture the real kernel CRASH
// Set this to false BEFORE close the Process, since we need this flag
// to capture the real kernel CRASH
KernelStarted = false;
vProcess->close();
// Block until V2ray core exits
@ -214,9 +244,7 @@ namespace Qv2ray::core::kernel
V2rayKernelInstance::~V2rayKernelInstance()
{
if (KernelStarted) {
StopConnection();
}
if (KernelStarted) { StopConnection(); }
delete apiWorker;
delete vProcess;
@ -226,4 +254,4 @@ namespace Qv2ray::core::kernel
{
emit OnNewStatsDataArrived(id, _totalUp, _totalDown);
}
}
} // namespace Qv2ray::core::kernel

View File

@ -1,46 +1,47 @@
#pragma once
#include <QProcess>
#include "base/Qv2rayBase.hpp"
#include "core/CoreSafeTypes.hpp"
#include <QProcess>
namespace Qv2ray::core::kernel
{
class APIWorker;
class V2rayKernelInstance : public QObject
{
Q_OBJECT
public:
explicit V2rayKernelInstance();
~V2rayKernelInstance() override;
//
// Speed
qulonglong getTagSpeedUp(const QString &tag);
qulonglong getTagSpeedDown(const QString &tag);
qulonglong getAllSpeedUp();
qulonglong getAllSpeedDown();
//
optional<QString> StartConnection(const ConnectionId &id, const CONFIGROOT &root);
void StopConnection();
bool KernelStarted = false;
//
static bool ValidateConfig(const QString &path);
static bool ValidateKernel(const QString &vCorePath, const QString &vAssetsPath, QString *message);
Q_OBJECT
public:
explicit V2rayKernelInstance();
~V2rayKernelInstance() override;
//
// Speed
qulonglong getTagSpeedUp(const QString &tag);
qulonglong getTagSpeedDown(const QString &tag);
qulonglong getAllSpeedUp();
qulonglong getAllSpeedDown();
//
optional<QString> StartConnection(const ConnectionId &id, const CONFIGROOT &root);
void StopConnection();
bool KernelStarted = false;
//
static bool ValidateConfig(const QString &path);
static bool ValidateKernel(const QString &vCorePath, const QString &vAssetsPath, QString *message);
signals:
void OnProcessErrored(const ConnectionId &id);
void OnProcessOutputReadyRead(const ConnectionId &id, const QString &output);
void OnNewStatsDataArrived(const ConnectionId &id, const quint64 _totalUp, const quint64 _totalDown);
signals:
void OnProcessErrored(const ConnectionId &id);
void OnProcessOutputReadyRead(const ConnectionId &id, const QString &output);
void OnNewStatsDataArrived(const ConnectionId &id, const quint64 _totalUp, const quint64 _totalDown);
public slots:
void onAPIDataReady(const quint64 _totalUp, const quint64 _totalDown);
public slots:
void onAPIDataReady(const quint64 _totalUp, const quint64 _totalDown);
private:
APIWorker *apiWorker;
QProcess *vProcess;
bool apiEnabled;
//
ConnectionId id = NullConnectionId;
private:
APIWorker *apiWorker;
QProcess *vProcess;
bool apiEnabled;
//
ConnectionId id = NullConnectionId;
};
}
} // namespace Qv2ray::core::kernel
using namespace Qv2ray::core::kernel;

View File

@ -1,15 +1,15 @@
#ifdef _WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#endif
#include "QtConcurrent/QtConcurrent"
#include "QvTCPing.hpp"
#include "core/handler/ConnectionHandler.hpp"
#include "QtConcurrent/QtConcurrent"
namespace Qv2ray::core::tcping
{
@ -23,7 +23,8 @@ namespace Qv2ray::core::tcping
void QvTCPingHelper::StopAllLatenceTest()
{
while (!pingWorkingThreads.isEmpty()) {
while (!pingWorkingThreads.isEmpty())
{
auto worker = pingWorkingThreads.dequeue();
worker->future().cancel();
worker->cancel();
@ -35,13 +36,11 @@ namespace Qv2ray::core::tcping
watcher->setFuture(QtConcurrent::run(&QvTCPingHelper::TestLatency_p, id, count));
pingWorkingThreads.enqueue(watcher);
//
connect(watcher, &QFutureWatcher<QvTCPingResultObject>::finished, this, [ = ]() {
connect(watcher, &QFutureWatcher<QvTCPingResultObject>::finished, this, [=]() {
auto result = watcher->result();
this->pingWorkingThreads.removeOne(watcher);
if (!result.errorMessage.isEmpty()) {
LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage)
}
if (!result.errorMessage.isEmpty()) { LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage) }
emit this->OnLatencyTestCompleted(result);
});
@ -54,12 +53,14 @@ namespace Qv2ray::core::tcping
if (isExiting) return data;
auto [host, port] = ConnectionManager->GetConnectionInfo(id);
auto [protocol, host, port] = ConnectionManager->GetConnectionData(id);
Q_UNUSED(protocol)
double successCount = 0, errorCount = 0;
addrinfo *resolved;
int errcode;
if ((errcode = resolveHost(host.toStdString(), port, &resolved)) != 0) {
if ((errcode = resolveHost(host.toStdString(), port, &resolved)) != 0)
{
#ifdef _WIN32
data.errorMessage = QString::fromStdWString(gai_strerror(errcode));
#else
@ -71,26 +72,35 @@ namespace Qv2ray::core::tcping
bool noAddress = false;
int currentCount = 0;
while (currentCount < count) {
while (currentCount < count)
{
if (isExiting) return QvTCPingResultObject();
system_clock::time_point start;
system_clock::time_point end;
if ((errcode = testLatency(resolved, &start, &end)) != 0) {
if (errcode != -EADDRNOTAVAIL) {
//LOG(MODULE_NETWORK, "Error connecting to host: " + data.hostName + ":" + QSTRN(data.port) + " " + strerror(-errcode))
if ((errcode = testLatency(resolved, &start, &end)) != 0)
{
if (errcode != -EADDRNOTAVAIL)
{
// LOG(MODULE_NETWORK, "Error connecting to host: " +
// data.hostName + ":" + QSTRN(data.port) + " " +
// strerror(-errcode))
errorCount++;
} else {
if (noAddress) {
LOG(MODULE_NETWORK, ".")
} else {
}
else
{
if (noAddress) { LOG(MODULE_NETWORK, ".") }
else
{
LOG(MODULE_NETWORK, "error connecting to host: " + QSTRN(-errcode) + " " + strerror(-errcode))
}
noAddress = true;
}
} else {
}
else
{
noAddress = false;
successCount++;
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
@ -99,7 +109,8 @@ namespace Qv2ray::core::tcping
data.worst = min(data.worst, ms);
data.best = max(data.best, ms);
if (ms > 1000) {
if (ms > 1000)
{
LOG(MODULE_NETWORK, "Stop the test on the first long connect()")
break; /* Stop the test on the first long connect() */
}
@ -146,20 +157,19 @@ namespace Qv2ray::core::tcping
int rv = 0;
/* try to connect for each of the entries: */
while (addr != nullptr) {
while (addr != nullptr)
{
if (isExiting) return 0;
/* create socket */
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (!fd) {
goto next_addr0;
}
if (!fd) { goto next_addr0; }
#ifdef _WIN32
// Windows needs special conversion.
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) < 0)
#else
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
#endif
@ -172,7 +182,8 @@ namespace Qv2ray::core::tcping
/* connect to peer */
// Qt has its own connect() function in QObject....
// So we add "::" here
if (::connect(fd, addr->ai_addr, addr->ai_addrlen) == 0) {
if (::connect(fd, addr->ai_addr, addr->ai_addrlen) == 0)
{
*end = system_clock::now();
#ifdef _WIN32
closesocket(fd);
@ -182,17 +193,17 @@ namespace Qv2ray::core::tcping
return 0;
}
next_addr1:
next_addr1:
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
next_addr0:
next_addr0:
addr = addr->ai_next;
}
rv = rv ? rv : -errno;
return rv;
}
}
} // namespace Qv2ray::core::tcping

View File

@ -4,7 +4,8 @@
namespace Qv2ray::core::tcping
{
struct QvTCPingResultObject {
struct QvTCPingResultObject
{
ConnectionId connectionId = NullConnectionId;
QString errorMessage;
int total, succeed, failed;
@ -13,19 +14,20 @@ namespace Qv2ray::core::tcping
class QvTCPingHelper : public QObject
{
Q_OBJECT
Q_OBJECT
public:
explicit QvTCPingHelper(const int defaultCount = 5, QObject *parent = nullptr);
void TestLatency(const ConnectionId &connectionId);
void StopAllLatenceTest();
signals:
void OnLatencyTestCompleted(const QvTCPingResultObject &data);
private:
static QvTCPingResultObject TestLatency_p(const ConnectionId &id, const int count);
int count;
QQueue<QFutureWatcher<QvTCPingResultObject>*> pingWorkingThreads;
public:
explicit QvTCPingHelper(const int defaultCount = 5, QObject *parent = nullptr);
void TestLatency(const ConnectionId &connectionId);
void StopAllLatenceTest();
signals:
void OnLatencyTestCompleted(const QvTCPingResultObject &data);
private:
static QvTCPingResultObject TestLatency_p(const ConnectionId &id, const int count);
int count;
QQueue<QFutureWatcher<QvTCPingResultObject> *> pingWorkingThreads;
};
}
} // namespace Qv2ray::core::tcping
using namespace Qv2ray::core::tcping;

View File

@ -1,37 +1,36 @@
#include <QFileInfo>
#include <QStandardPaths>
#include <QTranslator>
#include <QStyle>
#include <QLocale>
#include <QObject>
#include <QStyleFactory>
#include <QApplication>
#include <singleapplication.h>
#include <csignal>
#include "ui/w_MainWindow.hpp"
#include "common/CommandArgs.hpp"
#include "common/QvHelpers.hpp"
#include "common/QvTranslator.hpp"
#include "core/config/ConfigBackend.hpp"
#include "core/handler/ConnectionHandler.hpp"
#include "common/QvHelpers.hpp"
#include "common/CommandArgs.hpp"
#include "common/QvTranslator.hpp"
#include "ui/w_MainWindow.hpp"
#include <QApplication>
#include <QLocale>
#include <QObject>
#include <QStandardPaths>
#include <QStyle>
#include <QStyleFactory>
#include <QTranslator>
#include <csignal>
#include <singleapplication.h>
#ifdef Q_OS_UNIX
// For unix root user check
#include "unistd.h"
// For unix root user check
#include "unistd.h"
#endif
void signalHandler(int signum)
{
cout << "Interrupt signal (" << signum << ") received." << endl;
//if (MainWindow::mwInstance && MainWindow::mwInstance->vinstance) {
// if (MainWindow::mwInstance && MainWindow::mwInstance->vinstance) {
// cout << "Trying to stop connection..." << endl;
// MainWindow::mwInstance->vinstance->StopConnection();
//}
qApp->exit(-99);
}
bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
{
// Does not exist.
@ -41,17 +40,21 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
QFile testFile(path + ".qv2ray_file_write_test_file" + QSTRN(QTime::currentTime().msecsSinceStartOfDay()));
bool opened = testFile.open(QFile::OpenModeFlag::ReadWrite);
if (!opened) {
if (!opened)
{
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 {
}
else
{
testFile.write("Qv2ray test file, feel free to remove.");
testFile.flush();
testFile.close();
bool removed = testFile.remove();
if (!removed) {
if (!removed)
{
// This is rare, as we can create a file but failed to remove it.
LOG(MODULE_SETTINGS, "Directory at: " + path + " cannot be used as a valid config file path.")
LOG(MODULE_INIT, "---> Cannot remove a file.")
@ -59,7 +62,8 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
}
}
if (checkExistingConfig) {
if (checkExistingConfig)
{
// Check if an existing config is found.
QFile configFile(path + "Qv2ray.conf");
@ -68,37 +72,52 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
bool opened2 = configFile.open(QIODevice::ReadWrite);
try {
if (opened2) {
try
{
if (opened2)
{
// Verify if the config can be loaded.
// Failed to parse if we changed the file structure...
// Original:
// -- auto conf = StructFromJsonString<Qv2rayConfig>(configFile.readAll());
// -- auto conf =
// StructFromJsonString<Qv2rayConfig>(configFile.readAll());
//
// Verify JSON file format. (only) because this file version may not be upgraded and may contain unsupported structure.
// Verify JSON file format. (only) because this file version may
// not be upgraded and may contain unsupported structure.
auto err = VerifyJsonString(StringFromFile(&configFile));
if (!err.isEmpty()) {
if (!err.isEmpty())
{
LOG(MODULE_INIT, "Json parse returns: " + err)
return false;
} else {
}
else
{
// If the file format is valid.
auto conf = JsonFromString(StringFromFile(&configFile));
LOG(MODULE_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(MODULE_SETTINGS, "File: " + configFile.fileName() + " cannot be opened!")
}
else
{
LOG(MODULE_SETTINGS, "File: " + configFile.fileName() + " cannot be opened!")
return false;
}
} catch (...) {
}
catch (...)
{
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());
// LOG(INIT, e->what())
QvMessageBoxWarn(nullptr, QObject::tr("Warning"),
QObject::tr("Qv2ray cannot load the config file from here:") + NEWLINE + configFile.fileName());
return false;
}
} else return true;
}
else
return true;
}
bool initialiseQv2ray()
@ -109,12 +128,14 @@ bool initialiseQv2ray()
const QString homeQv2ray = QDir::homePath() + "/.qv2ray" QV2RAY_CONFIG_DIR_SUFFIX;
//
//
// Some built-in search paths for Qv2ray to find configs. (load the first one if possible).
// Some built-in search paths for Qv2ray to find configs. (load the first
// one if possible).
//
QStringList configFilePaths;
configFilePaths << currentPathConfig;
#ifdef WITH_FLATHUB_CONFIG_PATH
// AppConfigLocation uses 'Q'v2ray instead of `q`v2ray. Keep here as backward compatibility.
// AppConfigLocation uses 'Q'v2ray instead of `q`v2ray. Keep here as
// backward compatibility.
configFilePaths << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + QV2RAY_CONFIG_DIR_SUFFIX;
#endif
configFilePaths << configQv2ray;
@ -123,31 +144,40 @@ bool initialiseQv2ray()
QString configPath = "";
bool hasExistingConfig = false;
for (auto path : configFilePaths) {
// Verify the config path, check if the config file exists and in the correct JSON format.
// True means we check for config existance as well. --|HERE |
for (auto path : configFilePaths)
{
// Verify the config path, check if the config file exists and in the
// correct JSON format. True means we check for config existance as
// well. --|HERE |
bool isValidConfigPath = verifyConfigAvaliability(path, true);
// If we already found a valid config file. just simply load it...
if (hasExistingConfig) break;
if (isValidConfigPath) {
if (isValidConfigPath)
{
DEBUG(MODULE_INIT, "Path: " + path + " is valid.")
configPath = path;
hasExistingConfig = true;
} else {
}
else
{
LOG(MODULE_INIT, "Path: " + path + " does not contain a valid config file.")
}
}
// If there's no existing config.
if (hasExistingConfig) {
if (hasExistingConfig)
{
// Use the config path found by the checks above
SetConfigDirPath(configPath);
LOG(MODULE_INIT, "Using " + QV2RAY_CONFIG_DIR + " as the config path.")
} else {
}
else
{
//
// Create new config at these dirs, these are default values for each platform.
// Create new config at these dirs, these are default values for each
// platform.
#ifdef Q_OS_WIN
configPath = currentPathConfig;
#else
@ -156,23 +186,26 @@ bool initialiseQv2ray()
bool mkpathResult = QDir().mkpath(configPath);
// 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.
if (mkpathResult && verifyConfigAvaliability(configPath, false))
{
// Found a valid config dir, with write permission, but assume no
// config is located in it.
LOG(MODULE_INIT, "Set " + configPath + " as the config path.")
SetConfigDirPath(configPath);
if (QFile::exists(QV2RAY_CONFIG_FILE)) {
if (QFile::exists(QV2RAY_CONFIG_FILE))
{
// As we already tried to load config from every possible dir.
// This condition branch (!hasExistingConfig check) holds the fact that
// current config dir, should NOT contain any valid file (at least in the same name)
// 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.
// This condition branch (!hasExistingConfig check) holds the
// fact that current config dir, should NOT contain any valid
// file (at least in the same name) 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(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 +
QObject::tr("Please report if you think it's a bug."));
QObject::tr("Qv2ray will now exit.") + NEWLINE + QObject::tr("Please report if you think it's a bug."));
return false;
}
@ -184,7 +217,9 @@ bool initialiseQv2ray()
// Save initial config.
SaveGlobalConfig(conf);
LOG(MODULE_INIT, "Created initial config file.")
} else {
}
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(MODULE_INIT, "FATAL")
@ -192,14 +227,14 @@ bool initialiseQv2ray()
QString searchPath = configFilePaths.join(NEWLINE);
QvMessageBoxWarn(nullptr, QObject::tr("Cannot Start Qv2ray"),
QObject::tr("Cannot find a place to store config files.") + NEWLINE +
QObject::tr("Qv2ray has searched these paths below:") +
NEWLINE + NEWLINE + searchPath + NEWLINE +
QObject::tr("Qv2ray will now exit."));
QObject::tr("Qv2ray has searched these paths below:") + NEWLINE + NEWLINE + searchPath + NEWLINE +
QObject::tr("Qv2ray will now exit."));
return false;
}
}
if (!QDir(QV2RAY_GENERATED_DIR).exists()) {
if (!QDir(QV2RAY_GENERATED_DIR).exists())
{
// The dir used to generate final config file, for V2ray interaction.
QDir().mkdir(QV2RAY_GENERATED_DIR);
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
@ -208,7 +243,6 @@ bool initialiseQv2ray()
return true;
}
int main(int argc, char *argv[])
{
#ifndef Q_OS_WIN
@ -228,9 +262,9 @@ int main(int argc, char *argv[])
QvCommandArgParser parser;
QString errorMessage;
switch (parser.ParseCommandLine(&errorMessage)) {
case CommandLineOk:
break;
switch (parser.ParseCommandLine(&errorMessage))
{
case CommandLineOk: break;
case CommandLineError:
cout << errorMessage.toStdString() << endl;
@ -243,16 +277,16 @@ int main(int argc, char *argv[])
LOG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
return 0;
case CommandLineHelpRequested:
cout << parser.Parser()->helpText().toStdString() << endl;
return 0;
case CommandLineHelpRequested: cout << parser.Parser()->helpText().toStdString() << endl; return 0;
}
}
#ifdef Q_OS_UNIX
// Unix OS root user check.
// Do not use getuid() here since it's installed as owned by the root, someone may accidently setuid to it.
if (!StartupOption.forceRunAsRootUser && geteuid() == 0) {
// Do not use getuid() here since it's installed as owned by the root,
// someone may accidently setuid to it.
if (!StartupOption.forceRunAsRootUser && geteuid() == 0)
{
LOG("ERROR", QObject::tr("You cannot run Qv2ray as root, please use --I-just-wanna-run-with-root if you REALLY want to do so."))
LOG("ERROR", QObject::tr(" --> USE IT AT YOUR OWN RISK!"))
return 1;
@ -263,9 +297,11 @@ 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(MODULE_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.
// This line must be called before any other ones, since we are using these
// values to identify instances.
SingleApplication::setApplicationName("Qv2ray");
SingleApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
SingleApplication::setApplicationDisplayName("Qv2ray");
@ -275,7 +311,8 @@ int main(int argc, char *argv[])
// ----------------------------> For debug build...
SingleApplication::setApplicationName("Qv2ray - DEBUG");
#endif
SingleApplication _qApp(argc, argv, false, SingleApplication::Mode::User | SingleApplication::Mode::ExcludeAppPath | SingleApplication::Mode::ExcludeAppVersion);
SingleApplication _qApp(
argc, argv, false, SingleApplication::Mode::User | SingleApplication::Mode::ExcludeAppPath | SingleApplication::Mode::ExcludeAppVersion);
_qApp.setQuitOnLastWindowClosed(false);
// Early initialisation
//
@ -288,14 +325,11 @@ int main(int argc, char *argv[])
bool _result_ = _qApp.installTranslator(Qv2rayTranslator.get());
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
"under certain conditions." NEWLINE NEWLINE
"Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE
NEWLINE NEWLINE
LOG("LICENCE", NEWLINE
"This program comes with ABSOLUTELY NO WARRANTY." NEWLINE "This is free software, and you are welcome to redistribute it" NEWLINE
"under certain conditions." NEWLINE NEWLINE "Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE NEWLINE NEWLINE
"Libraries that have been used in Qv2ray are listed below (Sorted by date added):" NEWLINE
"Copyright (c) 2020 dridk (@dridk): X2Struct (Apache)" NEWLINE
"Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE
"Copyright (c) 2020 dridk (@dridk): X2Struct (Apache)" NEWLINE "Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE
"Copyright (c) 2020 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)" NEWLINE
"Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)" NEWLINE
"Copyright (c) 2016 Nikhil Marathe (@nikhilm): QHttpServer (MIT)" NEWLINE
@ -304,48 +338,50 @@ int main(int argc, char *argv[])
"Copyright (c) 2019 TheWanderingCoel (@TheWanderingCoel): ShadowClash (launchatlogin) (GPLv3)" NEWLINE
"Copyright (c) 2020 Ram Pani (@DuckSoft): QvRPCBridge (WTFPL)" NEWLINE
"Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)" NEWLINE
"Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE
NEWLINE)
"Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE NEWLINE)
//
LOG(MODULE_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;
cout << "WARNING: ============================== This is a debug build, many features are not stable enough. =============================="
<< endl;
#endif
//
// Load the language translation list.
auto langs = GetFileList(QDir(":/translations"));
if (langs.empty()) {
if (langs.empty())
{
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(MODULE_INIT, "Found Translator: " + lang)
}
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(MODULE_INIT, "Found Translator: " + lang) }
}
// Qv2ray Initialize, find possible config paths and verify them.
if (!initialiseQv2ray()) {
return -1;
}
if (!initialiseQv2ray()) { return -1; }
// Load the config for upgrade, but do not parse it to the struct.
auto conf = JsonFromString(StringFromFile(QV2RAY_CONFIG_FILE));
auto confVersion = conf["config_version"].toVariant().toString().toInt();
if (confVersion > QV2RAY_CONFIG_VERSION) {
if (confVersion > QV2RAY_CONFIG_VERSION)
{
// Config version is larger than the current version...
// This is rare but it may happen....
QvMessageBoxWarn(nullptr, QObject::tr("Qv2ray Cannot Continue"),
QObject::tr("You are running a lower version of Qv2ray compared to the current config file.") + NEWLINE +
QObject::tr("Please check if there's an issue explaining about it.") + NEWLINE +
QObject::tr("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE +
QObject::tr("Qv2ray will now exit."));
QObject::tr("Please check if there's an issue explaining about it.") + NEWLINE +
QObject::tr("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE +
QObject::tr("Qv2ray will now exit."));
return -2;
}
if (confVersion < QV2RAY_CONFIG_VERSION) {
if (confVersion < QV2RAY_CONFIG_VERSION)
{
// That is, config file needs to be upgraded.
conf = Qv2ray::UpgradeConfig(confVersion, QV2RAY_CONFIG_VERSION, conf);
}
@ -356,7 +392,8 @@ int main(int argc, char *argv[])
qApp->removeTranslator(Qv2rayTranslator.get());
LOG(MODULE_INIT, "Removed system translations")
if (confObject.uiConfig.language.isEmpty()) {
if (confObject.uiConfig.language.isEmpty())
{
// Prevent empty.
LOG(MODULE_UI, "Setting default UI language to en-US")
confObject.uiConfig.language = "en-US";
@ -364,15 +401,15 @@ int main(int argc, char *argv[])
Qv2rayTranslator = std::move(QvTranslator(confObject.uiConfig.language).pTranslator);
if (qApp->installTranslator(Qv2rayTranslator.get())) {
LOG(MODULE_INIT, "Successfully installed a translator for " + confObject.uiConfig.language)
} else {
if (qApp->installTranslator(Qv2rayTranslator.get()))
{ 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.
QvMessageBoxWarn(
nullptr, "Translation Failed",
"Cannot load translation for " + confObject.uiConfig.language + ", English is now used." + NEWLINE + NEWLINE +
"Please go to Preferences Window to change language or open an Issue");
QvMessageBoxWarn(nullptr, "Translation Failed",
"Cannot load translation for " + confObject.uiConfig.language + ", English is now used." + NEWLINE + NEWLINE +
"Please go to Preferences Window to change language or open an Issue");
}
// Let's save the config.
@ -383,16 +420,16 @@ int main(int argc, char *argv[])
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)
if (!QSslSocket::supportsSsl()) {
if (!QSslSocket::supportsSsl())
{
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 +
QObject::tr("If you are using an AppImage from Github Action, please report a bug.") + NEWLINE + NEWLINE +
QObject::tr("Technical Details") + NEWLINE +
"OSsl.Rq.V=" + osslReqVersion + NEWLINE +
"OSsl.Cr.V=" + osslCurVersion);
QObject::tr("This could be caused by a missing of `openssl` package in your system.") + NEWLINE +
QObject::tr("If you are using an AppImage from Github Action, please report a bug.") + NEWLINE + NEWLINE +
QObject::tr("Technical Details") + NEWLINE + "OSsl.Rq.V=" + osslReqVersion + NEWLINE +
"OSsl.Cr.V=" + osslCurVersion);
return -3;
}
@ -406,7 +443,8 @@ int main(int argc, char *argv[])
#ifdef QV2RAY_USE_BUILTIN_DARKTHEME
LOG(MODULE_UI, "Using built-in theme.")
if (confObject.uiConfig.useDarkTheme) {
if (confObject.uiConfig.useDarkTheme)
{
LOG(MODULE_UI, " --> Using built-in dark theme.")
// From https://forum.qt.io/topic/101391/windows-10-dark-theme/4
_qApp.setStyle("Fusion");
@ -441,7 +479,8 @@ int main(int argc, char *argv[])
QStringList themes = QStyleFactory::keys();
//_qApp.setDesktopFileName("qv2ray.desktop");
if (themes.contains(confObject.uiConfig.theme)) {
if (themes.contains(confObject.uiConfig.theme))
{
_qApp.setStyle(confObject.uiConfig.theme);
LOG(MODULE_INIT + " " + MODULE_UI, "Setting Qv2ray UI themes: " + confObject.uiConfig.theme)
}
@ -449,7 +488,8 @@ int main(int argc, char *argv[])
#endif
#ifndef QT_DEBUG
try {
try
{
#endif
//_qApp.setAttribute(Qt::AA_DontUseNativeMenuBar);
// Initialise Connection Handler
@ -465,23 +505,19 @@ int main(int argc, char *argv[])
// Handler for session logout, shutdown, etc.
// Will not block.
QGuiApplication::setFallbackSessionManagementEnabled(false);
QObject::connect(&_qApp, &QGuiApplication::commitDataRequest, []() {
LOG(MODULE_INIT, "Quit triggered by session manager.")
});
QObject::connect(&_qApp, &QGuiApplication::commitDataRequest, []() { LOG(MODULE_INIT, "Quit triggered by session manager.") });
#ifndef Q_OS_WIN
signal(SIGUSR1, [](int) {
emit MainWindow::mwInstance->Connect();
});
signal(SIGUSR2, [](int) {
emit MainWindow::mwInstance->DisConnect();
});
signal(SIGUSR1, [](int) { emit MainWindow::mwInstance->Connect(); });
signal(SIGUSR2, [](int) { emit MainWindow::mwInstance->DisConnect(); });
#endif
auto rcode = _qApp.exec();
delete ConnectionManager;
LOG(MODULE_INIT, "Quitting normally")
return rcode;
#ifndef QT_DEBUG
} catch (...) {
}
catch (...)
{
QvMessageBoxWarn(nullptr, "ERROR", "There's something wrong happened and Qv2ray will quit now.");
LOG(MODULE_INIT, "EXCEPTION THROWN: " __FILE__)
return -99;

View File

@ -1,36 +1,45 @@
#include "w_InboundEditor.hpp"
#include "core/CoreUtils.hpp"
#include "common/QvHelpers.hpp"
#include "core/CoreUtils.hpp"
#include "core/connection/ConnectionIO.hpp"
static bool isLoading = false;
#define CHECKLOADING if(isLoading) return;
#define CHECKLOADING \
if (isLoading) return;
InboundEditor::InboundEditor(INBOUND root, QWidget *parent) :
QDialog(parent),
original(root)
InboundEditor::InboundEditor(INBOUND root, QWidget *parent) : QDialog(parent), original(root)
{
QvMessageBusConnect(InboundEditor);
setupUi(this);
this->root = root;
auto inboundType = root["protocol"].toString();
allocate = root["allocate"].toObject();
sniffing = root["sniffing"].toObject();
sniffing = root["sniffing"].toObject();
if (inboundType == "http") {
httpSettings = root["settings"].toObject();
} else if (inboundType == "socks") {
if (inboundType == "http") { httpSettings = root["settings"].toObject(); }
else if (inboundType == "socks")
{
socksSettings = root["settings"].toObject();
} else if (inboundType == "dokodemo-door") {
}
else if (inboundType == "dokodemo-door")
{
dokoSettings = root["settings"].toObject();
} else if (inboundType == "mtproto") {
}
else if (inboundType == "mtproto")
{
mtSettings = root["settings"].toObject();
} else {
if (!root["protocol"].toString().isEmpty()) {
}
else
{
if (!root["protocol"].toString().isEmpty())
{
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 {
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(MODULE_UI, "Creating new inbound config")
root["protocol"] = inboundType = "http";
}
@ -41,10 +50,9 @@ InboundEditor::InboundEditor(INBOUND root, QWidget *parent) :
QvMessageBusSlotImpl(InboundEditor)
{
switch (msg) {
MBShowDefaultImpl\
MBHideDefaultImpl\
MBRetranslateDefaultImpl\
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -59,27 +67,28 @@ INBOUND InboundEditor::GenerateNewRoot()
INBOUND _newRoot = root;
auto inboundType = root["protocol"].toString();
if (inboundType.isNull() || inboundType.isEmpty()) {
inboundType = "http";
}
if (inboundType.isNull() || inboundType.isEmpty()) { inboundType = "http"; }
if (inboundType == "http") {
if (inboundType == "http")
{
// Remove useless, misleading 'accounts' array.
if (httpAccountListBox->count() == 0) {
httpSettings.remove("accounts");
}
if (httpAccountListBox->count() == 0) { httpSettings.remove("accounts"); }
_newRoot["settings"] = httpSettings;
} else if (inboundType == "socks") {
}
else if (inboundType == "socks")
{
// See above
if (socksAccountListBox->count() == 0) {
socksSettings.remove("accounts");
}
if (socksAccountListBox->count() == 0) { socksSettings.remove("accounts"); }
_newRoot["settings"] = socksSettings;
} else if (inboundType == "dokodemo-door") {
}
else if (inboundType == "dokodemo-door")
{
_newRoot["settings"] = dokoSettings;
} else if (inboundType == "mtproto") {
}
else if (inboundType == "mtproto")
{
_newRoot["settings"] = mtSettings;
}
@ -102,7 +111,8 @@ void InboundEditor::LoadUIData()
//
destOverrideList->setEnabled(sniffing["enabled"].toBool());
for (auto item : sniffing["destOverride"].toArray()) {
for (auto item : sniffing["destOverride"].toArray())
{
if (item.toString().toLower() == "http") destOverrideList->item(0)->setCheckState(Qt::Checked);
if (item.toString().toLower() == "tls") destOverrideList->item(1)->setCheckState(Qt::Checked);
@ -118,9 +128,8 @@ void InboundEditor::LoadUIData()
httpUserLevelSB->setValue(httpSettings["userLevel"].toInt());
httpAccountListBox->clear();
for (auto user : httpSettings["accounts"].toArray()) {
httpAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString());
}
for (auto user : httpSettings["accounts"].toArray())
{ httpAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString()); }
// SOCKS
socksAuthCombo->setCurrentText(socksSettings["auth"].toString());
@ -128,9 +137,8 @@ void InboundEditor::LoadUIData()
socksUDPIPAddrTxt->setText(socksSettings["ip"].toString());
socksUserLevelSB->setValue(socksSettings["userLevel"].toInt());
for (auto user : socksSettings["accounts"].toArray()) {
socksAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString());
}
for (auto user : socksSettings["accounts"].toArray())
{ socksAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString()); }
// Dokodemo-Door
dokoFollowRedirectCB->setChecked(dokoSettings["followRedirect"].toBool());
@ -190,15 +198,18 @@ void InboundEditor::on_httpRemoveUserBtn_clicked()
{
CHECKLOADING
if (httpAccountListBox->currentRow() != -1) {
if (httpAccountListBox->currentRow() != -1)
{
auto item = httpAccountListBox->currentItem();
auto list = httpSettings["accounts"].toArray();
for (int i = 0 ; i < list.count(); i++) {
for (int i = 0; i < list.count(); i++)
{
auto user = list[i].toObject();
auto entry = user["user"].toString() + ":" + user["pass"].toString();
if (entry == item->text().trimmed()) {
if (entry == item->text().trimmed())
{
list.removeAt(i);
httpSettings["accounts"] = list;
LOG(MODULE_UI, "Removed http inbound user " + entry)
@ -206,8 +217,11 @@ void InboundEditor::on_httpRemoveUserBtn_clicked()
}
}
//QvMessageBox(this, tr("Removing a user"), tr("No user has been removed. Why?"));
} else {
// QvMessageBox(this, tr("Removing a user"), tr("No user has been
// removed. Why?"));
}
else
{
QvMessageBoxWarn(this, tr("Removing a user"), tr("You haven't selected a user yet."));
}
}
@ -220,10 +234,12 @@ void InboundEditor::on_httpAddUserBtn_clicked()
//
auto list = httpSettings["accounts"].toArray();
for (int i = 0 ; i < list.count(); i++) {
for (int i = 0; i < list.count(); i++)
{
auto _user = list[i].toObject();
if (_user["user"].toString() == user) {
if (_user["user"].toString() == user)
{
QvMessageBoxWarn(this, tr("Add a user"), tr("This user exists already."));
return;
}
@ -243,15 +259,18 @@ void InboundEditor::on_socksRemoveUserBtn_clicked()
{
CHECKLOADING
if (socksAccountListBox->currentRow() != -1) {
if (socksAccountListBox->currentRow() != -1)
{
auto item = socksAccountListBox->currentItem();
auto list = socksSettings["accounts"].toArray();
for (int i = 0 ; i < list.count(); i++) {
for (int i = 0; i < list.count(); i++)
{
auto user = list[i].toObject();
auto entry = user["user"].toString() + ":" + user["pass"].toString();
if (entry == item->text().trimmed()) {
if (entry == item->text().trimmed())
{
list.removeAt(i);
socksSettings["accounts"] = list;
LOG(MODULE_UI, "Removed http inbound user " + entry)
@ -259,7 +278,9 @@ void InboundEditor::on_socksRemoveUserBtn_clicked()
return;
}
}
} else {
}
else
{
QvMessageBoxWarn(this, tr("Removing a user"), tr("You haven't selected a user yet."));
}
}
@ -272,10 +293,12 @@ void InboundEditor::on_socksAddUserBtn_clicked()
//
auto list = socksSettings["accounts"].toArray();
for (int i = 0 ; i < list.count(); i++) {
for (int i = 0; i < list.count(); i++)
{
auto _user = list[i].toObject();
if (_user["user"].toString() == user) {
if (_user["user"].toString() == user)
{
QvMessageBoxWarn(this, tr("Add a user"), tr("This user exists already."));
return;
}
@ -322,12 +345,11 @@ void InboundEditor::on_destOverrideList_itemChanged(QListWidgetItem *item)
Q_UNUSED(item)
QJsonArray list;
for (int i = 0; i < destOverrideList->count(); i++) {
for (int i = 0; i < destOverrideList->count(); i++)
{
auto _item = destOverrideList->item(i);
if (_item->checkState() == Qt::Checked) {
list.append(_item->text().toLower());
}
if (_item->checkState() == Qt::Checked) { list.append(_item->text().toLower()); }
}
sniffing["destOverride"] = list;
@ -360,7 +382,7 @@ void InboundEditor::on_dokoIPAddrTxt_textEdited(const QString &arg1)
void InboundEditor::on_dokoPortSB_valueChanged(int arg1)
{
CHECKLOADING
dokoSettings["port"] = arg1;
dokoSettings["port"] = arg1;
}
void InboundEditor::on_dokoTCPCB_stateChanged(int arg1)
@ -461,5 +483,5 @@ void InboundEditor::on_inboundPortTxt_textEdited(const QString &arg1)
void InboundEditor::on_socksAuthCombo_currentIndexChanged(const QString &arg1)
{
CHECKLOADING
socksSettings["auth"] = arg1.toLower();
socksSettings["auth"] = arg1.toLower();
}

View File

@ -1,97 +1,100 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_InboundEditor.h"
#include <QDialog>
#include <QJsonObject>
#include <QListWidgetItem>
#include "ui_w_InboundEditor.h"
#include "base/Qv2rayBase.hpp"
#include "ui/messaging/QvMessageBus.hpp"
class InboundEditor : public QDialog, private Ui::InboundEditor
class InboundEditor
: public QDialog
, private Ui::InboundEditor
{
Q_OBJECT
Q_OBJECT
public:
explicit InboundEditor(INBOUND root, QWidget *parent = nullptr);
~InboundEditor();
INBOUND OpenEditor();
public slots:
QvMessageBusSlotDecl
public:
explicit InboundEditor(INBOUND root, QWidget *parent = nullptr);
~InboundEditor();
INBOUND OpenEditor();
public slots:
QvMessageBusSlotDecl;
private slots:
void on_inboundProtocolCombo_currentIndexChanged(const QString &arg1);
private slots:
void on_inboundProtocolCombo_currentIndexChanged(const QString &arg1);
void on_inboundProtocolCombo_currentIndexChanged(int index);
void on_inboundProtocolCombo_currentIndexChanged(int index);
void on_inboundTagTxt_textEdited(const QString &arg1);
void on_inboundTagTxt_textEdited(const QString &arg1);
void on_httpTimeoutSpinBox_valueChanged(int arg1);
void on_httpTimeoutSpinBox_valueChanged(int arg1);
void on_httpTransparentCB_stateChanged(int arg1);
void on_httpTransparentCB_stateChanged(int arg1);
void on_httpUserLevelSB_valueChanged(int arg1);
void on_httpUserLevelSB_valueChanged(int arg1);
void on_httpRemoveUserBtn_clicked();
void on_httpRemoveUserBtn_clicked();
void on_httpAddUserBtn_clicked();
void on_httpAddUserBtn_clicked();
void on_strategyCombo_currentIndexChanged(const QString &arg1);
void on_strategyCombo_currentIndexChanged(const QString &arg1);
void on_refreshNumberBox_valueChanged(int arg1);
void on_refreshNumberBox_valueChanged(int arg1);
void on_concurrencyNumberBox_valueChanged(int arg1);
void on_concurrencyNumberBox_valueChanged(int arg1);
void on_enableSniffingCB_stateChanged(int arg1);
void on_enableSniffingCB_stateChanged(int arg1);
void on_destOverrideList_itemChanged(QListWidgetItem *item);
void on_destOverrideList_itemChanged(QListWidgetItem *item);
void on_socksUDPCB_stateChanged(int arg1);
void on_socksUDPCB_stateChanged(int arg1);
void on_socksUDPIPAddrTxt_textEdited(const QString &arg1);
void on_socksUDPIPAddrTxt_textEdited(const QString &arg1);
void on_socksUserLevelSB_valueChanged(int arg1);
void on_socksUserLevelSB_valueChanged(int arg1);
void on_socksRemoveUserBtn_clicked();
void on_socksRemoveUserBtn_clicked();
void on_socksAddUserBtn_clicked();
void on_socksAddUserBtn_clicked();
void on_dokoIPAddrTxt_textEdited(const QString &arg1);
void on_dokoIPAddrTxt_textEdited(const QString &arg1);
void on_dokoPortSB_valueChanged(int arg1);
void on_dokoPortSB_valueChanged(int arg1);
void on_dokoTCPCB_stateChanged(int arg1);
void on_dokoTCPCB_stateChanged(int arg1);
void on_dokoUDPCB_stateChanged(int arg1);
void on_dokoUDPCB_stateChanged(int arg1);
void on_dokoTimeoutSB_valueChanged(int arg1);
void on_dokoTimeoutSB_valueChanged(int arg1);
void on_dokoFollowRedirectCB_stateChanged(int arg1);
void on_dokoFollowRedirectCB_stateChanged(int arg1);
void on_dokoUserLevelSB_valueChanged(int arg1);
void on_dokoUserLevelSB_valueChanged(int arg1);
void on_mtEMailTxt_textEdited(const QString &arg1);
void on_mtEMailTxt_textEdited(const QString &arg1);
void on_mtSecretTxt_textEdited(const QString &arg1);
void on_mtSecretTxt_textEdited(const QString &arg1);
void on_mtUserLevelSB_valueChanged(int arg1);
void on_mtUserLevelSB_valueChanged(int arg1);
void on_inboundHostTxt_textEdited(const QString &arg1);
void on_inboundHostTxt_textEdited(const QString &arg1);
void on_inboundPortTxt_textEdited(const QString &arg1);
void on_inboundPortTxt_textEdited(const QString &arg1);
void on_socksAuthCombo_currentIndexChanged(const QString &arg1);
void on_socksAuthCombo_currentIndexChanged(const QString &arg1);
private:
INBOUND GenerateNewRoot();
void LoadUIData();
INBOUND original;
INBOUND root;
//
QJsonObject httpSettings;
QJsonObject socksSettings;
QJsonObject mtSettings;
QJsonObject dokoSettings;
//
QJsonObject sniffing;
QJsonObject allocate;
private:
INBOUND GenerateNewRoot();
void LoadUIData();
INBOUND original;
INBOUND root;
//
QJsonObject httpSettings;
QJsonObject socksSettings;
QJsonObject mtSettings;
QJsonObject dokoSettings;
//
QJsonObject sniffing;
QJsonObject allocate;
};

View File

@ -2,20 +2,22 @@
#include "common/QvHelpers.hpp"
JsonEditor::JsonEditor(QJsonObject rootObject, QWidget *parent) :
QDialog(parent)
JsonEditor::JsonEditor(QJsonObject rootObject, QWidget *parent) : QDialog(parent)
{
QvMessageBusConnect(JsonEditor);
setupUi(this);
original = rootObject;
final = rootObject;
QString jsonString = JsonToString(rootObject);
QString jsonString = JsonToString(rootObject);
if (VerifyJsonString(jsonString).isEmpty()) {
if (VerifyJsonString(jsonString).isEmpty())
{
LOG(MODULE_UI, "Begin loading Json Model")
jsonTree->setModel(&model);
model.loadJson(QJsonDocument(rootObject).toJson());
} else {
}
else
{
QvMessageBoxWarn(this, tr("Json Contains Syntax Errors"), tr("Original Json may contain syntax errors. Json tree is disabled."));
}
@ -26,10 +28,9 @@ JsonEditor::JsonEditor(QJsonObject rootObject, QWidget *parent) :
QvMessageBusSlotImpl(JsonEditor)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -38,7 +39,8 @@ QJsonObject JsonEditor::OpenEditor()
int resultCode = this->exec();
auto string = jsonEditor->toPlainText();
while (resultCode == QDialog::Accepted && !VerifyJsonString(string).isEmpty()) {
while (resultCode == QDialog::Accepted && !VerifyJsonString(string).isEmpty())
{
QvMessageBoxWarn(this, tr("Json Contains Syntax Errors"), tr("You must correct these errors before continue."));
resultCode = this->exec();
string = jsonEditor->toPlainText();
@ -57,13 +59,16 @@ void JsonEditor::on_jsonEditor_textChanged()
auto VerifyResult = VerifyJsonString(string);
jsonValidateStatus->setText(VerifyResult);
if (VerifyResult.isEmpty()) {
if (VerifyResult.isEmpty())
{
BLACK(jsonEditor)
final = JsonFromString(string);
model.loadJson(QJsonDocument(final).toJson());
jsonTree->expandAll();
jsonTree->resizeColumnToContents(0);
} else {
}
else
{
RED(jsonEditor)
}
}
@ -74,10 +79,13 @@ void JsonEditor::on_formatJsonBtn_clicked()
auto VerifyResult = VerifyJsonString(string);
jsonValidateStatus->setText(VerifyResult);
if (VerifyResult.isEmpty()) {
if (VerifyResult.isEmpty())
{
BLACK(jsonEditor)
jsonEditor->setPlainText(JsonToString(JsonFromString(string)));
} else {
}
else
{
RED(jsonEditor)
QvMessageBoxWarn(this, tr("Syntax Errors"), tr("Please fix the JSON errors before continue"));
}

View File

@ -1,30 +1,33 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include "common/QJsonModel.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_JsonEditor.h"
#include <QDialog>
#include <QtCore>
#include "common/QJsonModel.hpp"
#include "base/Qv2rayBase.hpp"
#include "ui_w_JsonEditor.h"
#include "ui/messaging/QvMessageBus.hpp"
class JsonEditor : public QDialog, private Ui::JsonEditor
class JsonEditor
: public QDialog
, private Ui::JsonEditor
{
Q_OBJECT
Q_OBJECT
public:
explicit JsonEditor(QJsonObject rootObject, QWidget *parent = nullptr);
~JsonEditor();
QJsonObject OpenEditor();
public slots:
QvMessageBusSlotDecl
public:
explicit JsonEditor(QJsonObject rootObject, QWidget *parent = nullptr);
~JsonEditor();
QJsonObject OpenEditor();
public slots:
QvMessageBusSlotDecl;
private slots:
void on_jsonEditor_textChanged();
private slots:
void on_jsonEditor_textChanged();
void on_formatJsonBtn_clicked();
void on_formatJsonBtn_clicked();
private:
QJsonModel model;
QJsonObject original;
QJsonObject final;
private:
QJsonModel model;
QJsonObject original;
QJsonObject final;
};

View File

@ -1,20 +1,16 @@
#include <QDebug>
#include "w_OutboundEditor.hpp"
#include "core/connection/Generation.hpp"
#include "ui/editors/w_JsonEditor.hpp"
#include "ui/editors/w_RoutesEditor.hpp"
#include "ui/w_MainWindow.hpp"
#include <QFile>
#include <QIntValidator>
#include <iostream>
#include "w_OutboundEditor.hpp"
#include "ui/w_MainWindow.hpp"
#include "ui/editors/w_JsonEditor.hpp"
#include "ui/editors/w_RoutesEditor.hpp"
#include "core/connection/Generation.hpp"
OutboundEditor::OutboundEditor(QWidget *parent)
: QDialog(parent),
Tag(""),
Mux(),
vmess(),
shadowsocks()
OutboundEditor::OutboundEditor(QWidget *parent) : QDialog(parent), Tag(""), Mux(), vmess(), shadowsocks()
{
QvMessageBusConnect(OutboundEditor);
setupUi(this);
@ -40,10 +36,9 @@ OutboundEditor::OutboundEditor(QWidget *parent)
QvMessageBusSlotImpl(OutboundEditor)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -57,20 +52,28 @@ OutboundEditor::OutboundEditor(OUTBOUND outboundEntry, QWidget *parent) : Outbou
useFProxy = outboundEntry[QV2RAY_USE_FPROXY_KEY].toBool(false);
ssWidget->SetStreamObject(StructFromJsonString<StreamSettingsObject>(JsonToString(outboundEntry["streamSettings"].toObject())));
if (OutboundType == "vmess") {
vmess = StructFromJsonString<VMessServerObject>(JsonToString(outboundEntry["settings"].toObject()["vnext"].toArray().first().toObject()));
if (OutboundType == "vmess")
{
vmess =
StructFromJsonString<VMessServerObject>(JsonToString(outboundEntry["settings"].toObject()["vnext"].toArray().first().toObject()));
shadowsocks.port = vmess.port;
shadowsocks.address = vmess.address;
socks.address = vmess.address;
socks.port = vmess.port;
} else if (OutboundType == "shadowsocks") {
shadowsocks = StructFromJsonString<ShadowSocksServerObject>(JsonToString(outboundEntry["settings"].toObject()["servers"].toArray().first().toObject()));
}
else if (OutboundType == "shadowsocks")
{
shadowsocks = StructFromJsonString<ShadowSocksServerObject>(
JsonToString(outboundEntry["settings"].toObject()["servers"].toArray().first().toObject()));
vmess.address = shadowsocks.address;
vmess.port = shadowsocks.port;
socks.address = shadowsocks.address;
socks.port = shadowsocks.port;
} else if (OutboundType == "socks") {
socks = StructFromJsonString<SocksServerObject>(JsonToString(outboundEntry["settings"].toObject()["servers"].toArray().first().toObject()));
}
else if (OutboundType == "socks")
{
socks =
StructFromJsonString<SocksServerObject>(JsonToString(outboundEntry["settings"].toObject()["servers"].toArray().first().toObject()));
vmess.address = socks.address;
vmess.port = socks.port;
shadowsocks.address = socks.address;
@ -81,7 +84,6 @@ OutboundEditor::OutboundEditor(OUTBOUND outboundEntry, QWidget *parent) : Outbou
Result = GenerateConnectionJson();
}
OutboundEditor::~OutboundEditor()
{
}
@ -106,18 +108,23 @@ OUTBOUND OutboundEditor::GenerateConnectionJson()
OUTBOUNDSETTING settings;
auto streaming = GetRootObject(ssWidget->GetStreamSettings());
if (OutboundType == "vmess") {
if (OutboundType == "vmess")
{
// VMess is only a ServerObject, and we need an array { "vnext": [] }
QJsonArray vnext;
vnext.append(GetRootObject(vmess));
settings.insert("vnext", vnext);
} else if (OutboundType == "shadowsocks") {
}
else if (OutboundType == "shadowsocks")
{
streaming = QJsonObject();
LOG(MODULE_CONNECTION, "Shadowsocks outbound does not need StreamSettings.")
QJsonArray servers;
servers.append(GetRootObject(shadowsocks));
settings["servers"] = servers;
} else if (OutboundType == "socks") {
}
else if (OutboundType == "socks")
{
streaming = QJsonObject();
LOG(MODULE_CONNECTION, "Socks outbound does not need StreamSettings.")
QJsonArray servers;
@ -132,14 +139,17 @@ OUTBOUND OutboundEditor::GenerateConnectionJson()
void OutboundEditor::ReloadGUI()
{
if (OutboundType == "vmess") {
if (OutboundType == "vmess")
{
outBoundTypeCombo->setCurrentIndex(0);
ipLineEdit->setText(vmess.address);
portLineEdit->setText(QSTRN(vmess.port));
idLineEdit->setText(vmess.users.front().id);
alterLineEdit->setValue(vmess.users.front().alterId);
securityCombo->setCurrentText(vmess.users.front().security);
} else if (OutboundType == "shadowsocks") {
}
else if (OutboundType == "shadowsocks")
{
outBoundTypeCombo->setCurrentIndex(1);
// ShadowSocks Configs
ipLineEdit->setText(shadowsocks.address);
@ -149,7 +159,9 @@ void OutboundEditor::ReloadGUI()
ss_otaCheckBox->setChecked(shadowsocks.ota);
ss_passwordTxt->setText(shadowsocks.password);
ss_encryptionMethod->setCurrentText(shadowsocks.method);
} else if (OutboundType == "socks") {
}
else if (OutboundType == "socks")
{
outBoundTypeCombo->setCurrentIndex(2);
ipLineEdit->setText(socks.address);
portLineEdit->setText(QSTRN(socks.port));
@ -165,7 +177,6 @@ void OutboundEditor::ReloadGUI()
muxConcurrencyTxt->setValue(Mux["concurrency"].toInt());
}
void OutboundEditor::on_buttonBox_accepted()
{
Result = GenerateConnectionJson();
@ -180,7 +191,8 @@ void OutboundEditor::on_ipLineEdit_textEdited(const QString &arg1)
void OutboundEditor::on_portLineEdit_textEdited(const QString &arg1)
{
if (arg1 != "") {
if (arg1 != "")
{
vmess.port = arg1.toInt();
shadowsocks.port = arg1.toInt();
socks.port = arg1.toInt();

View File

@ -1,76 +1,79 @@
#pragma once
#include <QtCore>
#include <QDialog>
#include "base/Qv2rayBase.hpp"
#include "ui_w_OutboundEditor.h"
#include "ui/widgets/StreamSettingsWidget.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui/widgets/StreamSettingsWidget.hpp"
#include "ui_w_OutboundEditor.h"
class OutboundEditor : public QDialog, private Ui::OutboundEditor
#include <QDialog>
#include <QtCore>
class OutboundEditor
: public QDialog
, private Ui::OutboundEditor
{
Q_OBJECT
public:
explicit OutboundEditor(QWidget *parent = nullptr);
explicit OutboundEditor(OUTBOUND outboundEntry, QWidget *parent = nullptr);
~OutboundEditor();
OUTBOUND OpenEditor();
QString GetFriendlyName();
public slots:
QvMessageBusSlotDecl
signals:
void s_reload_config(bool need_restart);
private slots:
void on_buttonBox_accepted();
Q_OBJECT
public:
explicit OutboundEditor(QWidget *parent = nullptr);
explicit OutboundEditor(OUTBOUND outboundEntry, QWidget *parent = nullptr);
~OutboundEditor();
OUTBOUND OpenEditor();
QString GetFriendlyName();
public slots:
QvMessageBusSlotDecl;
signals:
void s_reload_config(bool need_restart);
private slots:
void on_buttonBox_accepted();
void on_ipLineEdit_textEdited(const QString &arg1);
void on_ipLineEdit_textEdited(const QString &arg1);
void on_portLineEdit_textEdited(const QString &arg1);
void on_portLineEdit_textEdited(const QString &arg1);
void on_idLineEdit_textEdited(const QString &arg1);
void on_idLineEdit_textEdited(const QString &arg1);
void on_tagTxt_textEdited(const QString &arg1);
void on_tagTxt_textEdited(const QString &arg1);
void on_muxEnabledCB_stateChanged(int arg1);
void on_muxEnabledCB_stateChanged(int arg1);
void on_muxConcurrencyTxt_valueChanged(int arg1);
void on_muxConcurrencyTxt_valueChanged(int arg1);
void on_alterLineEdit_valueChanged(int arg1);
void on_alterLineEdit_valueChanged(int arg1);
void on_useFPCB_stateChanged(int arg1);
void on_useFPCB_stateChanged(int arg1);
void on_outBoundTypeCombo_currentIndexChanged(int index);
void on_outBoundTypeCombo_currentIndexChanged(int index);
void on_ss_emailTxt_textEdited(const QString &arg1);
void on_ss_emailTxt_textEdited(const QString &arg1);
void on_ss_passwordTxt_textEdited(const QString &arg1);
void on_ss_passwordTxt_textEdited(const QString &arg1);
void on_ss_encryptionMethod_currentIndexChanged(const QString &arg1);
void on_ss_encryptionMethod_currentIndexChanged(const QString &arg1);
void on_ss_levelSpin_valueChanged(int arg1);
void on_ss_levelSpin_valueChanged(int arg1);
void on_ss_otaCheckBox_stateChanged(int arg1);
void on_ss_otaCheckBox_stateChanged(int arg1);
void on_socks_UserNameTxt_textEdited(const QString &arg1);
void on_socks_UserNameTxt_textEdited(const QString &arg1);
void on_socks_PasswordTxt_textEdited(const QString &arg1);
void on_socks_PasswordTxt_textEdited(const QString &arg1);
void on_securityCombo_currentIndexChanged(const QString &arg1);
void on_securityCombo_currentIndexChanged(const QString &arg1);
private:
QString Tag;
void ReloadGUI();
bool useFProxy;
OUTBOUND GenerateConnectionJson();
OUTBOUND Original;
OUTBOUND Result;
QJsonObject Mux;
//
// Connection Configs
QString OutboundType;
//
VMessServerObject vmess;
ShadowSocksServerObject shadowsocks;
SocksServerObject socks;
//
StreamSettingsWidget *ssWidget;
private:
QString Tag;
void ReloadGUI();
bool useFProxy;
OUTBOUND GenerateConnectionJson();
OUTBOUND Original;
OUTBOUND Result;
QJsonObject Mux;
//
// Connection Configs
QString OutboundType;
//
VMessServerObject vmess;
ShadowSocksServerObject shadowsocks;
SocksServerObject socks;
//
StreamSettingsWidget *ssWidget;
};

View File

@ -1,36 +1,40 @@
// WARNING
// Since it's required for *extra.cpp to know the content of those macros defined below.
// We include this CPP file instead of the proper HPP file. Adding #pragma once to prevent duplicate function instances
// Since it's required for *extra.cpp to know the content of those macros
// defined below. We include this CPP file instead of the proper HPP file.
// Adding #pragma once to prevent duplicate function instances
#pragma once
#include "w_RoutesEditor.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/connection/Generation.hpp"
#include "w_OutboundEditor.hpp"
#include "w_JsonEditor.hpp"
#include "w_InboundEditor.hpp"
#include "ui/w_ImportConfig.hpp"
#include "core/CoreUtils.hpp"
#include "ui/models/RuleNodeModel.hpp"
#include "ui/models/InboundNodeModel.hpp"
#include "ui/models/OutboundNodeModel.hpp"
#include "NodeStyle.hpp"
#include "FlowView.hpp"
#include "FlowViewStyle.hpp"
#include "NodeStyle.hpp"
#include "core/CoreUtils.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/connection/Generation.hpp"
#include "ui/models/InboundNodeModel.hpp"
#include "ui/models/OutboundNodeModel.hpp"
#include "ui/models/RuleNodeModel.hpp"
#include "ui/w_ImportConfig.hpp"
#include "w_InboundEditor.hpp"
#include "w_JsonEditor.hpp"
#include "w_OutboundEditor.hpp"
using QtNodes::FlowView;
using namespace Qv2ray::ui::nodemodels;
static bool isLoading = false;
#define CurrentRule this->rules[this->currentRuleTag]
#define LOADINGCHECK if(isLoading) return;
#define GetFirstNodeData(node, nodeModel, dataModel) (static_cast<dataModel *>(static_cast<nodeModel *>((node).nodeDataModel())->outData(0).get()))
#define LOADINGCHECK \
if (isLoading) return;
#define GetFirstNodeData(node, nodeModel, dataModel) \
(static_cast<dataModel *>(static_cast<nodeModel *>((node).nodeDataModel())->outData(0).get()))
#define CHECKEMPTYRULES if (this->rules.isEmpty()) { \
LOG(MODULE_UI, "No rules currently, we add one.") \
AddNewRule(); \
#define CHECKEMPTYRULES \
if (this->rules.isEmpty()) \
{ \
LOG(MODULE_UI, "No rules currently, we add one.") \
AddNewRule(); \
}
#define GRAPH_GLOBAL_OFFSET_X -80
@ -41,18 +45,25 @@ static bool isLoading = false;
void RouteEditor::SetupNodeWidget()
{
if (GlobalConfig.uiConfig.useDarkTheme) {
ConnectionStyle::setConnectionStyle(R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
if (GlobalConfig.uiConfig.useDarkTheme)
{
ConnectionStyle::setConnectionStyle(
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,
"ConstructionLineWidth": 2.0,"PointDiameter": 10.0,"UseDataDefinedColors": true}})");
} else {
QtNodes::NodeStyle::setNodeStyle(R"({"NodeStyle": {"NormalBoundaryColor": "darkgray","SelectedBoundaryColor": "deepskyblue",
}
else
{
QtNodes::NodeStyle::setNodeStyle(
R"({"NodeStyle": {"NormalBoundaryColor": "darkgray","SelectedBoundaryColor": "deepskyblue",
"GradientColor0": "mintcream","GradientColor1": "mintcream","GradientColor2": "mintcream",
"GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10],
"FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5,
"ConnectionPointDiameter": 10.0,"Opacity": 1.0}})");
QtNodes::FlowViewStyle::setStyle(R"({"FlowViewStyle": {"BackgroundColor": [255, 255, 240],"FineGridColor": [245, 245, 230],"CoarseGridColor": [235, 235, 220]}})");
ConnectionStyle::setConnectionStyle(R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
QtNodes::FlowViewStyle::setStyle(
R"({"FlowViewStyle": {"BackgroundColor": [255, 255, 240],"FineGridColor": [245, 245, 230],"CoarseGridColor": [235, 235, 220]}})");
ConnectionStyle::setConnectionStyle(
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0,
"PointDiameter": 10.0,"UseDataDefinedColors": false}})");
}
@ -91,17 +102,20 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare
domainStrategyCombo->setCurrentText(domainStrategy);
// Show connections in the node graph
for (auto in : root["inbounds"].toArray()) {
for (auto in : root["inbounds"].toArray())
{
INBOUND _in = INBOUND(in.toObject());
AddInbound(_in);
}
for (auto out : root["outbounds"].toArray()) {
for (auto out : root["outbounds"].toArray())
{
OUTBOUND _out = OUTBOUND(out.toObject());
AddOutbound(_out);
}
for (auto item : root["routing"].toObject()["rules"].toArray()) {
for (auto item : root["routing"].toObject()["rules"].toArray())
{
auto _rule = StructFromJsonString<RuleObject>(JsonToString(item.toObject()));
AddRule(_rule);
}
@ -110,12 +124,12 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare
defaultOutboundCombo->setCurrentText(root["outbounds"].toArray().first().toObject()["tag"].toString());
// Find and add balancers.
for (auto _balancer : root["routing"].toObject()["balancers"].toArray()) {
for (auto _balancer : root["routing"].toObject()["balancers"].toArray())
{
auto _balancerObject = _balancer.toObject();
if (!_balancerObject["tag"].toString().isEmpty()) {
balancers[_balancerObject["tag"].toString()] = _balancerObject["selector"].toVariant().toStringList();
}
if (!_balancerObject["tag"].toString().isEmpty())
{ balancers[_balancerObject["tag"].toString()] = _balancerObject["selector"].toVariant().toStringList(); }
}
isLoading = false;
@ -123,10 +137,9 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare
QvMessageBusSlotImpl(RouteEditor)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -140,25 +153,31 @@ void RouteEditor::onNodeClicked(Node &n)
auto isIn = inboundNodes.values().contains(&n);
auto isRule = ruleNodes.values().contains(&n);
if (isRule) {
if (isRule)
{
// It's a rule object
currentRuleTag = GetFirstNodeData(n, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
DEBUG(MODULE_GRAPH, "Selecting rule: " + currentRuleTag)
ShowCurrentRuleDetail();
toolBox->setCurrentIndex(1);
} else if (isOut || isIn) {
}
else if (isOut || isIn)
{
// It's an inbound or an outbound.
QString alias;
QString host;
int port;
QString protocol;
if (isOut) {
if (isOut)
{
alias = GetFirstNodeData(n, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
QJsonObject _root = outbounds[alias].raw();
throw new runtime_error("Not implemented");
GetOutboundData(OUTBOUND(_root), &host, &port, &protocol);
} else {
}
else
{
alias = GetFirstNodeData(n, QvInboundNodeModel, InboundNodeData)->GetInbound();
QJsonObject _root = inbounds[alias].raw();
host = _root["listen"].toString();
@ -170,7 +189,9 @@ void RouteEditor::onNodeClicked(Node &n)
protocolLabel->setText(protocol);
portLabel->setNum(port);
hostLabel->setText(host);
} else {
}
else
{
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
}
}
@ -185,7 +206,8 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
auto const sourceNode = c.getNode(PortType::Out);
auto const targetNode = c.getNode(PortType::In);
if (inboundNodes.values().contains(sourceNode) && ruleNodes.values().contains(targetNode)) {
if (inboundNodes.values().contains(sourceNode) && ruleNodes.values().contains(targetNode))
{
// It's a inbound-rule connection
onNodeClicked(*sourceNode);
onNodeClicked(*targetNode);
@ -194,14 +216,16 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
// QStringList has an helper to let us remove duplicates, see below.
QStringList _inbounds;
for (auto &&[_, conn] : nodeScene->connections()) {
for (auto &&[_, conn] : nodeScene->connections())
{
auto _connection = conn.get();
if (_connection->getNode(PortType::In) == targetNode && _connection->getNode(PortType::Out) == sourceNode && _connection->id() != c.id()) {
nodeScene->deleteConnection(*_connection);
}
if (_connection->getNode(PortType::In) == targetNode && _connection->getNode(PortType::Out) == sourceNode &&
_connection->id() != c.id())
{ nodeScene->deleteConnection(*_connection); }
// Append all inbounds
else if (_connection->getNode(PortType::In) == targetNode) {
else if (_connection->getNode(PortType::In) == targetNode)
{
_inbounds.append(GetFirstNodeData(*_connection->getNode(PortType::Out), QvInboundNodeModel, InboundNodeData)->GetInbound());
}
}
@ -209,7 +233,9 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
// caused by multi-in connection
_inbounds.removeDuplicates();
CurrentRule.inboundTag = _inbounds;
} else if (ruleNodes.values().contains(sourceNode) && outboundNodes.values().contains(targetNode)) {
}
else if (ruleNodes.values().contains(sourceNode) && outboundNodes.values().contains(targetNode))
{
// It's a rule-outbound connection
onNodeClicked(*sourceNode);
onNodeClicked(*targetNode);
@ -219,7 +245,9 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
// Update balancer settings.
ShowCurrentRuleDetail();
LOG(MODULE_GRAPH, "Updated outbound: " + CurrentRule.outboundTag)
} else {
}
else
{
// It's an impossible connection
LOG(MODULE_GRAPH, "Unrecognized connection, RARE.")
}
@ -235,7 +263,8 @@ void RouteEditor::onConnectionDeleted(QtNodes::Connection const &c)
auto const source = c.getNode(PortType::Out);
auto const target = c.getNode(PortType::In);
if (inboundNodes.values().contains(source) && ruleNodes.values().contains(target)) {
if (inboundNodes.values().contains(source) && ruleNodes.values().contains(target))
{
// It's a inbound-rule connection
onNodeClicked(*source);
onNodeClicked(*target);
@ -243,19 +272,21 @@ void RouteEditor::onConnectionDeleted(QtNodes::Connection const &c)
auto _inboundTag = GetFirstNodeData(*source, QvInboundNodeModel, InboundNodeData)->GetInbound();
LOG(MODULE_UI, "Removing inbound: " + _inboundTag + " from rule: " + currentRuleTag)
CurrentRule.inboundTag.removeAll(_inboundTag);
} else if (ruleNodes.values().contains(source) && outboundNodes.values().contains(target)) {
}
else if (ruleNodes.values().contains(source) && outboundNodes.values().contains(target))
{
// It's a rule-outbound connection
onNodeClicked(*source);
onNodeClicked(*target);
currentRuleTag = GetFirstNodeData(*source, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
auto _outboundTag = GetFirstNodeData(*target, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
if (!CurrentRule.QV2RAY_RULE_USE_BALANCER && CurrentRule.outboundTag == _outboundTag) {
CurrentRule.outboundTag.clear();
}
if (!CurrentRule.QV2RAY_RULE_USE_BALANCER && CurrentRule.outboundTag == _outboundTag) { CurrentRule.outboundTag.clear(); }
LOG(MODULE_GRAPH, "Removing an outbound: " + _outboundTag)
} else {
}
else
{
// It's an impossible connection
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
}
@ -265,30 +296,35 @@ CONFIGROOT RouteEditor::OpenEditor()
{
auto result = this->exec();
if (rules.isEmpty()) {
// Prevent empty rule list causing mis-detection of config type to simple.
if (rules.isEmpty())
{
// Prevent empty rule list causing mis-detection of config type to
// simple.
on_addRouteBtn_clicked();
}
// If clicking OK
if (result == QDialog::Accepted) {
if (result == QDialog::Accepted)
{
QJsonArray rulesArray;
QJsonArray _balancers;
// Append rules by order
for (auto i = 0; i < ruleListWidget->count(); i++) {
for (auto i = 0; i < ruleListWidget->count(); i++)
{
auto _rule = rules[ruleListWidget->item(i)->text()];
auto ruleJsonObject = GetRootObject(_rule);
// Process balancer for a rule
if (_rule.QV2RAY_RULE_USE_BALANCER) {
if (_rule.QV2RAY_RULE_USE_BALANCER)
{
// Do not use outbound tag.
ruleJsonObject.remove("outboundTag");
// Find balancer list
if (!balancers.contains(_rule.balancerTag)) {
LOG(MODULE_UI, "Cannot find a balancer for tag: " + _rule.balancerTag)
} else {
if (!balancers.contains(_rule.balancerTag)) { LOG(MODULE_UI, "Cannot find a balancer for tag: " + _rule.balancerTag) }
else
{
auto _balancerList = balancers[_rule.balancerTag];
QJsonObject balancerEntry;
balancerEntry["tag"] = _rule.balancerTag;
@ -298,13 +334,9 @@ CONFIGROOT RouteEditor::OpenEditor()
}
// Remove some empty fields.
if (_rule.port.isEmpty()) {
ruleJsonObject.remove("port");
}
if (_rule.port.isEmpty()) { ruleJsonObject.remove("port"); }
if (_rule.network.isEmpty()) {
ruleJsonObject.remove("network");
}
if (_rule.network.isEmpty()) { ruleJsonObject.remove("network"); }
rulesArray.append(ruleJsonObject);
}
@ -318,22 +350,25 @@ CONFIGROOT RouteEditor::OpenEditor()
QJsonArray _outbounds;
// Convert our internal data format to QJsonArray
for (auto x : inbounds) {
if (x.isEmpty())
continue;
for (auto x : inbounds)
{
if (x.isEmpty()) continue;
_inbounds.append(x.raw());
}
for (auto x : outbounds) {
if (x.isEmpty())
continue;
for (auto x : outbounds)
{
if (x.isEmpty()) continue;
if (getTag(x) == defaultOutbound) {
if (getTag(x) == defaultOutbound)
{
LOG(MODULE_CONNECTION, "Pushing default outbound to the front.")
// Put the default outbound to the first.
_outbounds.push_front(x.raw());
} else {
}
else
{
_outbounds.push_back(x.raw());
}
}
@ -342,7 +377,9 @@ CONFIGROOT RouteEditor::OpenEditor()
root["outbounds"] = _outbounds;
root["routing"] = routing;
return root;
} else {
}
else
{
return original;
}
}
@ -355,18 +392,22 @@ RouteEditor::~RouteEditor()
disconnect(nodeScene, &FlowScene::connectionCreated, this, &RouteEditor::onConnectionCreated);
disconnect(nodeScene, &FlowScene::nodeClicked, this, &RouteEditor::onNodeClicked);
}
void RouteEditor::on_buttonBox_accepted() {}
void RouteEditor::on_buttonBox_accepted()
{
}
void RouteEditor::ShowCurrentRuleDetail()
{
LOADINGCHECK
if (currentRuleTag.isEmpty()) {
if (currentRuleTag.isEmpty())
{
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
return;
}
if (!rules.contains(currentRuleTag)) {
if (!rules.contains(currentRuleTag))
{
QvMessageBoxWarn(this, tr("Show rule details"), tr("A rule cannot be found: ") + currentRuleTag);
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
return;
@ -384,16 +425,15 @@ void RouteEditor::ShowCurrentRuleDetail()
balancerSelectionCombo->clear();
// BUG added the wrong items, should be outbound list.
for (auto out : outbounds) {
balancerSelectionCombo->addItem((out)["tag"].toString());
}
for (auto out : outbounds) { balancerSelectionCombo->addItem((out)["tag"].toString()); }
//
// Balancers combo and balancer list.
enableBalancerCB->setChecked(CurrentRule.QV2RAY_RULE_USE_BALANCER);
balancersWidget->setEnabled(CurrentRule.QV2RAY_RULE_USE_BALANCER);
if (!CurrentRule.balancerTag.isEmpty()) {
if (!CurrentRule.balancerTag.isEmpty())
{
balancerList->clear();
balancerList->addItems(balancers[CurrentRule.balancerTag]);
}
@ -490,12 +530,15 @@ void RouteEditor::on_balancerAddBtn_clicked()
LOADINGCHECK
auto balancerTx = balancerSelectionCombo->currentText();
if (!balancerTx.isEmpty()) {
if (!balancerTx.isEmpty())
{
this->balancers[CurrentRule.balancerTag].append(balancerSelectionCombo->currentText());
balancerList->addItem(balancerTx);
balancerSelectionCombo->setEditText("");
statusLabel->setText(tr("OK"));
} else {
}
else
{
statusLabel->setText(tr("Balancer is empty, not processing."));
}
}
@ -503,9 +546,7 @@ void RouteEditor::on_balancerDelBtn_clicked()
{
LOADINGCHECK
if (balancerList->currentRow() < 0) {
return;
}
if (balancerList->currentRow() < 0) { return; }
balancers[CurrentRule.balancerTag].removeAt(balancerList->currentRow());
balancerList->takeItem(balancerList->currentRow());
@ -568,7 +609,8 @@ void RouteEditor::on_enableBalancerCB_stateChanged(int arg1)
CurrentRule.QV2RAY_RULE_USE_BALANCER = useBalancer;
balancersWidget->setEnabled(useBalancer);
if (CurrentRule.balancerTag.isEmpty()) {
if (CurrentRule.balancerTag.isEmpty())
{
LOG(MODULE_UI, "Creating a new balancer tag.")
CurrentRule.balancerTag = GenerateRandomString(6);
balancers[CurrentRule.balancerTag] = QStringList();
@ -576,16 +618,18 @@ void RouteEditor::on_enableBalancerCB_stateChanged(int arg1)
DEBUG(MODULE_UI, "Balancer: " + CurrentRule.balancerTag)
if (useBalancer) {
if (useBalancer)
{
LOG(MODULE_UI, "A rule has been set to use balancer, disconnect it to any outbound.")
auto ruleNode = ruleNodes[currentRuleTag];
for (auto &&[_, conn] : nodeScene->connections()) {
if (conn.get()->getNode(PortType::Out) == ruleNode) {
nodeScene->deleteConnection(*conn);
}
for (auto &&[_, conn] : nodeScene->connections())
{
if (conn.get()->getNode(PortType::Out) == ruleNode) { nodeScene->deleteConnection(*conn); }
}
} else {
}
else
{
QvMessageBoxWarn(this, tr("Route Editor"), tr("To make this rule ready to use, you need to connect it to an outbound node."));
}
}
@ -597,8 +641,7 @@ void RouteEditor::on_addDefaultBtn_clicked()
auto _Inconfig = GlobalConfig.inboundConfig;
//
auto _in_httpConf = GenerateHTTPIN(QList<AccountObject>() << _Inconfig.httpAccount);
auto _in_socksConf = GenerateSocksIN((_Inconfig.socks_useAuth ? "password" : "noauth"),
QList<AccountObject>() << _Inconfig.socksAccount,
auto _in_socksConf = GenerateSocksIN((_Inconfig.socks_useAuth ? "password" : "noauth"), QList<AccountObject>() << _Inconfig.socksAccount,
_Inconfig.socksUDP, _Inconfig.socksLocalIP);
//
auto _in_HTTP = GenerateInboundEntry(_Inconfig.listenip, _Inconfig.http_port, "http", _in_httpConf, "HTTP_gConf");
@ -622,9 +665,7 @@ void RouteEditor::on_addInboundBtn_clicked()
InboundEditor w(INBOUND(), this);
auto _result = w.OpenEditor();
if (w.result() == QDialog::Accepted) {
AddInbound(_result);
}
if (w.result() == QDialog::Accepted) { AddInbound(_result); }
CHECKEMPTYRULES
}
@ -635,19 +676,17 @@ void RouteEditor::on_addOutboundBtn_clicked()
// True here for not keep the inbounds.
auto configs = w.OpenImport(true);
for (auto i = 0; i < configs.count(); i++) {
for (auto i = 0; i < configs.count(); i++)
{
auto conf = configs.values()[i];
auto name = configs.key(conf, "");
if (name.isEmpty())
continue;
if (name.isEmpty()) continue;
// conf is rootObject, needs to unwrap it.
auto confList = conf["outbounds"].toArray();
for (int i = 0; i < confList.count(); i++) {
AddOutbound(OUTBOUND(confList[i].toObject()));
}
for (int i = 0; i < confList.count(); i++) { AddOutbound(OUTBOUND(confList[i].toObject())); }
}
CHECKEMPTYRULES
@ -661,7 +700,8 @@ void RouteEditor::on_ruleEnableCB_stateChanged(int arg1)
}
void RouteEditor::on_delBtn_clicked()
{
if (nodeScene->selectedNodes().empty()) {
if (nodeScene->selectedNodes().empty())
{
QvMessageBoxWarn(this, tr("Remove Items"), tr("Please select a node from the graph to continue."));
return;
}
@ -671,40 +711,46 @@ void RouteEditor::on_delBtn_clicked()
auto isOutbound = outboundNodes.values().contains(firstNode);
auto isRule = ruleNodes.values().contains(firstNode);
// Get the tag first, and call inbounds/outbounds/rules container variable remove()
// Remove the node last since some events may trigger.
// Then remove the node container.
if (isInbound) {
// Get the tag first, and call inbounds/outbounds/rules container variable
// remove() Remove the node last since some events may trigger. Then remove
// the node container.
if (isInbound)
{
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound();
nodeScene->removeNode(*inboundNodes[currentInboundOutboundTag]);
inboundNodes.remove(currentInboundOutboundTag);
// Remove corresponded inbound tags from the rules.
for (auto k : rules.keys()) {
for (auto k : rules.keys())
{
auto v = rules[k];
v.inboundTag.removeAll(currentInboundOutboundTag);
rules[k] = v;
}
inbounds.remove(currentInboundOutboundTag);
} else if (isOutbound) {
}
else if (isOutbound)
{
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
outbounds.remove(currentInboundOutboundTag);
ResolveDefaultOutboundTag(currentInboundOutboundTag, "");
// Remove corresponded outbound tags from the rules.
for (auto k : rules.keys()) {
for (auto k : rules.keys())
{
auto v = rules[k];
if (v.outboundTag == currentInboundOutboundTag)
v.outboundTag.clear();
if (v.outboundTag == currentInboundOutboundTag) v.outboundTag.clear();
rules[k] = v;
}
nodeScene->removeNode(*outboundNodes[currentInboundOutboundTag]);
outboundNodes.remove(currentInboundOutboundTag);
} else if (isRule) {
}
else if (isRule)
{
ruleEnableCB->setEnabled(false);
ruleTagLineEdit->setEnabled(false);
ruleRenameBtn->setEnabled(false);
@ -719,27 +765,30 @@ void RouteEditor::on_delBtn_clicked()
// Remove item from the rule order list widget.
ruleListWidget->takeItem(ruleListWidget->row(ruleListWidget->findItems(RuleTag, Qt::MatchExactly).first()));
CHECKEMPTYRULES
//currentRuleTag = rules.firstKey();
//ShowCurrentRuleDetail();
} else {
// currentRuleTag = rules.firstKey();
// ShowCurrentRuleDetail();
}
else
{
LOG(MODULE_UI, "Unknown node selected.")
QvMessageBoxWarn(this, tr("Error"), tr("Qv2ray entered an unknown state."));
}
}
void RouteEditor::on_editBtn_clicked()
{
if (nodeScene->selectedNodes().empty()) {
QvMessageBoxWarn(this, tr("Edit Inbound/Outbound"), tr("Please select a node from the graph to continue."));
}
if (nodeScene->selectedNodes().empty())
{ QvMessageBoxWarn(this, tr("Edit Inbound/Outbound"), tr("Please select a node from the graph to continue.")); }
auto firstNode = nodeScene->selectedNodes().at(0);
auto isInbound = inboundNodes.values().contains(firstNode);
auto isOutbound = outboundNodes.values().contains(firstNode);
if (isInbound) {
if (isInbound)
{
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound();
if (!inbounds.contains(currentInboundOutboundTag)) {
if (!inbounds.contains(currentInboundOutboundTag))
{
QvMessageBoxWarn(this, tr("Edit Inbound"), tr("No inbound tag found: ") + currentInboundOutboundTag);
return;
}
@ -749,14 +798,18 @@ void RouteEditor::on_editBtn_clicked()
auto protocol = _in["protocol"].toString();
int _code;
if (protocol != "http" && protocol != "mtproto" && protocol != "socks" && protocol != "dokodemo-door") {
QvMessageBoxWarn(this, tr("Cannot Edit"), tr("Currently, this type of outbound is not supported by the editor.") + "\r\n" +
tr("We will launch Json Editor instead."));
if (protocol != "http" && protocol != "mtproto" && protocol != "socks" && protocol != "dokodemo-door")
{
QvMessageBoxWarn(this, tr("Cannot Edit"),
tr("Currently, this type of outbound is not supported by the editor.") + "\r\n" +
tr("We will launch Json Editor instead."));
statusLabel->setText(tr("Opening JSON editor"));
JsonEditor w(_in, this);
_result = INBOUND(w.OpenEditor());
_code = w.result();
} else {
}
else
{
InboundEditor w(_in, this);
statusLabel->setText(tr("Opening default inbound editor"));
_result = w.OpenEditor();
@ -765,22 +818,24 @@ void RouteEditor::on_editBtn_clicked()
statusLabel->setText(tr("OK"));
if (_code == QDialog::Accepted) {
if (_code == QDialog::Accepted)
{
bool isTagChanged = getTag(_in) != getTag(_result);
if (isTagChanged) {
RenameItemTag(RENAME_INBOUND, getTag(_in), getTag(_result));
}
if (isTagChanged) { RenameItemTag(RENAME_INBOUND, getTag(_in), getTag(_result)); }
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_in))
inbounds.remove(getTag(_in));
DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result))
inbounds[getTag(_result)] = _result;
}
} else if (isOutbound) {
}
else if (isOutbound)
{
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
if (!outbounds.contains(currentInboundOutboundTag)) {
if (!outbounds.contains(currentInboundOutboundTag))
{
QvMessageBoxWarn(this, tr("Edit Inbound"), tr("No inbound tag found: ") + currentInboundOutboundTag);
return;
}
@ -790,25 +845,30 @@ void RouteEditor::on_editBtn_clicked()
auto protocol = _out["protocol"].toString().toLower();
int _code;
if (protocol != "vmess" && protocol != "shadowsocks" && protocol != "socks") {
if (protocol != "vmess" && protocol != "shadowsocks" && protocol != "socks")
{
QvMessageBoxWarn(this, tr("Unsupported Outbound Type"),
tr("This outbound entry is not supported by the GUI editor.") + NEWLINE +
tr("We will launch Json Editor instead."));
tr("We will launch Json Editor instead."));
JsonEditor w(_out, this);
statusLabel->setText(tr("Opening JSON editor"));
_result = OUTBOUND(w.OpenEditor());
_code = w.result();
} else {
}
else
{
OutboundEditor w(_out, this);
statusLabel->setText(tr("Opening default outbound editor."));
_result = w.OpenEditor();
_code = w.result();
}
if (_code == QDialog::Accepted) {
if (_code == QDialog::Accepted)
{
bool isTagChanged = getTag(_out) != getTag(_result);
if (isTagChanged) {
if (isTagChanged)
{
DEBUG(MODULE_UI, "Outbound tag is changed: " + QString(isTagChanged))
RenameItemTag(RENAME_OUTBOUND, getTag(_out), getTag(_result));
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_out))
@ -819,7 +879,9 @@ void RouteEditor::on_editBtn_clicked()
outbounds[getTag(_result)] = _result;
statusLabel->setText(tr("OK"));
}
} else {
}
else
{
LOG(MODULE_UI, "Cannot apply 'edit' operation to non-inbound and non-outbound")
}
}
@ -840,16 +902,23 @@ void RouteEditor::on_ruleRenameBtn_clicked()
{
auto newTag = ruleTagLineEdit->text();
if (newTag.isEmpty()) {
if (newTag.isEmpty())
{
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) {
}
else if (newTag == CurrentRule.QV2RAY_RULE_TAG)
{
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)) {
}
else if (rules.contains(newTag))
{
LOG(MODULE_UI, "Tag duplicate detected.")
QvMessageBoxWarn(this, tr("Renaming a tag"), tr("Duplicate rule tag detected, please try another."));
} else {
}
else
{
RenameItemTag(RENAME_RULE, CurrentRule.QV2RAY_RULE_TAG, newTag);
}
}

View File

@ -1,131 +1,134 @@
#pragma once
#include <list>
#include "ConnectionStyle.hpp"
#include "FlowScene.hpp"
#include "Node.hpp"
#include "NodeData.hpp"
#include "common/QvHelpers.hpp"
#include <QDialog>
#include <QJsonArray>
#include <QJsonObject>
#include <QListWidgetItem>
#include "common/QvHelpers.hpp"
#include <list>
#include "Node.hpp"
#include "NodeData.hpp"
#include "ConnectionStyle.hpp"
#include "FlowScene.hpp"
using QtNodes::Node;
using QtNodes::FlowScene;
using QtNodes::ConnectionStyle;
using QtNodes::FlowScene;
using QtNodes::Node;
#include "ui_w_RoutesEditor.h"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_RoutesEditor.h"
enum ROUTE_EDIT_MODE {
enum ROUTE_EDIT_MODE
{
RENAME_INBOUND,
RENAME_OUTBOUND,
RENAME_RULE,
};
class RouteEditor : public QDialog, private Ui::RouteEditor
class RouteEditor
: public QDialog
, private Ui::RouteEditor
{
Q_OBJECT
Q_OBJECT
public:
explicit RouteEditor(QJsonObject connection, QWidget *parent = nullptr);
~RouteEditor();
CONFIGROOT OpenEditor();
public slots:
QvMessageBusSlotDecl
public:
explicit RouteEditor(QJsonObject connection, QWidget *parent = nullptr);
~RouteEditor();
CONFIGROOT OpenEditor();
public slots:
QvMessageBusSlotDecl;
private slots:
void on_buttonBox_accepted();
private slots:
void on_buttonBox_accepted();
void on_insertDirectBtn_clicked();
void on_insertDirectBtn_clicked();
void on_routeProtocolHTTPCB_stateChanged(int arg1);
void on_routeProtocolHTTPCB_stateChanged(int arg1);
void on_routeProtocolTLSCB_stateChanged(int arg1);
void on_routeProtocolTLSCB_stateChanged(int arg1);
void on_routeProtocolBTCB_stateChanged(int arg1);
void on_routeProtocolBTCB_stateChanged(int arg1);
void on_balancerAddBtn_clicked();
void on_balancerAddBtn_clicked();
void on_balancerDelBtn_clicked();
void on_balancerDelBtn_clicked();
void on_hostList_textChanged();
void on_hostList_textChanged();
void on_ipList_textChanged();
void on_ipList_textChanged();
void on_routePortTxt_textEdited(const QString &arg1);
void on_routePortTxt_textEdited(const QString &arg1);
void on_routeUserTxt_textEdited(const QString &arg1);
void on_routeUserTxt_textEdited(const QString &arg1);
void on_addRouteBtn_clicked();
void on_addRouteBtn_clicked();
void on_netBothRB_clicked();
void on_netBothRB_clicked();
void on_netUDPRB_clicked();
void on_netUDPRB_clicked();
void on_netTCPRB_clicked();
void on_netTCPRB_clicked();
void on_routeUserTxt_textChanged();
void on_routeUserTxt_textChanged();
void on_sourceIPList_textChanged();
void on_sourceIPList_textChanged();
void on_enableBalancerCB_stateChanged(int arg1);
void on_enableBalancerCB_stateChanged(int arg1);
void on_addDefaultBtn_clicked();
void on_addDefaultBtn_clicked();
void on_insertBlackBtn_clicked();
void on_insertBlackBtn_clicked();
void on_addInboundBtn_clicked();
void on_addInboundBtn_clicked();
void on_addOutboundBtn_clicked();
void on_addOutboundBtn_clicked();
void on_ruleEnableCB_stateChanged(int arg1);
void on_ruleEnableCB_stateChanged(int arg1);
void on_delBtn_clicked();
void on_delBtn_clicked();
void on_editBtn_clicked();
void on_editBtn_clicked();
void on_domainStrategyCombo_currentIndexChanged(const QString &arg1);
void on_domainStrategyCombo_currentIndexChanged(const QString &arg1);
void on_defaultOutboundCombo_currentIndexChanged(const QString &arg1);
void on_defaultOutboundCombo_currentIndexChanged(const QString &arg1);
void on_ruleRenameBtn_clicked();
void on_ruleRenameBtn_clicked();
public slots:
void onNodeClicked(QtNodes::Node &n);
void onConnectionCreated(QtNodes::Connection const &c);
void onConnectionDeleted(QtNodes::Connection const &c);
public slots:
void onNodeClicked(QtNodes::Node &n);
void onConnectionCreated(QtNodes::Connection const &c);
void onConnectionDeleted(QtNodes::Connection const &c);
private:
void RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, const QString newTag);
void ShowCurrentRuleDetail();
//
QString currentRuleTag;
QString currentInboundOutboundTag;
QMap<QString, QStringList> balancers;
QString domainStrategy;
QString defaultOutbound;
//
QMap<QString, INBOUND> inbounds;
QMap<QString, OUTBOUND> outbounds;
QMap<QString, RuleObject> rules;
//
CONFIGROOT root;
CONFIGROOT original;
//
// ---------------------------- Node Graph Impl --------------------------
void SetupNodeWidget();
QMap<QString, Node *> inboundNodes;
QMap<QString, Node *> outboundNodes;
QMap<QString, Node *> ruleNodes;
//
FlowScene *nodeScene;
// ---------------------------- Extra Source File Headers ----------------
void AddInbound(INBOUND in);
void AddOutbound(OUTBOUND out);
void AddRule(RuleObject rule);
QString AddNewRule();
void ResolveDefaultOutboundTag(QString original, QString newTag);
private:
void RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, const QString newTag);
void ShowCurrentRuleDetail();
//
QString currentRuleTag;
QString currentInboundOutboundTag;
QMap<QString, QStringList> balancers;
QString domainStrategy;
QString defaultOutbound;
//
QMap<QString, INBOUND> inbounds;
QMap<QString, OUTBOUND> outbounds;
QMap<QString, RuleObject> rules;
//
CONFIGROOT root;
CONFIGROOT original;
//
// ---------------------------- Node Graph Impl --------------------------
void SetupNodeWidget();
QMap<QString, Node *> inboundNodes;
QMap<QString, Node *> outboundNodes;
QMap<QString, Node *> ruleNodes;
//
FlowScene *nodeScene;
// ---------------------------- Extra Source File Headers ----------------
void AddInbound(INBOUND in);
void AddOutbound(OUTBOUND out);
void AddRule(RuleObject rule);
QString AddNewRule();
void ResolveDefaultOutboundTag(QString original, QString newTag);
};

View File

@ -1,18 +1,16 @@
// WARNING
// Since it's required for this file to know the content of the macros defined in another CPP file.
// We included an CPP file instead of the proper HPP file.
// Since it's required for this file to know the content of the macros defined
// in another CPP file. We included an CPP file instead of the proper HPP file.
#include "w_RoutesEditor.cpp"
// Supplementary source file for Routes editor, basically providing routes-related operations.
// Supplementary source file for Routes editor, basically providing
// routes-related operations.
void RouteEditor::AddInbound(INBOUND in)
{
QString tag = getTag(in);
if (inbounds.contains(tag)) {
tag = tag + "_" + GenerateRandomString(5);
}
if (inbounds.contains(tag)) { tag = tag + "_" + GenerateRandomString(5); }
in["tag"] = tag;
auto _nodeData = make_unique<QvInboundNodeModel>(make_shared<InboundNodeData>(tag));
@ -29,9 +27,7 @@ void RouteEditor::AddOutbound(OUTBOUND out)
{
QString tag = getTag(out);
if (outbounds.contains(tag)) {
tag = tag + "_" + GenerateRandomString(5);
}
if (outbounds.contains(tag)) { tag = tag + "_" + GenerateRandomString(5); }
out["tag"] = tag;
auto _nodeData = make_unique<QvOutboundNodeModel>(make_shared<OutboundNodeData>(tag));
@ -64,9 +60,7 @@ QString RouteEditor::AddNewRule()
void RouteEditor::AddRule(RuleObject rule)
{
// Prevent duplicate
if (ruleNodes.contains(rule.QV2RAY_RULE_TAG)) {
rule.QV2RAY_RULE_TAG += "-" + GenerateRandomString(5);
}
if (ruleNodes.contains(rule.QV2RAY_RULE_TAG)) { rule.QV2RAY_RULE_TAG += "-" + GenerateRandomString(5); }
rules[rule.QV2RAY_RULE_TAG] = rule;
auto pos = nodeGraphWidget->pos();
@ -76,25 +70,34 @@ void RouteEditor::AddRule(RuleObject rule)
auto &node = nodeScene->createNode(std::move(_nodeData));
nodeScene->setNodePosition(node, pos);
for (auto inTag : rule.inboundTag) {
if (!inboundNodes.contains(inTag)) {
for (auto inTag : rule.inboundTag)
{
if (!inboundNodes.contains(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 {
}
else
{
auto inboundNode = inboundNodes[inTag];
nodeScene->createConnection(node, 0, *inboundNode, 0);
}
}
// If not using balancers (use outbound tag)
if (!rule.QV2RAY_RULE_USE_BALANCER) {
if (outboundNodes.contains(rule.outboundTag)) {
if (!rule.QV2RAY_RULE_USE_BALANCER)
{
if (outboundNodes.contains(rule.outboundTag))
{
DEBUG(MODULE_GRAPH, "Found outbound tag: " + rule.outboundTag + ", for rule: " + rule.QV2RAY_RULE_TAG)
nodeScene->createConnection(*outboundNodes[rule.outboundTag], 0, node, 0);
} else {
}
else
{
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."));
// QvMessageBoxWarn(this, tr("No outbound tag"), tr("Please connect
// the rule with an outbound."));
}
}
@ -105,19 +108,20 @@ void RouteEditor::AddRule(RuleObject rule)
// Do not use reference here, we need deep
void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, QString newTag)
{
switch (mode) {
switch (mode)
{
case RENAME_RULE:
if (rules.contains(originalTag) && ruleNodes.contains(originalTag)) {
if (rules.contains(newTag) && rules.contains(newTag)) {
if (rules.contains(originalTag) && ruleNodes.contains(originalTag))
{
if (rules.contains(newTag) && rules.contains(newTag))
{
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
newTag += "_" + GenerateRandomString(5);
}
auto node = static_cast<QvRuleNodeDataModel *>(ruleNodes[originalTag]->nodeDataModel());
if (node == nullptr) {
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
if (node == nullptr) { LOG(MODULE_GRAPH, "EMPTY NODE WARN") }
node->setData(newTag);
//
@ -125,27 +129,30 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
rules[newTag].QV2RAY_RULE_TAG = newTag;
ruleNodes[newTag] = ruleNodes.take(originalTag);
//
// No other operation needed, but need to rename the one in the ruleOrder list widget.
// No other operation needed, but need to rename the one in the
// ruleOrder list widget.
auto items = ruleListWidget->findItems(originalTag, Qt::MatchExactly);
if (items.isEmpty()) {
LOG(MODULE_UI, "Cannot find a node: " + originalTag)
} else {
if (items.isEmpty()) { LOG(MODULE_UI, "Cannot find a node: " + originalTag) }
else
{
items.first()->setText(newTag);
}
if (currentRuleTag == originalTag) {
currentRuleTag = newTag;
}
} else {
if (currentRuleTag == originalTag) { currentRuleTag = newTag; }
}
else
{
LOG(MODULE_UI, "There's nothing match " + originalTag + " in the containers.")
}
break;
case RENAME_OUTBOUND:
if (outbounds.contains(originalTag) && outboundNodes.contains(originalTag)) {
if (outbounds.contains(newTag) && outboundNodes.contains(newTag)) {
if (outbounds.contains(originalTag) && outboundNodes.contains(originalTag))
{
if (outbounds.contains(newTag) && outboundNodes.contains(newTag))
{
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
newTag += "_" + GenerateRandomString(5);
}
@ -154,34 +161,39 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
outboundNodes[newTag] = outboundNodes.take(originalTag);
auto node = static_cast<QvOutboundNodeModel *>(outboundNodes[newTag]->nodeDataModel());
if (node == nullptr) {
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
if (node == nullptr) { LOG(MODULE_GRAPH, "EMPTY NODE WARN") }
node->setData(newTag);
// Change outbound tag in rules accordingly.
for (auto k : rules.keys()) {
for (auto k : rules.keys())
{
auto v = rules[k];
if (v.outboundTag == originalTag) {
if (v.outboundTag == originalTag)
{
v.outboundTag = newTag;
// Put this inside the if block since no need an extra operation if the condition is false.
// Put this inside the if block since no need an extra
// operation if the condition is false.
rules[k] = v;
}
}
// Resolve default outbound.
ResolveDefaultOutboundTag(originalTag, newTag);
} else {
}
else
{
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
}
break;
case RENAME_INBOUND:
if (inbounds.contains(originalTag) && inboundNodes.contains(originalTag)) {
if (inbounds.contains(newTag) && inboundNodes.contains(newTag)) {
if (inbounds.contains(originalTag) && inboundNodes.contains(originalTag))
{
if (inbounds.contains(newTag) && inboundNodes.contains(newTag))
{
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
newTag += "_" + GenerateRandomString(5);
}
@ -190,26 +202,29 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
inboundNodes[newTag] = inboundNodes.take(originalTag);
auto node = static_cast<QvInboundNodeModel *>(inboundNodes[newTag]->nodeDataModel());
if (node == nullptr) {
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
if (node == nullptr) { LOG(MODULE_GRAPH, "EMPTY NODE WARN") }
node->setData(newTag);
// Change inbound tag in rules accordingly.
// k -> rule tag
// v -> rule object
for (auto k : rules.keys()) {
for (auto k : rules.keys())
{
auto v = rules[k];
if (v.inboundTag.contains(originalTag)) {
if (v.inboundTag.contains(originalTag))
{
v.inboundTag.append(newTag);
v.inboundTag.removeAll(originalTag);
// Put this inside the if block since no need an extra operation if the condition is false.
// Put this inside the if block since no need an extra
// operation if the condition is false.
rules[k] = v;
}
}
} else {
}
else
{
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
}
@ -219,26 +234,31 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
void RouteEditor::ResolveDefaultOutboundTag(QString original, QString newTag)
{
LOG(MODULE_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) {
if (!isDefaultChanged)
{
LOG(MODULE_UI, "Default outbound is not changed: retaining: " + defaultOutbound)
// Just simply restore the default one.
defaultOutboundCombo->setCurrentText(defaultOutbound);
} else if (newTag.isEmpty()) {
}
else if (newTag.isEmpty())
{
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()) {
defaultOutbound.clear();
} else {
if (outbounds.isEmpty()) { defaultOutbound.clear(); }
else
{
defaultOutbound = getTag(outbounds.first());
defaultOutboundCombo->addItem(outbounds.firstKey());
}
} else {
}
else
{
LOG(MODULE_UI, "Default outbound is renamed, ")
defaultOutboundCombo->setCurrentText(newTag);
defaultOutbound = newTag;

View File

@ -1,8 +1,9 @@
#include <QMetaEnum>
#include "QvMessageBus.hpp"
#include "base/Qv2rayBase.hpp"
#include <QMetaEnum>
namespace Qv2ray::ui::messaging
{
QvMessageBusObject::QvMessageBusObject()
@ -15,4 +16,4 @@ namespace Qv2ray::ui::messaging
LOG(MODULE_MESSAGING, "Emitting signal: " + QString(metaEnum.valueToKey(msg)));
emit QvSendMessage(msg);
}
}
} // namespace Qv2ray::ui::messaging

View File

@ -6,28 +6,27 @@
#define QvMessageBusSlotSig const QvMBMessage &msg
#define QvMessageBusSlotIdentifier on_QvMessageReceived
#define QvMessageBusSlotDecl void QvMessageBusSlotIdentifier(QvMessageBusSlotSig);
#define QvMessageBusSlotDecl void QvMessageBusSlotIdentifier(QvMessageBusSlotSig)
#define QvMessageBusSlotImpl(CLASSNAME) void CLASSNAME::QvMessageBusSlotIdentifier(QvMessageBusSlotSig)
#define MBShowDefaultImpl \
case SHOW_WINDOWS:\
this->setWindowOpacity(1);\
break;
#define MBShowDefaultImpl \
case SHOW_WINDOWS: \
this->setWindowOpacity(1); \
break;
#define MBHideDefaultImpl \
case HIDE_WINDOWS:\
this->setWindowOpacity(0);\
break;
#define MBHideDefaultImpl \
case HIDE_WINDOWS: \
this->setWindowOpacity(0); \
break;
#define MBRetranslateDefaultImpl \
case RETRANSLATE:\
this->retranslateUi(this);\
break;
#define MBRetranslateDefaultImpl \
case RETRANSLATE: this->retranslateUi(this); break;
namespace Qv2ray::ui::messaging
{
Q_NAMESPACE
enum QvMBMessage {
enum QvMBMessage
{
/// Show all windows.
SHOW_WINDOWS,
/// Hide all windows.
@ -43,20 +42,20 @@ namespace Qv2ray::ui::messaging
//
class QvMessageBusObject : public QObject
{
Q_OBJECT
public:
explicit QvMessageBusObject();
Q_OBJECT
public:
explicit QvMessageBusObject();
//
void EmitGlobalSignal(const QvMBMessage &msg);
signals:
void QvSendMessage(const QvMBMessage &msg);
//private slots:
// void on_QvMessageReceived(QvMessage msg);
//
void EmitGlobalSignal(const QvMBMessage &msg);
signals:
void QvSendMessage(const QvMBMessage &msg);
// private slots:
// void on_QvMessageReceived(QvMessage msg);
};
// Danger, new is used here. Possible memory leak (hope not so much leak)
inline QvMessageBusObject messageBus = QvMessageBusObject();
}
} // namespace Qv2ray::ui::messaging
using namespace Qv2ray::ui::messaging;

View File

@ -1,6 +1,6 @@
#include "ui/models/InboundNodeModel.hpp"
QvInboundNodeModel::QvInboundNodeModel(std::shared_ptr<InboundNodeData> data): NodeDataModel()
QvInboundNodeModel::QvInboundNodeModel(std::shared_ptr<InboundNodeData> data) : NodeDataModel()
{
_in = data;
_label = new QLabel();

View File

@ -1,68 +1,72 @@
#pragma once
#include <QtCore/qglobal.h>
#include "ui/models/NodeModelsBase.hpp"
#include <QtCore/qglobal.h>
class QvInboundNodeModel : public NodeDataModel
{
Q_OBJECT
public:
explicit QvInboundNodeModel(std::shared_ptr<InboundNodeData> data);
~QvInboundNodeModel()
{
//if (_label) {
// delete _label;
//}
}
Q_OBJECT
public:
explicit QvInboundNodeModel(std::shared_ptr<InboundNodeData> data);
~QvInboundNodeModel()
{
// if (_label) {
// delete _label;
//}
}
QString caption() const override
{
return "Nothing";
}
QString caption() const override
{
return "Nothing";
}
bool captionVisible() const override
{
return false;
}
bool captionVisible() const override
{
return false;
}
unsigned int nPorts(PortType portType) const override
{
return portType == PortType::Out ? 1 : 0;
}
unsigned int nPorts(PortType portType) const override
{
return portType == PortType::Out ? 1 : 0;
}
QString name() const override
{
return "InboundNode";
}
QString name() const override
{
return "InboundNode";
}
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
{
Q_UNUSED(portType);
Q_UNUSED(portIndex);
return inboundType;
}
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
{
Q_UNUSED(portType);
Q_UNUSED(portIndex);
return inboundType;
}
std::shared_ptr<NodeData> outData(PortIndex) override
{
return _in;
}
std::shared_ptr<NodeData> outData(PortIndex) override
{
return _in;
}
void setInData(std::shared_ptr<NodeData>, int) override {}
void setData(const QString &data)
{
_in = make_shared<InboundNodeData>(data);
_label->setText(data);
_label->adjustSize();
}
void setInData(std::shared_ptr<NodeData>, int) override
{
}
void setData(const QString &data)
{
_in = make_shared<InboundNodeData>(data);
_label->setText(data);
_label->adjustSize();
}
QWidget *embeddedWidget() override
{
return _label;
}
private:
NodeValidationState modelValidationState = NodeValidationState::Warning;
QString modelValidationError = tr("Missing or incorrect inputs");
//
std::shared_ptr<InboundNodeData> _in;
QLabel *_label;
QWidget *embeddedWidget() override
{
return _label;
}
private:
NodeValidationState modelValidationState = NodeValidationState::Warning;
QString modelValidationError = tr("Missing or incorrect inputs");
//
std::shared_ptr<InboundNodeData> _in;
QLabel *_label;
};

View File

@ -1,101 +1,99 @@
#pragma once
#include <QLabel>
#include "NodeDataModel.hpp"
#include "PortType.hpp"
#include "common/QvHelpers.hpp"
using QtNodes::PortType;
using QtNodes::PortIndex;
#include <QLabel>
using QtNodes::NodeData;
using QtNodes::NodeDataType;
using QtNodes::NodeDataModel;
using QtNodes::NodeValidationState;
using QtNodes::NodeDataType;
using QtNodes::NodeValidationState;
using QtNodes::PortIndex;
using QtNodes::PortType;
using QtNodes::NodeData;
using QtNodes::NodeDataType;
const int GRAPH_NODE_LABEL_FONTSIZE_INCREMENT = 3;
namespace Qv2ray::ui::nodemodels
{
const NodeDataType outboundType = {"outbound", "Outbound Object"};
const NodeDataType inboundType = {"inbound", "Inbound Object"};
const NodeDataType outboundType = { "outbound", "Outbound Object" };
const NodeDataType inboundType = { "inbound", "Inbound Object" };
/// The class can potentially incapsulate any user data
/// need to be transferred within the Node Editor graph
class InboundNodeData : public NodeData
{
public:
InboundNodeData()
{
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
}
InboundNodeData(QString in) : _inboundTag(in) { }
public:
InboundNodeData(){ DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.") } InboundNodeData(QString in)
: _inboundTag(in)
{
}
NodeDataType type() const override
{
return inboundType;
}
NodeDataType type() const override
{
return inboundType;
}
QString GetInbound()
{
return _inboundTag;
}
private:
QString _inboundTag;
QString GetInbound()
{
return _inboundTag;
}
private:
QString _inboundTag;
};
/// The class can potentially incapsulate any user data
/// need to be transferred within the Node Editor graph
class OutboundNodeData : public NodeData
{
public:
OutboundNodeData() : _outboundTag()
{
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
}
OutboundNodeData(QString out) : _outboundTag(out) { }
public:
OutboundNodeData()
: _outboundTag(){ DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.") } OutboundNodeData(QString out)
: _outboundTag(out)
{
}
NodeDataType type() const override
{
return outboundType;
}
NodeDataType type() const override
{
return outboundType;
}
QString GetOutbound()
{
return _outboundTag;
}
private:
QString _outboundTag;
QString GetOutbound()
{
return _outboundTag;
}
private:
QString _outboundTag;
};
/// The class can potentially incapsulate any user data
/// need to be transferred within the Node Editor graph
class RuleNodeData : public NodeData
{
public:
RuleNodeData() : _ruleTag()
{
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
}
RuleNodeData(QString out) : _ruleTag(out) { }
public:
RuleNodeData()
: _ruleTag(){ DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.") } RuleNodeData(QString out) : _ruleTag(out)
{
}
NodeDataType type() const override
{
return outboundType;
}
NodeDataType type() const override
{
return outboundType;
}
QString GetRuleTag()
{
return _ruleTag;
}
private:
QString _ruleTag;
QString GetRuleTag()
{
return _ruleTag;
}
private:
QString _ruleTag;
};
}
} // namespace Qv2ray::ui::nodemodels
using namespace Qv2ray::ui::nodemodels;

View File

@ -1,6 +1,6 @@
#include "ui/models/OutboundNodeModel.hpp"
QvOutboundNodeModel::QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data): NodeDataModel()
QvOutboundNodeModel::QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data) : NodeDataModel()
{
_out = data;
_label = new QLabel();

View File

@ -1,74 +1,80 @@
#pragma once
#include <QtCore/qglobal.h>
#include "ui/models/NodeModelsBase.hpp"
#include <QtCore/qglobal.h>
class QvOutboundNodeModel : public NodeDataModel
{
Q_OBJECT
public:
explicit QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data);
~QvOutboundNodeModel()
{
//if (_label) {
// delete _label;
//}
}
Q_OBJECT
public:
explicit QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data);
~QvOutboundNodeModel()
{
// if (_label) {
// delete _label;
//}
}
QString caption() const override
{
return "Nothing";
}
QString caption() const override
{
return "Nothing";
}
bool captionVisible() const override
{
return false;
}
bool captionVisible() const override
{
return false;
}
unsigned int nPorts(PortType portType) const override
{
return portType == PortType::In ? 1 : 0;
}
unsigned int nPorts(PortType portType) const override
{
return portType == PortType::In ? 1 : 0;
}
QString name() const override
{
return "OutboundNode";
}
QString name() const override
{
return "OutboundNode";
}
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
{
Q_UNUSED(portType);
Q_UNUSED(portIndex);
return outboundType;
}
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
{
Q_UNUSED(portType);
Q_UNUSED(portIndex);
return outboundType;
}
std::shared_ptr<NodeData> outData(PortIndex) override
{
return _out;
}
std::shared_ptr<NodeData> outData(PortIndex) override
{
return _out;
}
void setInData(shared_ptr<NodeData>, int) override {}
void setInData(shared_ptr<NodeData>, int) override
{
}
void setInData(vector<shared_ptr<NodeData>>, int) override {}
void setData(const QString &data)
{
_out = make_shared<OutboundNodeData>(data);
_label->setText(_out->GetOutbound());
_label->adjustSize();
}
void setInData(vector<shared_ptr<NodeData>>, int) override
{
}
void setData(const QString &data)
{
_out = make_shared<OutboundNodeData>(data);
_label->setText(_out->GetOutbound());
_label->adjustSize();
}
QWidget *embeddedWidget() override
{
return _label;
}
QWidget *embeddedWidget() override
{
return _label;
}
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
{
return ConnectionPolicy::Many;
}
private:
NodeValidationState modelValidationState = NodeValidationState::Warning;
QString modelValidationError = tr("Missing or incorrect inputs");
//
std::shared_ptr<OutboundNodeData> _out;
QLabel *_label;
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
{
return ConnectionPolicy::Many;
}
private:
NodeValidationState modelValidationState = NodeValidationState::Warning;
QString modelValidationError = tr("Missing or incorrect inputs");
//
std::shared_ptr<OutboundNodeData> _out;
QLabel *_label;
};

View File

@ -1,6 +1,6 @@
#include "ui/models/RuleNodeModel.hpp"
QvRuleNodeDataModel::QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data): NodeDataModel()
QvRuleNodeDataModel::QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data) : NodeDataModel()
{
_ruleTag = data;
_label = new QLabel();

View File

@ -1,98 +1,103 @@
#pragma once
#include <QtCore/qglobal.h>
#include "ui/models/NodeModelsBase.hpp"
#include <QtCore/qglobal.h>
class QvRuleNodeDataModel : public NodeDataModel
{
Q_OBJECT
public:
QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data);
~QvRuleNodeDataModel()
Q_OBJECT
public:
QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data);
~QvRuleNodeDataModel()
{
// if (_label) {
// delete _label;
//}
}
QString caption() const override
{
return "Nothing";
}
bool captionVisible() const override
{
return false;
}
unsigned int nPorts(PortType portType) const override
{
if (portType == PortType::In) { return 1; }
else if (portType == PortType::Out)
{
//if (_label) {
// delete _label;
//}
return 1;
}
else
{
return 0;
}
}
QString name() const override
{
return "RuleNode";
}
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
{
Q_UNUSED(portIndex)
switch (portType)
{
case PortType::In: return inboundType;
case PortType::Out: return outboundType;
case PortType::None: break;
}
QString caption() const override
{
return "Nothing";
}
return NodeDataType();
}
bool captionVisible() const override
{
return false;
}
std::shared_ptr<NodeData> outData(PortIndex port) override
{
Q_UNUSED(port)
return _ruleTag;
}
unsigned int nPorts(PortType portType) const override
{
if (portType == PortType::In) {
return 1;
} else if (portType == PortType::Out) {
return 1;
} else {
return 0;
}
}
void setInData(std::shared_ptr<NodeData>, int) override
{
}
void setInData(vector<shared_ptr<NodeData>>, int) override
{
}
void setData(const QString &data)
{
_ruleTag = make_shared<RuleNodeData>(data);
_label->setText(_ruleTag->GetRuleTag());
_label->adjustSize();
}
QString name() const override
{
return "RuleNode";
}
QWidget *embeddedWidget() override
{
return _label;
}
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
{
Q_UNUSED(portIndex)
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
{
return ConnectionPolicy::Many;
}
switch (portType) {
case PortType::In:
return inboundType;
ConnectionPolicy portOutConnectionPolicy(PortIndex) const override
{
return ConnectionPolicy::One;
}
case PortType::Out:
return outboundType;
case PortType::None:
break;
}
return NodeDataType();
}
std::shared_ptr<NodeData> outData(PortIndex port) override
{
Q_UNUSED(port)
return _ruleTag;
}
void setInData(std::shared_ptr<NodeData>, int) override {}
void setInData(vector<shared_ptr<NodeData>>, int) override {}
void setData(const QString &data)
{
_ruleTag = make_shared<RuleNodeData>(data);
_label->setText(_ruleTag->GetRuleTag());
_label->adjustSize();
}
QWidget *embeddedWidget() override
{
return _label;
}
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
{
return ConnectionPolicy::Many;
}
ConnectionPolicy portOutConnectionPolicy(PortIndex) const override
{
return ConnectionPolicy::One;
}
private:
NodeValidationState modelValidationState = NodeValidationState::Warning;
QString modelValidationError = tr("Missing or incorrect inputs");
//
shared_ptr<RuleNodeData> _ruleTag;
QLabel *_label;
private:
NodeValidationState modelValidationState = NodeValidationState::Warning;
QString modelValidationError = tr("Missing or incorrect inputs");
//
shared_ptr<RuleNodeData> _ruleTag;
QLabel *_label;
};

View File

@ -1,12 +1,11 @@
#include "w_ExportConfig.hpp"
#include "common/QvHelpers.hpp"
#include "core/connection/Serialization.hpp"
#include <QFileDialog>
// Private initialiser
ConfigExporter::ConfigExporter(QWidget *parent) :
QDialog(parent),
qzxing(this)
ConfigExporter::ConfigExporter(QWidget *parent) : QDialog(parent), qzxing(this)
{
setupUi(this);
QvMessageBusConnect(ConfigExporter);
@ -14,10 +13,9 @@ ConfigExporter::ConfigExporter(QWidget *parent) :
QvMessageBusSlotImpl(ConfigExporter)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -25,7 +23,7 @@ ConfigExporter::~ConfigExporter()
{
}
//ConfigExporter::ConfigExporter(QWidget *parent) : ConfigExporter(parent)
// ConfigExporter::ConfigExporter(QWidget *parent) : ConfigExporter(parent)
//{
// // WIP
// // /auto &x = connection;
@ -49,17 +47,13 @@ void ConfigExporter::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
retranslateUi(this);
break;
switch (e->type())
{
case QEvent::LanguageChange: retranslateUi(this); break;
case QEvent::Resize:
imageLabel->setPixmap(QPixmap::fromImage(image));
break;
case QEvent::Resize: imageLabel->setPixmap(QPixmap::fromImage(image)); break;
default:
break;
default: break;
}
}

View File

@ -1,32 +1,36 @@
#pragma once
#include "ui_w_ExportConfig.h"
#include "base/Qv2rayBase.hpp"
#include "3rdparty/qzxing/src/QZXing.h"
#include "base/Qv2rayBase.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_ExportConfig.h"
class ConfigExporter : public QDialog, private Ui::ExportConfigWindow
class ConfigExporter
: public QDialog
, private Ui::ExportConfigWindow
{
Q_OBJECT
Q_OBJECT
public:
explicit ConfigExporter(QWidget *parent = nullptr);
~ConfigExporter();
void OpenExport();
public slots:
QvMessageBusSlotDecl
protected:
void changeEvent(QEvent *e);
private slots:
void on_closeBtn_clicked();
public:
explicit ConfigExporter(QWidget *parent = nullptr);
~ConfigExporter();
void OpenExport();
public slots:
QvMessageBusSlotDecl;
void on_saveBtn_clicked();
protected:
void changeEvent(QEvent *e);
private slots:
void on_closeBtn_clicked();
void on_copyImageBtn_clicked();
void on_saveBtn_clicked();
void on_copyVMessBtn_clicked();
private:
QZXing qzxing;
QImage image;
QString message;
void on_copyImageBtn_clicked();
void on_copyVMessBtn_clicked();
private:
QZXing qzxing;
QImage image;
QString message;
};

View File

@ -1,26 +1,25 @@
#include <QDebug>
#include "w_ImportConfig.hpp"
#include "3rdparty/qzxing/src/QZXing.h"
#include "core/CoreUtils.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/connection/Serialization.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include "ui/editors/w_JsonEditor.hpp"
#include "ui/editors/w_OutboundEditor.hpp"
#include "ui/editors/w_RoutesEditor.hpp"
#include "ui/w_SubscriptionManager.hpp"
#include "w_ScreenShot_Core.hpp"
#include <QFile>
#include <QFileDialog>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QThread>
#include "3rdparty/qzxing/src/QZXing.h"
#include "core/CoreUtils.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/connection/Serialization.hpp"
#include "w_ScreenShot_Core.hpp"
#include "ui/editors/w_OutboundEditor.hpp"
#include "ui/editors/w_JsonEditor.hpp"
#include "w_ImportConfig.hpp"
#include "ui/w_SubscriptionManager.hpp"
#include "ui/editors/w_RoutesEditor.hpp"
ImportConfigWindow::ImportConfigWindow(QWidget *parent)
: QDialog(parent)
ImportConfigWindow::ImportConfigWindow(QWidget *parent) : QDialog(parent)
{
setupUi(this);
nameTxt->setText(QDateTime::currentDateTime().toString("MMdd_hhmm"));
@ -30,10 +29,9 @@ ImportConfigWindow::ImportConfigWindow(QWidget *parent)
QvMessageBusSlotImpl(ImportConfigWindow)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -43,7 +41,8 @@ ImportConfigWindow::~ImportConfigWindow()
QMap<QString, CONFIGROOT> ImportConfigWindow::OpenImport(bool partialImport)
{
// partial import means only import as an outbound, will set keepImported to false and disable the checkbox
// partial import means only import as an outbound, will set keepImported to
// false and disable the checkbox
// keepImportedInboundCheckBox->setChecked(!outboundsOnly);
keepImportedInboundCheckBox->setEnabled(!partialImport);
routeEditBtn->setEnabled(!partialImport);
@ -61,9 +60,7 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
{
bool hideQv2ray = hideQv2rayCB->isChecked();
if (hideQv2ray) {
messageBus.EmitGlobalSignal(QvMBMessage::HIDE_WINDOWS);
}
if (hideQv2ray) { messageBus.EmitGlobalSignal(QvMBMessage::HIDE_WINDOWS); }
QApplication::processEvents();
QThread::msleep(static_cast<ulong>(doubleSpinBox->value() * 1000));
@ -72,24 +69,29 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
auto _r = w.result();
// Explicitly delete w to call UNREGISTER_WINDOW
if (hideQv2ray) {
if (hideQv2ray)
{
messageBus.EmitGlobalSignal(QvMBMessage::SHOW_WINDOWS);
//ShowAllGlobalWindow();
// ShowAllGlobalWindow();
}
if (_r == QDialog::Accepted) {
if (_r == QDialog::Accepted)
{
QZXing decoder;
decoder.setDecoder(QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13);
auto str = decoder.decodeImage(pix);
//auto str = QZXing().decodeImage(pix);
// auto str = QZXing().decodeImage(pix);
if (str.trimmed().isEmpty()) {
if (str.trimmed().isEmpty())
{
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 {
}
else
{
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
//QvMessageBoxWarn(this, tr("Capture QRCode"), tr("Successfully imported a QR code form the screen."));
//this->show();
// QvMessageBoxWarn(this, tr("Capture QRCode"), tr("Successfully
// imported a QR code form the screen.")); this->show();
}
}
}
@ -97,26 +99,30 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
void ImportConfigWindow::on_beginImportBtn_clicked()
{
QString aliasPrefix = nameTxt->text();
//auto conf = GetGlobalConfig();
// auto conf = GetGlobalConfig();
switch (tabWidget->currentIndex()) {
case 0: {
switch (tabWidget->currentIndex())
{
case 0:
{
//// From File...
//bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
//QString path = fileLineTxt->text();
// 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;
// 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;
// aliasPrefix += "_" + QFileInfo(path).fileName();
////CONFIGROOT config = ConvertConfigFromFile(path,
/// ImportAsComplex);
// connections[aliasPrefix] = config;
// break;
}
case 1: {
case 1:
{
QStringList linkList = SplitLines(vmessConnectionStringTxt->toPlainText());
//
// Clear UI and error lists
@ -126,24 +132,30 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
//
LOG(MODULE_IMPORT, QSTRN(linkList.count()) + " string found in vmess box.")
while (!linkList.isEmpty()) {
while (!linkList.isEmpty())
{
aliasPrefix = nameTxt->text();
auto link = linkList.takeFirst();
QString errMessage;
CONFIGROOT config = ConvertConfigFromString(link, &aliasPrefix, &errMessage);
// If the config is empty or we have any err messages.
if (config.isEmpty() || !errMessage.isEmpty()) {
if (config.isEmpty() || !errMessage.isEmpty())
{
// To prevent duplicated values.
linkErrors[link] = QSTRN(linkErrors.count() + 1) + ": " + errMessage;
continue;
} else {
}
else
{
connections[aliasPrefix] = config;
}
}
if (!linkErrors.isEmpty()) {
for (auto item : linkErrors) {
if (!linkErrors.isEmpty())
{
for (auto item : linkErrors)
{
vmessConnectionStringTxt->appendPlainText(linkErrors.key(item));
errorsList->addItem(item);
}
@ -173,10 +185,13 @@ void ImportConfigWindow::on_selectImageBtn_clicked()
decoder.setDecoder(QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13);
auto str = decoder.decodeImage(QImage::fromData(buf));
if (str.isEmpty()) {
if (str.isEmpty())
{
QvMessageBoxWarn(this, tr("QRCode scanning failed"), tr("Cannot find any QRCode from the image."));
return;
} else {
}
else
{
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
}
}
@ -184,9 +199,7 @@ void ImportConfigWindow::on_errorsList_currentItemChanged(QListWidgetItem *curre
{
Q_UNUSED(previous)
if (current == nullptr) {
return;
}
if (current == nullptr) { return; }
auto currentErrorText = current->text();
auto vmessEntry = linkErrors.key(currentErrorText);
@ -194,9 +207,7 @@ void ImportConfigWindow::on_errorsList_currentItemChanged(QListWidgetItem *curre
auto startPos = vmessConnectionStringTxt->toPlainText().indexOf(vmessEntry);
auto endPos = startPos + vmessEntry.length();
if (startPos < 0) {
return;
}
if (startPos < 0) { return; }
// Select vmess string that is invalid.
QTextCursor c = vmessConnectionStringTxt->textCursor();
@ -208,36 +219,43 @@ void ImportConfigWindow::on_editFileBtn_clicked()
{
QFile file(fileLineTxt->text());
if (!file.exists()) {
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Provided file not found: ") + fileLineTxt->text());
if (!file.exists())
{
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Provided file not found: ") + fileLineTxt->text());
return;
}
auto jsonString = StringFromFile(&file);
auto jsonCheckingError = VerifyJsonString(jsonString);
if (!jsonCheckingError.isEmpty()) {
if (!jsonCheckingError.isEmpty())
{
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 {
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(MODULE_FILEIO, "Continue editing curruped json file, data loss is expected.")
}
}
auto json = JsonFromString(jsonString);
auto json = JsonFromString(jsonString);
JsonEditor editor(json, this);
json = editor.OpenEditor();
if (editor.result() == QDialog::Accepted) {
if (editor.result() == QDialog::Accepted)
{
auto str = JsonToString(json);
bool result = StringToFile(str, file);
if (!result) {
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions"));
}
} else {
if (!result) { QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions")); }
}
else
{
LOG(MODULE_FILEIO, "Canceled saving a file.")
}
}
@ -249,7 +267,8 @@ void ImportConfigWindow::on_connectionEditBtn_clicked()
bool isChanged = w.result() == QDialog::Accepted;
QString alias = w.GetFriendlyName();
if (isChanged) {
if (isChanged)
{
OUTBOUNDS outboundsList;
outboundsList.push_back(outboundEntry);
CONFIGROOT root;
@ -257,7 +276,9 @@ void ImportConfigWindow::on_connectionEditBtn_clicked()
//
connections[alias] = root;
accept();
} else {
}
else
{
return;
}
}
@ -275,7 +296,8 @@ void ImportConfigWindow::on_subscriptionButton_clicked()
auto importToComplex = !keepImportedInboundCheckBox->isEnabled();
connections.clear();
if (importToComplex) {
if (importToComplex)
{
auto _result = w.GetSelectedConfig();
connections[_result.first] = _result.second;
}
@ -290,10 +312,13 @@ void ImportConfigWindow::on_routeEditBtn_clicked()
bool isChanged = w.result() == QDialog::Accepted;
QString alias = nameTxt->text();
if (isChanged) {
if (isChanged)
{
connections[alias] = result;
accept();
} else {
}
else
{
return;
}
}

View File

@ -1,44 +1,47 @@
#pragma once
#include <QDialog>
#include <QString>
#include <QJsonObject>
#include "base/Qv2rayBase.hpp"
#include "ui_w_ImportConfig.h"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_ImportConfig.h"
class ImportConfigWindow : public QDialog, private Ui::ImportConfigWindow
#include <QDialog>
#include <QJsonObject>
#include <QString>
class ImportConfigWindow
: public QDialog
, private Ui::ImportConfigWindow
{
Q_OBJECT
Q_OBJECT
public:
explicit ImportConfigWindow(QWidget *parent = nullptr);
~ImportConfigWindow();
QMap<QString, CONFIGROOT> OpenImport(bool outboundsOnly = false);
public slots:
QvMessageBusSlotDecl
private slots:
public:
explicit ImportConfigWindow(QWidget *parent = nullptr);
~ImportConfigWindow();
QMap<QString, CONFIGROOT> OpenImport(bool outboundsOnly = false);
public slots:
QvMessageBusSlotDecl;
private slots:
void on_selectFileBtn_clicked();
void on_selectFileBtn_clicked();
void on_qrFromScreenBtn_clicked();
void on_beginImportBtn_clicked();
void on_selectImageBtn_clicked();
void on_errorsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
void on_qrFromScreenBtn_clicked();
void on_beginImportBtn_clicked();
void on_selectImageBtn_clicked();
void on_errorsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
void on_editFileBtn_clicked();
void on_editFileBtn_clicked();
void on_connectionEditBtn_clicked();
void on_connectionEditBtn_clicked();
void on_cancelImportBtn_clicked();
void on_cancelImportBtn_clicked();
void on_subscriptionButton_clicked();
void on_subscriptionButton_clicked();
void on_routeEditBtn_clicked();
void on_routeEditBtn_clicked();
void on_hideQv2rayCB_stateChanged(int arg1);
void on_hideQv2rayCB_stateChanged(int arg1);
private:
QMap<QString, CONFIGROOT> connections;
QMap<QString, QString> linkErrors;
private:
QMap<QString, CONFIGROOT> connections;
QMap<QString, QString> linkErrors;
};

View File

@ -1,76 +1,86 @@
#pragma once
#include "w_MainWindow.hpp"
#include "ui/editors/w_JsonEditor.hpp"
#include "ui/editors/w_OutboundEditor.hpp"
#include "ui/editors/w_RoutesEditor.hpp"
#include "w_ExportConfig.hpp"
#include "w_ImportConfig.hpp"
#include "w_PreferencesWindow.hpp"
#include "w_SubscriptionManager.hpp"
#include "w_ExportConfig.hpp"
#include "ui/editors/w_OutboundEditor.hpp"
#include "ui/editors/w_RoutesEditor.hpp"
#include "ui/editors/w_JsonEditor.hpp"
//#include <QAction>
#include "components/pac/QvPACHandler.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "ui/widgets/ConnectionInfoWidget.hpp"
#include <QCloseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QFile>
#include <QFileInfo>
#include <QHeaderView>
#include <QInputDialog>
#include <QKeyEvent>
#include <QMenu>
#include <QStandardItemModel>
#include <QDesktopServices>
#include <QUrl>
#include <QVersionNumber>
#include <QKeyEvent>
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "components/pac/QvPACHandler.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "ui/widgets/ConnectionInfoWidget.hpp"
// MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related operations.
// MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related
// operations.
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
//
#define GetItemWidget(item) (qobject_cast<ConnectionItemWidget*>(connectionListWidget->itemWidget(item, 0)))
#define GetItemWidget(item) (qobject_cast<ConnectionItemWidget *>(connectionListWidget->itemWidget(item, 0)))
/*
#define ItemConnectionIdentifier(__item__) (__item__->data(0, Qt::UserRole).value<ConnectionIdentifier>())
#define ItemConnectionIdentifier(__item__) (__item__->data(0,
Qt::UserRole).value<ConnectionIdentifier>())
#define CheckConfigType(_item_, TYPE) (connections.contains(ItemConnectionIdentifier(_item_)) && connections[ItemConnectionIdentifier(_item_)].configType == CONNECTION_ ## TYPE)
#define CheckConfigType(_item_, TYPE)
(connections.contains(ItemConnectionIdentifier(_item_)) &&
connections[ItemConnectionIdentifier(_item_)].configType == CONNECTION_ ## TYPE)
#define SUBSCRIPTION_CONFIG_MODIFY_ASK(_item_) \
if (!CheckConfigType(_item_, REGULAR)) { \
if (QvMessageBoxAsk(this, QObject::tr("Editing a subscription config"), QObject::tr("You are trying to edit a config loaded from subscription.") + \
NEWLINE + QObject::tr("All changes will be overwritten when the subscriptions are updated next time.") + \
NEWLINE + QObject::tr("Are you still going to do so?")) != QMessageBox::Yes) { \
return; \
} \
} \
#define SUBSCRIPTION_CONFIG_MODIFY_ASK(_item_) \
if (!CheckConfigType(_item_, REGULAR)) { \
if (QvMessageBoxAsk(this, QObject::tr("Editing a subscription config"),
QObject::tr("You are trying to edit a config loaded from subscription.") + \
NEWLINE + QObject::tr("All changes will be
overwritten when the subscriptions are updated next time.") + \
NEWLINE + QObject::tr("Are you still going to do
so?")) != QMessageBox::Yes) { \
return; \
} \
} \
#define SUBSCRIPTION_CONFIG_MODIFY_DENY(_item_) \
if (!CheckConfigType(_item_, REGULAR)) { \
QvMessageBoxWarn(this, QObject::tr("Editing a subscription config"), QObject::tr("You should not modity this property of a config from a subscription")); \
return; \
} \
#define SUBSCRIPTION_CONFIG_MODIFY_DENY(_item_) \
if (!CheckConfigType(_item_, REGULAR)) { \
QvMessageBoxWarn(this, QObject::tr("Editing a subscription config"),
QObject::tr("You should not modity this property of a config from a
subscription")); \
return; \
} \
#define IsConnectableItem(item) (item != nullptr && item->childCount() == 0 && (CheckConfigType(item, REGULAR) || CheckConfigType(item, SUBSCRIPTION)))
#define IsSelectionConnectable (!connectionListWidget->selectedItems().empty() && IsConnectableItem(connectionListWidget->selectedItems().first()))
#define IsConnectableItem(item) (item != nullptr && item->childCount() == 0 &&
(CheckConfigType(item, REGULAR) || CheckConfigType(item, SUBSCRIPTION))) #define
IsSelectionConnectable (!connectionListWidget->selectedItems().empty() &&
IsConnectableItem(connectionListWidget->selectedItems().first()))
*/
MainWindow *MainWindow::mwInstance = nullptr;
QvMessageBusSlotImpl(MainWindow)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTray(this), tcpingHelper(3, this)
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) //, vinstance(), hTray(this), tcpingHelper(3, this)
{
setupUi(this);
MainWindow::mwInstance = this;
@ -86,8 +96,8 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
this->setWindowIcon(QIcon(":/assets/icons/qv2ray.png"));
hTray.setIcon(QIcon(GlobalConfig.uiConfig.useDarkTrayIcon ? ":/assets/icons/ui_dark/tray.png" : ":/assets/icons/ui_light/tray.png"));
importConfigButton->setIcon(QICON_R("import.png"));
//pingTestBtn->setIcon(QICON_R("ping_gauge.png"));
//shareBtn->setIcon(QICON_R("share.png"));
// pingTestBtn->setIcon(QICON_R("ping_gauge.png"));
// shareBtn->setIcon(QICON_R("share.png"));
updownImageBox->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
updownImageBox_2->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
//
@ -96,7 +106,7 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
this->show();
QvMessageBoxWarn(this, tr("V2ray vcore terminated."),
tr("V2ray vcore terminated unexpectedly.") + NEWLINE + NEWLINE +
tr("To solve the problem, read the V2ray log in the log text browser."));
tr("To solve the problem, read the V2ray log in the log text browser."));
});
connect(ConnectionManager, &QvConnectionHandler::OnConnected, this, &MainWindow::OnConnected);
connect(ConnectionManager, &QvConnectionHandler::OnDisConnected, this, &MainWindow::OnDisConnected);
@ -141,9 +151,11 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
//
connect(action_Tray_ShowHide, &QAction::triggered, this, &MainWindow::ToggleVisibility);
connect(action_Tray_ShowPreferencesWindow, &QAction::triggered, this, &MainWindow::on_preferencesBtn_clicked);
//connect(action_Tray_Start, &QAction::triggered, this, &MainWindow::on_startButton_clicked);
//connect(action_Tray_Stop, &QAction::triggered, this, &MainWindow::on_stopButton_clicked);
//connect(action_Tray_Reconnect, &QAction::triggered, this, &MainWindow::on_reconnectButton_clicked);
// connect(action_Tray_Start, &QAction::triggered, this,
// &MainWindow::on_startButton_clicked); connect(action_Tray_Stop,
// &QAction::triggered, this, &MainWindow::on_stopButton_clicked);
// connect(action_Tray_Reconnect, &QAction::triggered, this,
// &MainWindow::on_reconnectButton_clicked);
connect(action_Tray_Quit, &QAction::triggered, this, &MainWindow::on_actionExit_triggered);
connect(action_Tray_SetSystemProxy, &QAction::triggered, this, &MainWindow::MWSetSystemProxy);
connect(action_Tray_ClearSystemProxy, &QAction::triggered, this, &MainWindow::MWClearSystemProxy);
@ -166,9 +178,11 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
connect(action_RCM_ShareQR, &QAction::triggered, this, &MainWindow::on_action_RCM_ShareQR_triggered);
//
// Globally invokable signals.
//connect(this, &MainWindow::Connect, this, &MainWindow::on_startButton_clicked);
//connect(this, &MainWindow::DisConnect, this, &MainWindow::on_stopButton_clicked);
//connect(this, &MainWindow::ReConnect, this, &MainWindow::on_reconnectButton_clicked);
// connect(this, &MainWindow::Connect, this,
// &MainWindow::on_startButton_clicked); connect(this,
// &MainWindow::DisConnect, this, &MainWindow::on_stopButton_clicked);
// connect(this, &MainWindow::ReConnect, this,
// &MainWindow::on_reconnectButton_clicked);
//
hTray.setContextMenu(tray_RootMenu);
hTray.show();
@ -183,13 +197,15 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
LOG(MODULE_UI, "Loading data...")
auto groups = ConnectionManager->AllGroups();
for (auto group : groups) {
for (auto group : groups)
{
auto groupItem = new QTreeWidgetItem(QStringList() << "" << ConnectionManager->GetDisplayName(group));
connectionListWidget->addTopLevelItem(groupItem);
connectionListWidget->setItemWidget(groupItem, 0, new ConnectionItemWidget(group, connectionListWidget));
auto connections = ConnectionManager->Connections(group);
for (auto connection : connections) {
for (auto connection : connections)
{
auto connectionItem = new QTreeWidgetItem(QStringList() << "" << ConnectionManager->GetDisplayName(connection));
groupItem->addChild(connectionItem);
auto widget = new ConnectionItemWidget(connection, connectionListWidget);
@ -202,18 +218,16 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
// Find and start if there is an auto-connection
auto needShowWindow = true;
if (!GlobalConfig.autoStartId.isEmpty()) {
if (!GlobalConfig.autoStartId.isEmpty())
{
auto id = ConnectionId(GlobalConfig.autoStartId);
needShowWindow = ConnectionManager->StartConnection(id).has_value();
}
if (needShowWindow) {
this->show();
}
if (needShowWindow) { this->show(); }
//// If we are not connected to anything, show the MainWindow.
if (needShowWindow) {
}
if (needShowWindow) {}
#ifndef DISABLE_AUTO_UPDATE
requestHelper = new QvHttpRequestHelper();
@ -221,7 +235,8 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
requestHelper->get("https://api.github.com/repos/Qv2ray/Qv2ray/releases/latest");
#endif
if (StartupOption.enableToolbarPlguin) {
if (StartupOption.enableToolbarPlguin)
{
LOG(MODULE_UI, "Plugin daemon is enabled.")
StartProcessingPlugins();
}
@ -231,33 +246,35 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
splitter->setSizes(QList<int>() << 100 << 300);
}
void MainWindow::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
{
// If pressed enter or return on connectionListWidget.
// Try to connect to the selected connection.
//if (focusWidget() == connectionListWidget) {
// if (focusWidget() == connectionListWidget) {
// if (!IsSelectionConnectable) return;
//
// auto selections = connectionListWidget->selectedItems();
// QVariant v;
// auto vv = v.value<QvConnectionObject>();
// ShowAndSetConnection(ItemConnectionIdentifier(selections.first()), true, true);
// ShowAndSetConnection(ItemConnectionIdentifier(selections.first()),
// true, true);
//}
}
}
void MainWindow::on_action_StartThis_triggered()
{
//if (!IsSelectionConnectable) {
// QvMessageBoxWarn(this, tr("No connection selected!"), tr("Please select a config from the list."));
// return;
// if (!IsSelectionConnectable) {
// QvMessageBoxWarn(this, tr("No connection selected!"), tr("Please
// select a config from the list.")); return;
//}
//
//CurrentSelectedItemPtr = connectionListWidget->selectedItems().first();
//CurrentConnectionIdentifier = ItemConnectionIdentifier(CurrentSelectedItemPtr);
//on_reconnectButton_clicked();
// CurrentSelectedItemPtr = connectionListWidget->selectedItems().first();
// CurrentConnectionIdentifier =
// ItemConnectionIdentifier(CurrentSelectedItemPtr);
// on_reconnectButton_clicked();
}
#ifndef DISABLE_AUTO_UPDATE
@ -269,28 +286,27 @@ void MainWindow::VersionUpdate(QByteArray &data)
QVersionNumber newVersion = QVersionNumber::fromString(root["tag_name"].toString("v").remove(0, 1));
QVersionNumber currentVersion = QVersionNumber::fromString(QString(QV2RAY_VERSION_STRING).remove(0, 1));
QVersionNumber ignoredVersion = QVersionNumber::fromString(GlobalConfig.ignoredVersion);
LOG(MODULE_UPDATE, "Received update info, Latest: " + newVersion.toString() + " Current: " + currentVersion.toString() + " Ignored: " + ignoredVersion.toString())
LOG(MODULE_UPDATE, "Received update info, Latest: " + newVersion.toString() + " Current: " + currentVersion.toString() +
" Ignored: " + ignoredVersion.toString())
// If the version is newer than us.
// And new version is newer than the ignored version.
if (newVersion > currentVersion && newVersion > ignoredVersion) {
if (newVersion > currentVersion && newVersion > ignoredVersion)
{
LOG(MODULE_UPDATE, "New version detected.")
auto link = root["html_url"].toString("");
auto result = QvMessageBoxAsk(this, tr("Update"),
tr("Found a new version: ") + root["tag_name"].toString("") +
"\r\n" +
root["name"].toString("") +
"\r\n------------\r\n" +
root["body"].toString("") +
"\r\n------------\r\n" +
tr("Download Link: ") + link, QMessageBox::Ignore);
auto result =
QvMessageBoxAsk(this, tr("Update"),
tr("Found a new version: ") + root["tag_name"].toString("") + "\r\n" + root["name"].toString("") +
"\r\n------------\r\n" + root["body"].toString("") + "\r\n------------\r\n" + tr("Download Link: ") + link,
QMessageBox::Ignore);
if (result == QMessageBox::Yes) {
QDesktopServices::openUrl(QUrl::fromUserInput(link));
} else if (result == QMessageBox::Ignore) {
if (result == QMessageBox::Yes) { QDesktopServices::openUrl(QUrl::fromUserInput(link)); }
else if (result == QMessageBox::Ignore)
{
// Set and save ingored version.
GlobalConfig.ignoredVersion = newVersion.toString();
//SaveGlobalConfig(GlobalConfig);
// SaveGlobalConfig(GlobalConfig);
}
}
}
@ -309,12 +325,14 @@ void MainWindow::closeEvent(QCloseEvent *event)
}
void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason)
{
switch (reason) {
switch (reason)
{
case QSystemTrayIcon::Trigger:
// Toggle Show/Hide
#ifndef __APPLE__
// Every single click will trigger the Show/Hide toggling.
// So, as what common macOS Apps do, we don't toggle visibility here.
// So, as what common macOS Apps do, we don't toggle visibility
// here.
ToggleVisibility();
#endif
break;
@ -325,13 +343,13 @@ void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason)
#endif
break;
default:
break;
default: break;
}
}
void MainWindow::ToggleVisibility()
{
if (this->isHidden()) {
if (this->isHidden())
{
this->show();
#ifdef Q_OS_WIN
setWindowState(Qt::WindowNoState);
@ -340,7 +358,9 @@ void MainWindow::ToggleVisibility()
SetWindowPos(HWND(this->winId()), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#endif
tray_RootMenu->actions()[0]->setText(tr("Hide"));
} else {
}
else
{
this->hide();
tray_RootMenu->actions()[0]->setText(tr("Show"));
}
@ -348,9 +368,7 @@ void MainWindow::ToggleVisibility()
void MainWindow::on_actionExit_triggered()
{
if (StartupOption.enableToolbarPlguin) {
StopProcessingPlugins();
}
if (StartupOption.enableToolbarPlguin) { StopProcessingPlugins(); }
ExitQv2ray();
}
@ -366,13 +384,14 @@ void MainWindow::on_clearlogButton_clicked()
void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
Q_UNUSED(previous)
//CurrentItem = current;
//isRenamingInProgress = false;
// CurrentItem = current;
// isRenamingInProgress = false;
//
//if (!IsConnectableItem(current)) return;
// if (!IsConnectableItem(current)) return;
//
//// no need to check !isRenamingInProgress since it's always true.
//ShowAndSetConnection(ItemConnectionIdentifier(current), !vinstance->KernelStarted, false);
// ShowAndSetConnection(ItemConnectionIdentifier(current),
// !vinstance->KernelStarted, false);
////on_connectionListWidget_itemClicked(current, 0);
}
void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint &pos)
@ -381,52 +400,55 @@ void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint
auto _pos = QCursor::pos();
auto item = connectionListWidget->itemAt(connectionListWidget->mapFromGlobal(_pos));
if (GetItemWidget(item)->IsConnection()) {
connectionListMenu->popup(_pos);
}
if (GetItemWidget(item)->IsConnection()) { connectionListMenu->popup(_pos); }
}
void MainWindow::on_action_RCM_RenameConnection_triggered()
{
//auto item = connectionListWidget->currentItem();
//SUBSCRIPTION_CONFIG_MODIFY_DENY(item)
//item->setFlags(item->flags() | Qt::ItemIsEditable);
//isRenamingInProgress = true;
//connectionListWidget->editItem(item);
//renameOriginalIdentifier = ItemConnectionIdentifier(item);
// auto item = connectionListWidget->currentItem();
// SUBSCRIPTION_CONFIG_MODIFY_DENY(item)
// item->setFlags(item->flags() | Qt::ItemIsEditable);
// isRenamingInProgress = true;
// connectionListWidget->editItem(item);
// renameOriginalIdentifier = ItemConnectionIdentifier(item);
}
void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
{
//DEBUG(UI, "A connection ListViewItem is changed. This should ONLY occur when renaming an connection.")
// DEBUG(UI, "A connection ListViewItem is changed. This should ONLY occur
// when renaming an connection.")
//
//if (!isRenamingInProgress) {
// if (!isRenamingInProgress) {
// return;
//}
//
//isRenamingInProgress = false;
// isRenamingInProgress = false;
//// In this case it's after we entered the name.
//// and tell user you should not rename a config from subscription.
//auto newIdentifier = renameOriginalIdentifier;
//newIdentifier.connectionName = item->text(0);
//LOG(CONNECTION, "RENAME: " + renameOriginalIdentifier.IdentifierString() + " -> " + newIdentifier.IdentifierString())
// auto newIdentifier = renameOriginalIdentifier;
// newIdentifier.connectionName = item->text(0);
// LOG(CONNECTION, "RENAME: " + renameOriginalIdentifier.IdentifierString()
// + " -> " + newIdentifier.IdentifierString())
//
//// If I really did some changes.
//if (renameOriginalIdentifier != newIdentifier) {
// if (renameOriginalIdentifier != newIdentifier) {
// bool canContinueRename = true;
//
// if (newIdentifier.connectionName.trimmed().isEmpty()) {
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name cannot be empty"));
// canContinueRename = false;
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name
// cannot be empty")); canContinueRename = false;
// }
//
// QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
// //if (GlobalConfig.configs.contains(newIdentifier.connectionName)) {
// // QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name has been used already, Please choose another."));
// // QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name
// has been used already, Please choose another."));
// // canContinueRename = false;
// //}
//
// if (!IsValidFileName(newIdentifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION)) {
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name you suggested is not valid, please try another."));
// canContinueRename = false;
// if (!IsValidFileName(newIdentifier.connectionName +
// QV2RAY_CONFIG_FILE_EXTENSION)) {
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name you
// suggested is not valid, please try another.")); canContinueRename
// = false;
// }
//
// if (!canContinueRename) {
@ -448,8 +470,10 @@ void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
// //GlobalConfig.configs.removeOne(renameOriginalIdentifier.connectionName);
// //GlobalConfig.configs.push_back(newIdentifier.connectionName);
// //
// //connections[newIdentifier] = connections.take(renameOriginalIdentifier);
// //RenameConnection(renameOriginalIdentifier.connectionName, newIdentifier.connectionName);
// //connections[newIdentifier] =
// connections.take(renameOriginalIdentifier);
// //RenameConnection(renameOriginalIdentifier.connectionName,
// newIdentifier.connectionName);
// //LOG(UI, "Saving a global config")
// //SaveGlobalConfig(GlobalConfig);
// ////
@ -462,35 +486,38 @@ void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
// // on_reconnectButton_clicked();
// // }
// //}
// //OnConfigListChanged(CurrentConnectionIdentifier.connectionName == renameOriginalName);
// //OnConfigListChanged(CurrentConnectionIdentifier.connectionName ==
// renameOriginalName);
//}
}
void MainWindow::on_removeConfigButton_clicked()
{
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
//QList<ConnectionIdentifier> connlist;
// QList<ConnectionIdentifier> connlist;
//
//for (auto item : connectionListWidget->selectedItems()) {
// for (auto item : connectionListWidget->selectedItems()) {
// if (IsConnectableItem(item)) {
// connlist.append(ItemConnectionIdentifier(item));
// }
//}
//
//LOG(UI, "Selected " + QSTRN(connlist.count()) + " items")
// LOG(UI, "Selected " + QSTRN(connlist.count()) + " items")
//
//if (connlist.isEmpty()) {
// if (connlist.isEmpty()) {
// // Remove nothing means doing nothing.
// return;
//}
//
//if (QvMessageBoxAsk(this, tr("Removing Connection(s)"), tr("Are you sure to remove selected connection(s)?")) != QMessageBox::Yes) {
// if (QvMessageBoxAsk(this, tr("Removing Connection(s)"), tr("Are you sure
// to remove selected connection(s)?")) != QMessageBox::Yes) {
// return;
//}
//
//// A triple-state flag which indicates if the user wants to remove the configs loaded from a subscription.
//int subscriptionRemovalCheckStatus = -1;
//// A triple-state flag which indicates if the user wants to remove the
/// configs loaded from a subscription.
// int subscriptionRemovalCheckStatus = -1;
//
//for (auto conn : connlist) {
// for (auto conn : connlist) {
// if (conn == CurrentConnectionIdentifier) {
// on_stopButton_clicked();
// CurrentConnectionIdentifier = ConnectionIdentifier();
@ -499,8 +526,10 @@ void MainWindow::on_removeConfigButton_clicked()
// auto connData = connections[conn];
//
// // Remove auto start config.
// if (GlobalConfig.autoStartConfig.subscriptionName == connData.subscriptionName &&
// GlobalConfig.autoStartConfig.connectionName == connData.connectionName)
// if (GlobalConfig.autoStartConfig.subscriptionName ==
// connData.subscriptionName &&
// GlobalConfig.autoStartConfig.connectionName ==
// connData.connectionName)
// // If all those settings match.
// {
// GlobalConfig.autoStartConfig.subscriptionName.clear();
@ -510,44 +539,53 @@ void MainWindow::on_removeConfigButton_clicked()
// if (connData.configType == CONNECTION_REGULAR) {
// // Just remove the regular configs.
// if (!connData.subscriptionName.isEmpty()) {
// LOG(UI, "Unexpected subscription name in a single regular config.")
// connData.subscriptionName.clear();
// LOG(UI, "Unexpected subscription name in a single regular
// config.") connData.subscriptionName.clear();
// }
//
// GlobalConfig.configs.removeOne(conn.connectionName);
//
// if (!RemoveConnection(conn.connectionName)) {
// QvMessageBoxWarn(this, tr("Removing this Connection"), tr("Failed to delete connection file, please delete manually."));
// QvMessageBoxWarn(this, tr("Removing this Connection"),
// tr("Failed to delete connection file, please delete
// manually."));
// }
// } else if (connData.configType == CONNECTION_SUBSCRIPTION) {
// if (subscriptionRemovalCheckStatus == -1) {
// subscriptionRemovalCheckStatus = (QvMessageBoxAsk(this, tr("Removing a subscription config"), tr("Do you want to remove the config loaded from a subscription?")) == QMessageBox::Yes)
// subscriptionRemovalCheckStatus = (QvMessageBoxAsk(this,
// tr("Removing a subscription config"), tr("Do you want to
// remove the config loaded from a subscription?")) ==
// QMessageBox::Yes)
// ? 1 // Yes i want
// : 0; // No please keep
// }
//
// if (subscriptionRemovalCheckStatus == 1) {
// if (!RemoveSubscriptionConnection(connData.subscriptionName, connData.connectionName)) {
// QvMessageBoxWarn(this, tr("Removing this Connection"), tr("Failed to delete connection file, please delete manually."));
// if (!RemoveSubscriptionConnection(connData.subscriptionName,
// connData.connectionName)) {
// QvMessageBoxWarn(this, tr("Removing this Connection"),
// tr("Failed to delete connection file, please delete
// manually."));
// }
// }
// } else {
// LOG(SETTINGS, "Unknown config type -> Not regular nor subscription...")
// LOG(SETTINGS, "Unknown config type -> Not regular nor
// subscription...")
// }
//}
//
//LOG(UI, "Saving GlobalConfig")
//SaveGlobalConfig(GlobalConfig);
//OnConfigListChanged(false);
//ShowAndSetConnection(CurrentConnectionIdentifier, false, false);
// LOG(UI, "Saving GlobalConfig")
// SaveGlobalConfig(GlobalConfig);
// OnConfigListChanged(false);
// ShowAndSetConnection(CurrentConnectionIdentifier, false, false);
}
void MainWindow::on_importConfigButton_clicked()
{
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
//ImportConfigWindow w(this);
//auto configs = w.OpenImport();
//if (!configs.isEmpty()) {
// ImportConfigWindow w(this);
// auto configs = w.OpenImport();
// if (!configs.isEmpty()) {
// for (auto conf : configs) {
// auto name = configs.key(conf, "");
//
@ -569,26 +607,26 @@ void MainWindow::on_editConfigButton_clicked()
void MainWindow::on_action_RCM_ConvToComplex_triggered()
{
//// Check if we have a connection selected...
//if (!IsSelectionConnectable) {
// QvMessageBoxWarn(this, tr("No Config Selected"), tr("Please Select a Config"));
// return;
// if (!IsSelectionConnectable) {
// QvMessageBoxWarn(this, tr("No Config Selected"), tr("Please Select a
// Config")); return;
//}
//
//auto selectedFirst = connectionListWidget->currentItem();
//auto _identifier = ItemConnectionIdentifier(selectedFirst);
//SUBSCRIPTION_CONFIG_MODIFY_DENY(selectedFirst)
// auto selectedFirst = connectionListWidget->currentItem();
// auto _identifier = ItemConnectionIdentifier(selectedFirst);
// SUBSCRIPTION_CONFIG_MODIFY_DENY(selectedFirst)
////
//auto outBoundRoot = connections[_identifier].config;
//CONFIGROOT root;
//bool isChanged = false;
// auto outBoundRoot = connections[_identifier].config;
// CONFIGROOT root;
// bool isChanged = false;
////
//LOG(UI, "INFO: Opening route editor.")
//RouteEditor routeWindow(outBoundRoot, this);
//root = routeWindow.OpenEditor();
//isChanged = routeWindow.result() == QDialog::Accepted;
//QString alias = _identifier.connectionName;
// LOG(UI, "INFO: Opening route editor.")
// RouteEditor routeWindow(outBoundRoot, this);
// root = routeWindow.OpenEditor();
// isChanged = routeWindow.result() == QDialog::Accepted;
// QString alias = _identifier.connectionName;
//
//if (isChanged) {
// if (isChanged) {
// connections[_identifier].config = root;
// // true indicates the alias will NOT change
// SaveConnectionConfig(root, &alias, true);
@ -603,7 +641,7 @@ void MainWindow::on_action_RCM_EditJson_triggered()
void MainWindow::on_action_RCM_ShareQR_triggered()
{
//on_shareBtn_clicked();
// on_shareBtn_clicked();
}
void MainWindow::on_subsButton_clicked()
@ -616,9 +654,7 @@ void MainWindow::on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item
Q_UNUSED(column)
auto widget = GetItemWidget(item);
if (widget->IsConnection()) {
widget->BeginConnection();
}
if (widget->IsConnection()) { widget->BeginConnection(); }
}
void MainWindow::OnDisConnected(const ConnectionId &id)
@ -628,14 +664,13 @@ void MainWindow::OnDisConnected(const ConnectionId &id)
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE);
connetionStatusLabel->setText(tr("Disconnected"));
if (systemProxyEnabled) {
MWClearSystemProxy(false);
}
if (systemProxyEnabled) { MWClearSystemProxy(false); }
//QFile(QV2RAY_GENERATED_FILE_PATH).remove();
// QFile(QV2RAY_GENERATED_FILE_PATH).remove();
if (GlobalConfig.inboundConfig.pacConfig.enablePAC) {
//pacServer.StopServer();
if (GlobalConfig.inboundConfig.pacConfig.enablePAC)
{
// pacServer.StopServer();
LOG(MODULE_UI, "Stopping PAC server")
}
}
@ -655,56 +690,64 @@ void MainWindow::OnConnected(const ConnectionId &id)
bool httpEnabled = GlobalConfig.inboundConfig.useHTTP;
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
if (usePAC) {
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
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()) {
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 {
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"));
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 {
}
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"));
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 {
if (canStartPAC)
{
// pacServer.SetProxyString(pacProxyString);
// pacServer.StartListen();
}
else
{
LOG(MODULE_PROXY, "Not starting PAC due to previous error.")
}
}
if (GlobalConfig.inboundConfig.setSystemProxy) {
MWSetSystemProxy();
}
if (GlobalConfig.inboundConfig.setSystemProxy) { MWSetSystemProxy(); }
}
void MainWindow::onConnectionWidgetFocusRequested(const ConnectionItemWidget *_widget)
{
if (_widget == nullptr) {
return;
}
if (_widget == nullptr) { return; }
for (auto _item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard | Qt::MatchRecursive)) {
if (GetItemWidget(_item_) == _widget) {
for (auto _item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard | Qt::MatchRecursive))
{
if (GetItemWidget(_item_) == _widget)
{
LOG(MODULE_UI, "Setting current item.")
connectionListWidget->setCurrentItem(_item_);
connectionListWidget->scrollToItem(_item_);
@ -717,28 +760,31 @@ void MainWindow::onConnectionWidgetFocusRequested(const ConnectionItemWidget *_w
void MainWindow::on_connectionFilterTxt_textEdited(const QString &arg1)
{
// No recursive since we only need top level item
for (auto _top_item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard)) {
//auto topWidget = GetItemWidget(_top_item_);
for (auto _top_item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard))
{
// auto topWidget = GetItemWidget(_top_item_);
bool isTotallyHide = true;
for (auto i = 0; i < _top_item_->childCount(); i++) {
for (auto i = 0; i < _top_item_->childCount(); i++)
{
auto _child_ = _top_item_->child(i);
if (GetItemWidget(_child_)->NameMatched(arg1)) {
if (GetItemWidget(_child_)->NameMatched(arg1))
{
LOG(MODULE_UI, "Setting current item.")
// Show the child
_child_->setHidden(false);
isTotallyHide = false;
} else {
}
else
{
_child_->setHidden(true);
}
}
_top_item_->setHidden(isTotallyHide);
if (!isTotallyHide) {
connectionListWidget->expandItem(_top_item_);
}
if (!isTotallyHide) { connectionListWidget->expandItem(_top_item_); }
}
}
@ -748,11 +794,12 @@ void MainWindow::on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int
infoWidget->ShowDetails(GetItemWidget(item)->Identifier());
}
void MainWindow::onConnectionStatsArrived(const ConnectionId &id, const quint64 upSpeed, const quint64 downSpeed, const quint64 totalUp, const quint64 totalDown)
void MainWindow::onConnectionStatsArrived(const ConnectionId &id, const quint64 upSpeed, const quint64 downSpeed, const quint64 totalUp,
const quint64 totalDown)
{
Q_UNUSED(id);
// This may not be, or may not precisely be, speed per second if low-level has "any" latency.
// (Hope not...)
// This may not be, or may not precisely be, speed per second if low-level
// has "any" latency. (Hope not...)
speedChartWidget->AddPointData(upSpeed, downSpeed);
//
auto totalSpeedUp = FormatBytes(upSpeed) + "/s";
@ -763,7 +810,8 @@ void MainWindow::onConnectionStatsArrived(const ConnectionId &id, const quint64
netspeedLabel->setText(totalSpeedUp + NEWLINE + totalSpeedDown);
dataamountLabel->setText(totalDataUp + NEWLINE + totalDataDown);
//
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + ConnectionManager->GetDisplayName(id) + NEWLINE "Up: " + totalSpeedUp + " Down: " + totalSpeedDown);
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + ConnectionManager->GetDisplayName(id) + NEWLINE "Up: " + totalSpeedUp +
" Down: " + totalSpeedDown);
}
void MainWindow::onVCoreLogArrived(const ConnectionId &id, const QString &log)
@ -777,35 +825,40 @@ void MainWindow::onVCoreLogArrived(const ConnectionId &id, const QString &log)
auto maxLines = GlobalConfig.uiConfig.maximumLogLines;
QTextBlock block = masterLogBrowser->document()->begin();
while (block.isValid()) {
if (masterLogBrowser->document()->blockCount() > maxLines) {
while (block.isValid())
{
if (masterLogBrowser->document()->blockCount() > maxLines)
{
QTextCursor cursor(block);
block = block.next();
cursor.select(QTextCursor::BlockUnderCursor);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
cursor.removeSelectedText();
} else {
}
else
{
break;
}
}
if (val >= max * 0.8 || val >= max - 20)
bar->setValue(max);
if (val >= max * 0.8 || val >= max - 20) bar->setValue(max);
}
void MainWindow::OnEditRequested(const ConnectionId &id)
{
auto outBoundRoot = ConnectionManager->GetConnectionRoot(id);
CONFIGROOT root;
bool isChanged = false;
if (IsComplexConfig(outBoundRoot)) {
if (IsComplexConfig(outBoundRoot))
{
LOG(MODULE_UI, "INFO: Opening route editor.")
RouteEditor routeWindow(outBoundRoot, this);
root = routeWindow.OpenEditor();
isChanged = routeWindow.result() == QDialog::Accepted;
} else {
}
else
{
LOG(MODULE_UI, "INFO: Opening single connection edit window.")
auto out = OUTBOUND(outBoundRoot["outbounds"].toArray().first().toObject());
OutboundEditor w(out, this);
@ -816,18 +869,21 @@ void MainWindow::OnEditRequested(const ConnectionId &id)
root.insert("outbounds", outboundsList);
}
if (isChanged) {
//if (CheckConfigType(firstSelected, SUBSCRIPTION)) {
if (isChanged)
{
// if (CheckConfigType(firstSelected, SUBSCRIPTION)) {
// auto name = connections[_identifier].connectionName;
// // Assume name will not change.
// SaveSubscriptionConfig(root, connections[_identifier].subscriptionName, &name);
// SaveSubscriptionConfig(root,
// connections[_identifier].subscriptionName, &name);
//} else {
// connections[_identifier].config = root;
// // true indicates the alias will NOT change
// SaveConnectionConfig(root, &alias, true);
//}
ConnectionManager->UpdateConnection(id, root);
//OnConfigListChanged(alias == CurrentConnectionIdentifier.connectionName);
// OnConfigListChanged(alias ==
// CurrentConnectionIdentifier.connectionName);
}
}
void MainWindow::OnJsonEditRequested(const ConnectionId &id)
@ -835,7 +891,5 @@ void MainWindow::OnJsonEditRequested(const ConnectionId &id)
JsonEditor w(ConnectionManager->GetConnectionRoot(id), this);
auto root = CONFIGROOT(w.OpenEditor());
if (w.result() == QDialog::Accepted) {
ConnectionManager->UpdateConnection(id, root);
}
if (w.result() == QDialog::Accepted) { ConnectionManager->UpdateConnection(id, root); }
}

View File

@ -1,114 +1,116 @@
#pragma once
#include "common/HTTPRequestHelper.hpp"
#include "common/LogHighlighter.hpp"
#include "components/speedchart/speedwidget.hpp"
#include "core/handler/ConnectionHandler.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_MainWindow.h"
#include <QMainWindow>
#include <QMenu>
#include <QScrollBar>
#include <QSystemTrayIcon>
#include "ui_w_MainWindow.h"
#include "common/LogHighlighter.hpp"
#include "common/HTTPRequestHelper.hpp"
#include "components/speedchart/speedwidget.hpp"
#include "core/handler/ConnectionHandler.hpp"
#include "ui/messaging/QvMessageBus.hpp"
// ==========================================================================================
#include "ui/widgets/ConnectionItemWidget.hpp"
#include "ui/widgets/ConnectionInfoWidget.hpp"
#include "ui/widgets/ConnectionItemWidget.hpp"
class MainWindow : public QMainWindow, Ui::MainWindow
class MainWindow
: public QMainWindow
, Ui::MainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
signals:
void Connect() const;
void DisConnect() const;
void ReConnect() const;
public slots:
QvMessageBusSlotDecl
private slots:
void on_action_RCM_ShareQR_triggered();
void on_activatedTray(QSystemTrayIcon::ActivationReason reason);
void on_actionExit_triggered();
void on_preferencesBtn_clicked();
void on_clearlogButton_clicked();
void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void on_connectionListWidget_customContextMenuRequested(const QPoint &pos);
void on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int column);
void on_removeConfigButton_clicked();
void on_importConfigButton_clicked();
void on_editConfigButton_clicked();
void on_subsButton_clicked();
//
void ToggleVisibility();
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
signals:
void Connect() const;
void DisConnect() const;
void ReConnect() const;
public slots:
QvMessageBusSlotDecl;
private slots:
void on_action_RCM_ShareQR_triggered();
void on_activatedTray(QSystemTrayIcon::ActivationReason reason);
void on_actionExit_triggered();
void on_preferencesBtn_clicked();
void on_clearlogButton_clicked();
void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void on_connectionListWidget_customContextMenuRequested(const QPoint &pos);
void on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int column);
void on_removeConfigButton_clicked();
void on_importConfigButton_clicked();
void on_editConfigButton_clicked();
void on_subsButton_clicked();
//
void ToggleVisibility();
#ifndef DISABLE_AUTO_UPDATE
void VersionUpdate(QByteArray &data);
void VersionUpdate(QByteArray &data);
#endif
//
//
public:
static MainWindow *mwInstance;
public:
static MainWindow *mwInstance;
protected:
void keyPressEvent(QKeyEvent *e) override;
void closeEvent(QCloseEvent *) override;
protected:
void keyPressEvent(QKeyEvent *e) override;
void closeEvent(QCloseEvent *) override;
private slots:
//
void OnConnected(const ConnectionId &id);
void OnDisConnected(const ConnectionId &id);
void OnEditRequested(const ConnectionId &id);
void OnJsonEditRequested(const ConnectionId &id);
private slots:
//
void OnConnected(const ConnectionId &id);
void OnDisConnected(const ConnectionId &id);
void OnEditRequested(const ConnectionId &id);
void OnJsonEditRequested(const ConnectionId &id);
void onConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
//void onConnectionConnected(const ConnectionId &id);
//void onConnectionDisConnected(const ConnectionId &id);
void onConnectionStatsArrived(const ConnectionId &id, const quint64 upSpeed, const quint64 downSpeed, const quint64 totalUp, const quint64 totalDown);
void onVCoreLogArrived(const ConnectionId &id, const QString &log);
//
void on_action_StartThis_triggered();
void on_action_RCM_EditJson_triggered();
void on_action_RCM_ConvToComplex_triggered();
void on_action_RCM_RenameConnection_triggered();
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
void on_connectionFilterTxt_textEdited(const QString &arg1);
void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
void onConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
// void onConnectionConnected(const ConnectionId &id);
// void onConnectionDisConnected(const ConnectionId &id);
void onConnectionStatsArrived(const ConnectionId &id, const quint64 upSpeed, const quint64 downSpeed, const quint64 totalUp,
const quint64 totalDown);
void onVCoreLogArrived(const ConnectionId &id, const QString &log);
//
void on_action_StartThis_triggered();
void on_action_RCM_EditJson_triggered();
void on_action_RCM_ConvToComplex_triggered();
void on_action_RCM_RenameConnection_triggered();
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
void on_connectionFilterTxt_textEdited(const QString &arg1);
void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
private:
QTreeWidgetItem *CurrentItem;
// Charts
SpeedWidget *speedChartWidget;
QMenu *connectionListMenu;
private:
QTreeWidgetItem *CurrentItem;
// Charts
SpeedWidget *speedChartWidget;
QMenu *connectionListMenu;
#ifndef DISABLE_AUTO_UPDATE
QvHttpRequestHelper *requestHelper;
QvHttpRequestHelper *requestHelper;
#endif
QSystemTrayIcon hTray;
//PACServer pacServer;
//QvTCPingModel tcpingHelper;
SyntaxHighlighter *vCoreLogHighlighter;
ConnectionInfoWidget *infoWidget;
//
// Actions in the system tray menu
//
QMenu *tray_RootMenu = new QMenu(this);
QAction *action_Tray_ShowHide;
QAction *action_Tray_ShowPreferencesWindow;
QAction *action_Tray_Quit;
// --> Connectivities
QAction *action_Tray_Start;
QAction *action_Tray_Reconnect ;
QAction *action_Tray_Stop;
// --> System proxy settings
QMenu *tray_SystemProxyMenu = new QMenu(this);
QAction *action_Tray_SetSystemProxy;
QAction *action_Tray_ClearSystemProxy;
//
// ----------------------------------- Extra Headers For w_MainWindow_extra.cpp Handling V2ray Connectivities.
bool systemProxyEnabled;
void MWSetSystemProxy();
void MWClearSystemProxy(bool);
void CheckSubscriptionsUpdate();
QSystemTrayIcon hTray;
// PACServer pacServer;
// QvTCPingModel tcpingHelper;
SyntaxHighlighter *vCoreLogHighlighter;
ConnectionInfoWidget *infoWidget;
//
// Actions in the system tray menu
//
QMenu *tray_RootMenu = new QMenu(this);
QAction *action_Tray_ShowHide;
QAction *action_Tray_ShowPreferencesWindow;
QAction *action_Tray_Quit;
// --> Connectivities
QAction *action_Tray_Start;
QAction *action_Tray_Reconnect;
QAction *action_Tray_Stop;
// --> System proxy settings
QMenu *tray_SystemProxyMenu = new QMenu(this);
QAction *action_Tray_SetSystemProxy;
QAction *action_Tray_ClearSystemProxy;
//
// ----------------------------------- Extra Headers For w_MainWindow_extra.cpp Handling V2ray Connectivities.
bool systemProxyEnabled;
void MWSetSystemProxy();
void MWClearSystemProxy(bool);
void CheckSubscriptionsUpdate();
};

View File

@ -1,16 +1,19 @@
// Supplementary file for MainWindow -- Basically the handler for connectivity management
// and components interactions.
// We NEED to include the cpp file to define the macros.
#include "w_MainWindow.cpp"
// Supplementary file for MainWindow -- Basically the handler for connectivity
// management and components interactions. We NEED to include the cpp file to
// define the macros.
#include "components/proxy/QvProxyConfigurator.hpp"
#include "w_MainWindow.cpp"
//QTreeWidgetItem *MainWindow::FindItemByIdentifier(QvConnectionObject identifier)
// QTreeWidgetItem *MainWindow::FindItemByIdentifier(QvConnectionObject
// identifier)
//{
// //// First filter out all items with our config name.
// //auto items = connectionListWidget->findItems(identifier.connectionName, Qt::MatchExactly | Qt::MatchRecursive);
// //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
// // // 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))
@ -25,8 +28,8 @@
// // }
// //}
// //
// //LOG(UI, "Warning: Failed to find an item named: " + identifier.IdentifierString())
// return nullptr;
// //LOG(UI, "Warning: Failed to find an item named: " +
// identifier.IdentifierString()) return nullptr;
//}
void MainWindow::MWClearSystemProxy(bool showMessage)
@ -35,9 +38,7 @@ void MainWindow::MWClearSystemProxy(bool showMessage)
LOG(MODULE_UI, "Clearing System Proxy")
systemProxyEnabled = false;
if (showMessage) {
hTray.showMessage("Qv2ray", tr("System proxy cleared."), windowIcon());
}
if (showMessage) { hTray.showMessage("Qv2ray", tr("System proxy cleared."), windowIcon()); }
}
void MainWindow::MWSetSystemProxy()
@ -48,45 +49,58 @@ 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) {
if (!isComplex)
{
// Is simple config and we will try to set system proxy.
LOG(MODULE_UI, "Preparing to set system proxy")
//
QString proxyAddress;
bool canSetSystemProxy = true;
if (usePAC) {
if ((httpEnabled && !pacUseSocks) || (socksEnabled && pacUseSocks)) {
if (usePAC)
{
if ((httpEnabled && !pacUseSocks) || (socksEnabled && pacUseSocks))
{
// If we use PAC and socks/http are properly configured for PAC
LOG(MODULE_PROXY, "System proxy uses PAC")
proxyAddress = "http://" + GlobalConfig.inboundConfig.listenip + ":" + QSTRN(GlobalConfig.inboundConfig.pacConfig.port) + "/pac";
} else {
proxyAddress = "http://" + GlobalConfig.inboundConfig.listenip + ":" + QSTRN(GlobalConfig.inboundConfig.pacConfig.port) + "/pac";
}
else
{
// Not properly configured
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."));
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;
}
} else {
}
else
{
// Not using PAC
if (httpEnabled || socksEnabled) {
if (httpEnabled || socksEnabled)
{
// Not use PAC, System proxy should use HTTP or SOCKS
LOG(MODULE_PROXY, "Setting up system proxy.")
// A 'proxy host' should be a host WITHOUT `http://` uri scheme
proxyAddress = "localhost";
} else {
}
else
{
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) {
if (canSetSystemProxy)
{
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;
@ -96,7 +110,9 @@ void MainWindow::MWSetSystemProxy()
systemProxyEnabled = true;
hTray.showMessage("Qv2ray", tr("System proxy settings applied."), windowIcon());
}
} else {
}
else
{
hTray.showMessage("Qv2ray", tr("Cannot set proxy for complex config."), windowIcon());
}
}
@ -105,28 +121,29 @@ void MainWindow::CheckSubscriptionsUpdate()
{
QStringList updateList;
for (auto index = 0; index < GlobalConfig.subscriptions.count(); index++) {
for (auto index = 0; index < GlobalConfig.subscriptions.count(); index++)
{
auto subs = GlobalConfig.subscriptions.values()[index];
auto key = GlobalConfig.subscriptions.keys()[index];
//
auto lastRenewDate = QDateTime::fromTime_t(subs.lastUpdated);
auto renewTime = lastRenewDate.addSecs(subs.updateInterval * 86400);
LOG(MODULE_SUBSCRIPTION, "Subscription \"" + key + "\": " + NEWLINE +
" --> Last renewal time: " + lastRenewDate.toString() + NEWLINE +
" --> Renew interval: " + QSTRN(subs.updateInterval) + NEWLINE +
" --> Ideal renew time: " + renewTime.toString())
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()) {
if (renewTime <= QDateTime::currentDateTime())
{
LOG(MODULE_SUBSCRIPTION, "Subscription: " + key + " needs to be updated.")
updateList.append(key);
}
}
if (!updateList.isEmpty()) {
if (!updateList.isEmpty())
{
QvMessageBoxWarn(this, tr("Update Subscriptions"),
tr("There are subscriptions need to be updated, please go to subscriptions window to update them.") + NEWLINE + NEWLINE +
tr("These subscriptions are out-of-date: ") + NEWLINE + updateList.join(";"));
tr("There are subscriptions need to be updated, please go to subscriptions window to update them.") + NEWLINE +
NEWLINE + tr("These subscriptions are out-of-date: ") + NEWLINE + updateList.join(";"));
on_subsButton_clicked();
}
}

View File

@ -1,27 +1,28 @@
#include "w_PreferencesWindow.hpp"
#include <QFileDialog>
#include <QColorDialog>
#include <QStyleFactory>
#include <QStyle>
#include <QDesktopServices>
#include "common/QvHelpers.hpp"
#include "common/HTTPRequestHelper.hpp"
#include "common/QvHelpers.hpp"
#include "common/QvTranslator.hpp"
#include "components/autolaunch/QvAutoLaunch.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "core/config/ConfigBackend.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include "core/handler/ConnectionHandler.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "components/autolaunch/QvAutoLaunch.hpp"
#include "common/QvTranslator.hpp"
#include "core/kernel/KernelInteractions.hpp"
#include <QColorDialog>
#include <QDesktopServices>
#include <QFileDialog>
#include <QStyle>
#include <QStyleFactory>
using Qv2ray::common::validation::IsValidIPAddress;
#define LOADINGCHECK if(!finishedLoading) return;
#define NEEDRESTART if(finishedLoading) IsConnectionPropertyChanged = true;
#define LOADINGCHECK \
if (!finishedLoading) return;
#define NEEDRESTART \
if (finishedLoading) IsConnectionPropertyChanged = true;
PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
CurrentConfig()
PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent), CurrentConfig()
{
setupUi(this);
QvMessageBusConnect(PreferencesWindow);
@ -31,17 +32,14 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
// Set network Toolbar page state.
networkToolbarPage->setEnabled(StartupOption.enableToolbarPlguin);
if (!StartupOption.enableToolbarPlguin) {
networkToolbarInfoLabel->setText(tr("Qv2ray Network Toolbar is disabled and still under test. Add --withToolbarPlugin to enable."));
}
if (!StartupOption.enableToolbarPlguin)
{ networkToolbarInfoLabel->setText(tr("Qv2ray Network Toolbar is disabled and still under test. Add --withToolbarPlugin to enable.")); }
// We add locales
languageComboBox->clear();
QDirIterator it(":/translations");
while (it.hasNext()) {
languageComboBox->addItem(it.next().split("/").last().split(".").first());
}
while (it.hasNext()) { languageComboBox->addItem(it.next().split("/").last().split(".").first()); }
// Set auto start button state
SetAutoStartButtonsState(GetLaunchAtLoginStatus());
@ -120,26 +118,30 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
//
DNSListTxt->clear();
for (auto dnsStr : CurrentConfig.connectionConfig.dnsList) {
for (auto dnsStr : CurrentConfig.connectionConfig.dnsList)
{
auto str = dnsStr.trimmed();
if (!str.isEmpty()) {
DNSListTxt->appendPlainText(str);
}
if (!str.isEmpty()) { DNSListTxt->appendPlainText(str); }
}
//
cancelIgnoreVersionBtn->setEnabled(CurrentConfig.ignoredVersion != "");
ignoredNextVersion->setText(CurrentConfig.ignoredVersion);
for (auto i = 0; i < CurrentConfig.toolBarConfig.Pages.size(); i++) {
nsBarPagesList->addItem(tr("Page") + QSTRN(i + 1) + ": " + QSTRN(CurrentConfig.toolBarConfig.Pages[i].Lines.size()) + " " + tr("Item(s)"));
for (auto i = 0; i < CurrentConfig.toolBarConfig.Pages.size(); i++)
{
nsBarPagesList->addItem(tr("Page") + QSTRN(i + 1) + ": " + QSTRN(CurrentConfig.toolBarConfig.Pages[i].Lines.size()) + " " +
tr("Item(s)"));
}
if (CurrentConfig.toolBarConfig.Pages.size() > 0) {
if (CurrentConfig.toolBarConfig.Pages.size() > 0)
{
nsBarPagesList->setCurrentRow(0);
on_nsBarPagesList_currentRowChanged(0);
} else {
}
else
{
networkToolbarSettingsFrame->setEnabled(false);
nsBarLinesList->setEnabled(false);
nsBarLineDelBTN->setEnabled(false);
@ -153,22 +155,17 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
auto autoStartConnId = ConnectionId(CurrentConfig.autoStartId);
auto autoStartGroupId = ConnectionManager->GetConnectionGroupId(autoStartConnId);
for (auto group : ConnectionManager->AllGroups()) {
autoStartSubsCombo->addItem(ConnectionManager->GetDisplayName(group));
}
for (auto group : ConnectionManager->AllGroups()) { autoStartSubsCombo->addItem(ConnectionManager->GetDisplayName(group)); }
autoStartSubsCombo->setCurrentText(ConnectionManager->GetDisplayName(autoStartGroupId));
for (auto conn : ConnectionManager->Connections(autoStartGroupId)) {
autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(conn));
}
for (auto conn : ConnectionManager->Connections(autoStartGroupId)) { autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(conn)); }
autoStartConnCombo->setCurrentText(ConnectionManager->GetDisplayName(autoStartConnId));
// FP Settings
if (CurrentConfig.connectionConfig.forwardProxyConfig.type.trimmed().isEmpty()) {
CurrentConfig.connectionConfig.forwardProxyConfig.type = "http";
}
if (CurrentConfig.connectionConfig.forwardProxyConfig.type.trimmed().isEmpty())
{ CurrentConfig.connectionConfig.forwardProxyConfig.type = "http"; }
fpGroupBox->setChecked(CurrentConfig.connectionConfig.forwardProxyConfig.enableForwardProxy);
fpUsernameTx->setText(CurrentConfig.connectionConfig.forwardProxyConfig.username);
@ -182,18 +179,17 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
//
maxLogLinesSB->setValue(CurrentConfig.uiConfig.maximumLogLines);
//
pacListenAddrLabel->setText("http://" + (pacProxyTxt->text().isEmpty() ? "127.0.0.1" : pacProxyTxt->text()) + ":" + QSTRN(pacPortSB->value()) + "/pac");
pacListenAddrLabel->setText("http://" + (pacProxyTxt->text().isEmpty() ? "127.0.0.1" : pacProxyTxt->text()) + ":" +
QSTRN(pacPortSB->value()) + "/pac");
//
finishedLoading = true;
}
QvMessageBusSlotImpl(PreferencesWindow)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
@ -204,45 +200,57 @@ PreferencesWindow::~PreferencesWindow()
void PreferencesWindow::on_buttonBox_accepted()
{
// Note:
// A signal-slot connection from buttonbox_accpted to QDialog::accepted() has been removed.
// To prevent closing this Dialog.
// A signal-slot connection from buttonbox_accpted to QDialog::accepted()
// has been removed. To prevent closing this Dialog.
QSet<int> ports;
auto size = 0;
if (CurrentConfig.inboundConfig.useHTTP) {
size ++;
if (CurrentConfig.inboundConfig.useHTTP)
{
size++;
ports << CurrentConfig.inboundConfig.http_port;
}
if (CurrentConfig.inboundConfig.useSocks) {
size ++;
if (CurrentConfig.inboundConfig.useSocks)
{
size++;
ports << CurrentConfig.inboundConfig.socks_port;
}
if (CurrentConfig.inboundConfig.pacConfig.enablePAC) {
size ++;
if (CurrentConfig.inboundConfig.pacConfig.enablePAC)
{
size++;
ports << CurrentConfig.inboundConfig.pacConfig.port;
}
if (!StartupOption.noAPI) {
size ++;
if (!StartupOption.noAPI)
{
size++;
ports << CurrentConfig.apiConfig.statsPort;
}
if (ports.size() != size) {
if (ports.size() != size)
{
// Duplicates detected.
QvMessageBoxWarn(this, tr("Preferences"), tr("Duplicated port numbers detected, please check the port number settings."));
} else if (CurrentConfig.inboundConfig.listenip.toLower() != "localhost" && !IsValidIPAddress(CurrentConfig.inboundConfig.listenip)) {
QvMessageBoxWarn(this, tr("Preferences"), tr("Invalid inbound listening address."));;
} else {
if (CurrentConfig.uiConfig.language != GlobalConfig.uiConfig.language) {
}
else if (CurrentConfig.inboundConfig.listenip.toLower() != "localhost" && !IsValidIPAddress(CurrentConfig.inboundConfig.listenip))
{
QvMessageBoxWarn(this, tr("Preferences"), tr("Invalid inbound listening address."));
;
}
else
{
if (CurrentConfig.uiConfig.language != GlobalConfig.uiConfig.language)
{
qApp->removeTranslator(Qv2rayTranslator.get());
Qv2rayTranslator = std::move(QvTranslator(CurrentConfig.uiConfig.language).pTranslator);
// Install translator
if (!qApp->installTranslator(Qv2rayTranslator.get())) {
LOG(MODULE_UI, "Failed to translate UI to: " + CurrentConfig.uiConfig.language)
} else {
if (!qApp->installTranslator(Qv2rayTranslator.get()))
{ LOG(MODULE_UI, "Failed to translate UI to: " + CurrentConfig.uiConfig.language) }
else
{
messageBus.EmitGlobalSignal(QvMBMessage::RETRANSLATE);
QApplication::processEvents();
}
@ -296,13 +304,14 @@ void PreferencesWindow::on_listenIPTxt_textEdited(const QString &arg1)
NEEDRESTART
CurrentConfig.inboundConfig.listenip = arg1;
if (IsValidIPAddress(arg1)) {
BLACK(listenIPTxt)
} else {
if (IsValidIPAddress(arg1)) { BLACK(listenIPTxt) }
else
{
RED(listenIPTxt)
}
//pacAccessPathTxt->setText("http://" + arg1 + ":" + QSTRN(pacPortSB->value()) + "/pac");
// pacAccessPathTxt->setText("http://" + arg1 + ":" +
// QSTRN(pacPortSB->value()) + "/pac");
}
void PreferencesWindow::on_httpAuthUsernameTxt_textEdited(const QString &arg1)
@ -346,7 +355,8 @@ void PreferencesWindow::on_selectVAssetBtn_clicked()
NEEDRESTART
QString dir = QFileDialog::getExistingDirectory(this, tr("Open V2ray assets folder"), QDir::currentPath());
if (!dir.isEmpty()) {
if (!dir.isEmpty())
{
vCoreAssetsPathTxt->setText(dir);
on_vCoreAssetsPathTxt_textEdited(dir);
}
@ -356,7 +366,8 @@ void PreferencesWindow::on_selectVCoreBtn_clicked()
{
QString core = QFileDialog::getOpenFileName(this, tr("Open V2ray core file"), QDir::currentPath());
if (!core.isEmpty()) {
if (!core.isEmpty())
{
vCorePathTxt->setText(core);
on_vCorePathTxt_textEdited(core);
}
@ -370,13 +381,17 @@ void PreferencesWindow::on_vCorePathTxt_textEdited(const QString &arg1)
void PreferencesWindow::on_DNSListTxt_textChanged()
{
if (finishedLoading) {
try {
if (finishedLoading)
{
try
{
QStringList hosts = DNSListTxt->toPlainText().replace("\r", "").split("\n");
CurrentConfig.connectionConfig.dnsList.clear();
foreach (auto host, hosts) {
if (host != "" && host != "\r") {
foreach (auto host, hosts)
{
if (host != "" && host != "\r")
{
// Not empty, so we save.
CurrentConfig.connectionConfig.dnsList.push_back(host);
NEEDRESTART
@ -384,7 +399,9 @@ void PreferencesWindow::on_DNSListTxt_textChanged()
}
BLACK(DNSListTxt)
} catch (...) {
}
catch (...)
{
RED(DNSListTxt)
}
}
@ -408,19 +425,25 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
// Setting up tProxy for linux
// Steps:
// --> 1. Copy V2ray core files to the QV2RAY_TPROXY_VCORE_PATH and QV2RAY_TPROXY_VCTL_PATH dir.
// --> 1. Copy V2ray core files to the QV2RAY_TPROXY_VCORE_PATH and
// QV2RAY_TPROXY_VCTL_PATH dir.
// --> 2. Change GlobalConfig.v2CorePath.
// --> 3. Call `pkexec setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the V2ray core.
if (arg1 == Qt::Checked) {
// --> 3. Call `pkexec setcap
// CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the V2ray core.
if (arg1 == Qt::Checked)
{
// We enable it!
if (QvMessageBoxAsk(this, tr("Enable tProxy Support"),
tr("This will append capabilities to the V2ray executable.") + NEWLINE + NEWLINE +
tr("Qv2ray will copy your V2ray core to this path: ") + NEWLINE + QV2RAY_TPROXY_VCORE_PATH + NEWLINE + NEWLINE +
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) {
tr("This will append capabilities to the V2ray executable.") + NEWLINE + NEWLINE +
tr("Qv2ray will copy your V2ray core to this path: ") + NEWLINE + QV2RAY_TPROXY_VCORE_PATH + NEWLINE + NEWLINE +
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(MODULE_UI, "Canceled enabling tProxy feature.")
} else {
}
else
{
LOG(MODULE_VCORE, "ENABLING tProxy Support")
LOG(MODULE_FILEIO, " --> Origin V2ray core file is at: " + CurrentConfig.v2CorePath)
auto v2ctlPath = QFileInfo(CurrentConfig.v2CorePath).absolutePath() + "/v2ctl";
@ -433,17 +456,22 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
//
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 (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()) {
if (QFile(QV2RAY_TPROXY_VCORE_PATH).exists())
{
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()) {
if (QFile(QV2RAY_TPROXY_VCTL_PATH).exists())
{
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();
@ -456,18 +484,22 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
LOG(MODULE_FILEIO, " --> V2ray Ctl: " + vCtlresult)
//
if (vCoreresult == "OK" && vCtlresult == "OK") {
if (vCoreresult == "OK" && vCtlresult == "OK")
{
LOG(MODULE_VCORE, " --> Done copying files.")
on_vCorePathTxt_textEdited(QV2RAY_TPROXY_VCORE_PATH);
} else {
}
else
{
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 +
tr("to this path: ") + NEWLINE + newPath);
tr("Qv2ray cannot copy one or both V2ray files from: ") + NEWLINE + NEWLINE + CurrentConfig.v2CorePath +
NEWLINE + v2ctlPath + NEWLINE + NEWLINE + tr("to this path: ") + NEWLINE + newPath);
return;
}
} else {
}
else
{
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.")
}
@ -475,7 +507,8 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
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) {
if (ret != 0)
{
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."));
}
@ -483,10 +516,13 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
CurrentConfig.tProxySupport = true;
NEEDRESTART
}
} else {
}
else
{
int ret = QProcess::execute("pkexec setcap -r " + CurrentConfig.v2CorePath);
if (ret != 0) {
if (ret != 0)
{
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."));
}
@ -540,14 +576,15 @@ void PreferencesWindow::on_socksUDPIP_textEdited(const QString &arg1)
NEEDRESTART
CurrentConfig.inboundConfig.socksLocalIP = arg1;
if (IsValidIPAddress(arg1)) {
BLACK(socksUDPIP)
} else {
if (IsValidIPAddress(arg1)) { BLACK(socksUDPIP) }
else
{
RED(socksUDPIP)
}
}
// ------------------- NET SPEED PLUGIN OPERATIONS -----------------------------------------------------------------
// ------------------- NET SPEED PLUGIN OPERATIONS
// -----------------------------------------------------------------
#define CurrentBarPage CurrentConfig.toolBarConfig.Pages[this->CurrentBarPageId]
#define CurrentBarLine CurrentBarPage.Lines[this->CurrentBarLineId]
@ -557,7 +594,7 @@ void PreferencesWindow::on_nsBarPageAddBTN_clicked()
{
QvBarPage page;
CurrentConfig.toolBarConfig.Pages.push_back(page);
CurrentBarPageId = CurrentConfig.toolBarConfig.Pages.size() - 1 ;
CurrentBarPageId = CurrentConfig.toolBarConfig.Pages.size() - 1;
// Add default line.
QvBarLine line;
CurrentBarPage.Lines.push_back(line);
@ -576,11 +613,13 @@ void PreferencesWindow::on_nsBarPageAddBTN_clicked()
void PreferencesWindow::on_nsBarPageDelBTN_clicked()
{
if (nsBarPagesList->currentRow() >= 0) {
if (nsBarPagesList->currentRow() >= 0)
{
CurrentConfig.toolBarConfig.Pages.removeAt(nsBarPagesList->currentRow());
nsBarPagesList->takeItem(nsBarPagesList->currentRow());
if (nsBarPagesList->count() <= 0) {
if (nsBarPagesList->count() <= 0)
{
nsBarPageDelBTN->setEnabled(false);
nsBarLineAddBTN->setEnabled(false);
nsBarLineDelBTN->setEnabled(false);
@ -613,12 +652,14 @@ void PreferencesWindow::on_nsBarLineAddBTN_clicked()
void PreferencesWindow::on_nsBarLineDelBTN_clicked()
{
if (nsBarLinesList->currentRow() >= 0) {
if (nsBarLinesList->currentRow() >= 0)
{
CurrentBarPage.Lines.removeAt(nsBarLinesList->currentRow());
nsBarLinesList->takeItem(nsBarLinesList->currentRow());
CurrentBarLineId = 0;
if (nsBarLinesList->count() <= 0) {
if (nsBarLinesList->count() <= 0)
{
networkToolbarSettingsFrame->setEnabled(false);
nsBarLineDelBTN->setEnabled(false);
}
@ -639,15 +680,19 @@ void PreferencesWindow::on_nsBarPagesList_currentRowChanged(int currentRow)
nsBarPageYOffset->setValue(CurrentBarPage.OffsetYpx);
nsBarLinesList->clear();
if (!CurrentBarPage.Lines.empty()) {
for (auto line : CurrentBarPage.Lines) {
if (!CurrentBarPage.Lines.empty())
{
for (auto line : CurrentBarPage.Lines)
{
auto description = GetBarLineDescription(line);
nsBarLinesList->addItem(description);
}
nsBarLinesList->setCurrentRow(0);
ShowLineParameters(CurrentBarLine);
} else {
}
else
{
networkToolbarSettingsFrame->setEnabled(false);
}
}
@ -725,11 +770,9 @@ QString PreferencesWindow::GetBarLineDescription(QvBarLine barLine)
QString result = "Empty";
result = NetSpeedPluginMessages[barLine.ContentType];
if (barLine.ContentType == 0) {
result += " (" + barLine.Message + ")";
}
if (barLine.ContentType == 0) { result += " (" + barLine.Message + ")"; }
result = result.append(barLine.Bold ? ", " + tr("Bold") : "");
result = result.append(barLine.Bold ? ", " + tr("Bold") : "");
result = result.append(barLine.Italic ? ", " + tr("Italic") : "");
return result;
}
@ -738,9 +781,7 @@ void PreferencesWindow::ShowLineParameters(QvBarLine &barLine)
{
finishedLoading = false;
if (!barLine.Family.isEmpty()) {
fontComboBox->setCurrentFont(QFont(barLine.Family));
}
if (!barLine.Family.isEmpty()) { fontComboBox->setCurrentFont(QFont(barLine.Family)); }
// Colors
nsBarFontASB->setValue(barLine.ColorA);
@ -749,10 +790,9 @@ void PreferencesWindow::ShowLineParameters(QvBarLine &barLine)
nsBarFontRSB->setValue(barLine.ColorR);
//
QColor color = QColor::fromRgb(barLine.ColorR, barLine.ColorG, barLine.ColorB, barLine.ColorA);
QString s(QStringLiteral("background: #")
+ ((color.red() < 16) ? "0" : "") + QString::number(color.red(), 16)
+ ((color.green() < 16) ? "0" : "") + QString::number(color.green(), 16)
+ ((color.blue() < 16) ? "0" : "") + QString::number(color.blue(), 16) + ";");
QString s(QStringLiteral("background: #") + ((color.red() < 16) ? "0" : "") + QString::number(color.red(), 16) +
((color.green() < 16) ? "0" : "") + QString::number(color.green(), 16) + ((color.blue() < 16) ? "0" : "") +
QString::number(color.blue(), 16) + ";");
chooseColorBtn->setStyleSheet(s);
nsBarFontSizeSB->setValue(barLine.Size);
nsBarFontBoldCB->setChecked(barLine.Bold);
@ -769,7 +809,8 @@ void PreferencesWindow::on_chooseColorBtn_clicked()
QColorDialog d(QColor::fromRgb(CurrentBarLine.ColorR, CurrentBarLine.ColorG, CurrentBarLine.ColorB, CurrentBarLine.ColorA), this);
d.exec();
if (d.result() == QDialog::DialogCode::Accepted) {
if (d.result() == QDialog::DialogCode::Accepted)
{
d.selectedColor().getRgb(&CurrentBarLine.ColorR, &CurrentBarLine.ColorG, &CurrentBarLine.ColorB, &CurrentBarLine.ColorA);
ShowLineParameters(CurrentBarLine);
SET_LINE_LIST_TEXT
@ -792,9 +833,10 @@ void PreferencesWindow::on_nsBarContentCombo_currentIndexChanged(const QString &
void PreferencesWindow::on_applyNSBarSettingsBtn_clicked()
{
if (QvMessageBoxAsk(this, tr("Apply network toolbar settings"), tr("All other modified settings will be applied as well after this object.") +
NEWLINE +
tr("Do you want to continue?")) == QMessageBox::Yes) {
if (QvMessageBoxAsk(this, tr("Apply network toolbar settings"),
tr("All other modified settings will be applied as well after this object.") + NEWLINE +
tr("Do you want to continue?")) == QMessageBox::Yes)
{
auto conf = GlobalConfig;
conf.toolBarConfig = CurrentConfig.toolBarConfig;
SaveGlobalConfig(conf);
@ -815,7 +857,8 @@ void PreferencesWindow::on_darkThemeCB_stateChanged(int arg1)
#ifdef QV2RAY_USE_BUILTIN_DARKTHEME
themeCombo->setEnabled(arg1 != Qt::Checked);
if (arg1 == Qt::Checked) {
if (arg1 == Qt::Checked)
{
themeCombo->setCurrentIndex(QStyleFactory::keys().indexOf("Fusion"));
CurrentConfig.uiConfig.theme = "Fusion";
}
@ -840,7 +883,8 @@ void PreferencesWindow::on_pacGoBtn_clicked()
LOG(MODULE_PROXY, "Downloading GFWList file.")
bool withProxy = getGFWListWithProxyCB->isChecked();
switch (gfwListCB->currentIndex()) {
switch (gfwListCB->currentIndex())
{
case 0:
gfwLocation = "https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt";
fileContent = QString::fromUtf8(request.syncget(gfwLocation, withProxy));
@ -874,7 +918,8 @@ void PreferencesWindow::on_pacGoBtn_clicked()
case 6:
auto file = QFileDialog::getOpenFileName(this, tr("Select GFWList in base64"));
if (file.isEmpty()) {
if (file.isEmpty())
{
QvMessageBoxWarn(this, tr("Download GFWList"), tr("Operation is cancelled."));
return;
}
@ -888,9 +933,7 @@ void PreferencesWindow::on_pacGoBtn_clicked()
pacGoBtn->setEnabled(true);
gfwListCB->setEnabled(true);
if (!QDir(QV2RAY_RULES_DIR).exists()) {
QDir(QV2RAY_RULES_DIR).mkpath(QV2RAY_RULES_DIR);
}
if (!QDir(QV2RAY_RULES_DIR).exists()) { QDir(QV2RAY_RULES_DIR).mkpath(QV2RAY_RULES_DIR); }
StringToFile(fileContent, QV2RAY_RULES_GFWLIST_PATH);
}
@ -900,7 +943,8 @@ void PreferencesWindow::on_pacPortSB_valueChanged(int arg1)
LOADINGCHECK
NEEDRESTART
CurrentConfig.inboundConfig.pacConfig.port = arg1;
pacListenAddrLabel->setText("http://" + (pacProxyTxt->text().isEmpty() ? "127.0.0.1" : pacProxyTxt->text()) + ":" + QSTRN(pacPortSB->value()) + "/pac");
pacListenAddrLabel->setText("http://" + (pacProxyTxt->text().isEmpty() ? "127.0.0.1" : pacProxyTxt->text()) + ":" +
QSTRN(pacPortSB->value()) + "/pac");
}
void PreferencesWindow::on_setSysProxyCB_stateChanged(int arg1)
@ -939,9 +983,7 @@ void PreferencesWindow::on_autoStartSubsCombo_currentIndexChanged(const QString
auto list = ConnectionManager->Connections(groupId);
autoStartConnCombo->clear();
for (auto id : list) {
autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(id));
}
for (auto id : list) { autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(id)); }
}
void PreferencesWindow::on_autoStartConnCombo_currentIndexChanged(const QString &arg1)
@ -955,9 +997,7 @@ void PreferencesWindow::on_startWithLoginCB_stateChanged(int arg1)
bool isEnabled = arg1 == Qt::Checked;
SetLaunchAtLoginStatus(isEnabled);
if (GetLaunchAtLoginStatus() != isEnabled) {
QvMessageBoxWarn(this, tr("Start with boot"), tr("Failed to set auto start option."));
}
if (GetLaunchAtLoginStatus() != isEnabled) { QvMessageBoxWarn(this, tr("Start with boot"), tr("Failed to set auto start option.")); }
SetAutoStartButtonsState(GetLaunchAtLoginStatus());
}
@ -978,9 +1018,9 @@ void PreferencesWindow::on_fpAddressTx_textEdited(const QString &arg1)
LOADINGCHECK
CurrentConfig.connectionConfig.forwardProxyConfig.serverAddress = arg1;
if (IsValidIPAddress(arg1)) {
BLACK(fpAddressTx)
} else {
if (IsValidIPAddress(arg1)) { BLACK(fpAddressTx) }
else
{
RED(fpAddressTx)
}
}
@ -1021,13 +1061,14 @@ void PreferencesWindow::on_pacProxyTxt_textChanged(const QString &arg1)
{
Q_UNUSED(arg1)
if (IsValidIPAddress(arg1)) {
BLACK(pacProxyTxt)
} else {
if (IsValidIPAddress(arg1)) { BLACK(pacProxyTxt) }
else
{
RED(pacProxyTxt)
}
pacListenAddrLabel->setText("http://" + (pacProxyTxt->text().isEmpty() ? "127.0.0.1" : pacProxyTxt->text()) + ":" + QSTRN(pacPortSB->value()) + "/pac");
pacListenAddrLabel->setText("http://" + (pacProxyTxt->text().isEmpty() ? "127.0.0.1" : pacProxyTxt->text()) + ":" +
QSTRN(pacPortSB->value()) + "/pac");
}
void PreferencesWindow::on_checkVCoreSettings_clicked()
@ -1036,11 +1077,12 @@ void PreferencesWindow::on_checkVCoreSettings_clicked()
auto vAssetsPath = vCoreAssetsPathTxt->text();
QString result;
if (!V2rayKernelInstance::ValidateKernel(vcorePath, vAssetsPath, &result)) {
QvMessageBoxWarn(this, tr("V2ray Core Settings"), result);
} else {
QvMessageBoxInfo(this, tr("V2ray Core Settings"), tr("V2ray path configuration check passed.") + NEWLINE + NEWLINE +
tr("Current version of V2ray is: ") + NEWLINE + result);
if (!V2rayKernelInstance::ValidateKernel(vcorePath, vAssetsPath, &result)) { QvMessageBoxWarn(this, tr("V2ray Core Settings"), result); }
else
{
QvMessageBoxInfo(this, tr("V2ray Core Settings"),
tr("V2ray path configuration check passed.") + NEWLINE + NEWLINE + tr("Current version of V2ray is: ") + NEWLINE +
result);
}
}

View File

@ -1,180 +1,183 @@
#pragma once
#include <QDialog>
#include <ui_w_PreferencesWindow.h>
#include "base/Qv2rayBase.hpp"
#include "ui/messaging/QvMessageBus.hpp"
class PreferencesWindow : public QDialog, private Ui::PreferencesWindow
#include <QDialog>
#include <ui_w_PreferencesWindow.h>
class PreferencesWindow
: public QDialog
, private Ui::PreferencesWindow
{
Q_OBJECT
Q_OBJECT
public:
explicit PreferencesWindow(QWidget *parent = nullptr);
~PreferencesWindow();
signals:
void s_reload_config(bool need_restart);
public:
explicit PreferencesWindow(QWidget *parent = nullptr);
~PreferencesWindow();
signals:
void s_reload_config(bool need_restart);
public slots:
QvMessageBusSlotDecl
public slots:
QvMessageBusSlotDecl;
private slots:
void on_buttonBox_accepted();
private slots:
void on_buttonBox_accepted();
void on_httpAuthCB_stateChanged(int arg1);
void on_httpAuthCB_stateChanged(int arg1);
void on_socksAuthCB_stateChanged(int arg1);
void on_socksAuthCB_stateChanged(int arg1);
void on_languageComboBox_currentTextChanged(const QString &arg1);
void on_languageComboBox_currentTextChanged(const QString &arg1);
void on_logLevelComboBox_currentIndexChanged(int index);
void on_logLevelComboBox_currentIndexChanged(int index);
void on_vCoreAssetsPathTxt_textEdited(const QString &arg1);
void on_vCoreAssetsPathTxt_textEdited(const QString &arg1);
void on_listenIPTxt_textEdited(const QString &arg1);
void on_listenIPTxt_textEdited(const QString &arg1);
void on_socksPortLE_valueChanged(int arg1);
void on_socksPortLE_valueChanged(int arg1);
void on_httpPortLE_valueChanged(int arg1);
void on_httpPortLE_valueChanged(int arg1);
void on_httpAuthUsernameTxt_textEdited(const QString &arg1);
void on_httpAuthUsernameTxt_textEdited(const QString &arg1);
void on_httpAuthPasswordTxt_textEdited(const QString &arg1);
void on_httpAuthPasswordTxt_textEdited(const QString &arg1);
void on_socksAuthUsernameTxt_textEdited(const QString &arg1);
void on_socksAuthUsernameTxt_textEdited(const QString &arg1);
void on_socksAuthPasswordTxt_textEdited(const QString &arg1);
void on_socksAuthPasswordTxt_textEdited(const QString &arg1);
void on_proxyDefaultCb_stateChanged(int arg1);
void on_proxyDefaultCb_stateChanged(int arg1);
void on_localDNSCb_stateChanged(int arg1);
void on_localDNSCb_stateChanged(int arg1);
void on_selectVAssetBtn_clicked();
void on_selectVAssetBtn_clicked();
void on_DNSListTxt_textChanged();
void on_DNSListTxt_textChanged();
void on_aboutQt_clicked();
void on_aboutQt_clicked();
void on_cancelIgnoreVersionBtn_clicked();
void on_cancelIgnoreVersionBtn_clicked();
void on_tProxyCheckBox_stateChanged(int arg1);
void on_tProxyCheckBox_stateChanged(int arg1);
void on_bypassCNCb_stateChanged(int arg1);
void on_bypassCNCb_stateChanged(int arg1);
void on_statsPortBox_valueChanged(int arg1);
void on_statsPortBox_valueChanged(int arg1);
void on_socksUDPCB_stateChanged(int arg1);
void on_socksUDPCB_stateChanged(int arg1);
void on_socksUDPIP_textEdited(const QString &arg1);
void on_socksUDPIP_textEdited(const QString &arg1);
void on_nsBarPageAddBTN_clicked();
void on_nsBarPageAddBTN_clicked();
void on_nsBarPageDelBTN_clicked();
void on_nsBarPageDelBTN_clicked();
void on_nsBarPageYOffset_valueChanged(int arg1);
void on_nsBarPageYOffset_valueChanged(int arg1);
void on_nsBarLineAddBTN_clicked();
void on_nsBarLineAddBTN_clicked();
void on_nsBarLineDelBTN_clicked();
void on_nsBarLineDelBTN_clicked();
void on_nsBarPagesList_currentRowChanged(int currentRow);
void on_nsBarPagesList_currentRowChanged(int currentRow);
void on_nsBarLinesList_currentRowChanged(int currentRow);
void on_nsBarLinesList_currentRowChanged(int currentRow);
void on_fontComboBox_currentFontChanged(const QFont &f);
void on_fontComboBox_currentFontChanged(const QFont &f);
void on_nsBarFontBoldCB_stateChanged(int arg1);
void on_nsBarFontBoldCB_stateChanged(int arg1);
void on_nsBarFontItalicCB_stateChanged(int arg1);
void on_nsBarFontItalicCB_stateChanged(int arg1);
void on_nsBarFontASB_valueChanged(int arg1);
void on_nsBarFontASB_valueChanged(int arg1);
void on_nsBarFontRSB_valueChanged(int arg1);
void on_nsBarFontRSB_valueChanged(int arg1);
void on_nsBarFontGSB_valueChanged(int arg1);
void on_nsBarFontGSB_valueChanged(int arg1);
void on_nsBarFontBSB_valueChanged(int arg1);
void on_nsBarFontBSB_valueChanged(int arg1);
void on_nsBarFontSizeSB_valueChanged(double arg1);
void on_nsBarFontSizeSB_valueChanged(double arg1);
void on_chooseColorBtn_clicked();
void on_chooseColorBtn_clicked();
void on_nsBarTagTxt_textEdited(const QString &arg1);
void on_nsBarTagTxt_textEdited(const QString &arg1);
void on_nsBarContentCombo_currentIndexChanged(const QString &arg1);
void on_nsBarContentCombo_currentIndexChanged(const QString &arg1);
void on_applyNSBarSettingsBtn_clicked();
void on_applyNSBarSettingsBtn_clicked();
void on_selectVCoreBtn_clicked();
void on_selectVCoreBtn_clicked();
void on_vCorePathTxt_textEdited(const QString &arg1);
void on_vCorePathTxt_textEdited(const QString &arg1);
void on_themeCombo_currentTextChanged(const QString &arg1);
void on_themeCombo_currentTextChanged(const QString &arg1);
void on_darkThemeCB_stateChanged(int arg1);
void on_darkThemeCB_stateChanged(int arg1);
void on_darkTrayCB_stateChanged(int arg1);
void on_darkTrayCB_stateChanged(int arg1);
void on_pacGoBtn_clicked();
void on_pacGoBtn_clicked();
void on_pacPortSB_valueChanged(int arg1);
void on_pacPortSB_valueChanged(int arg1);
void on_setSysProxyCB_stateChanged(int arg1);
void on_setSysProxyCB_stateChanged(int arg1);
void on_pacProxyCB_currentIndexChanged(int index);
void on_pacProxyCB_currentIndexChanged(int index);
void on_pushButton_clicked();
void on_pushButton_clicked();
void on_pacProxyTxt_textEdited(const QString &arg1);
void on_pacProxyTxt_textEdited(const QString &arg1);
void on_autoStartSubsCombo_currentIndexChanged(const QString &arg1);
void on_autoStartSubsCombo_currentIndexChanged(const QString &arg1);
void on_autoStartConnCombo_currentIndexChanged(const QString &arg1);
void on_autoStartConnCombo_currentIndexChanged(const QString &arg1);
void on_fpTypeCombo_currentIndexChanged(const QString &arg1);
void on_fpTypeCombo_currentIndexChanged(const QString &arg1);
void on_fpAddressTx_textEdited(const QString &arg1);
void on_fpAddressTx_textEdited(const QString &arg1);
void on_spPortSB_valueChanged(int arg1);
void on_spPortSB_valueChanged(int arg1);
void on_fpUseAuthCB_stateChanged(int arg1);
void on_fpUseAuthCB_stateChanged(int arg1);
void on_fpUsernameTx_textEdited(const QString &arg1);
void on_fpUsernameTx_textEdited(const QString &arg1);
void on_fpPasswordTx_textEdited(const QString &arg1);
void on_fpPasswordTx_textEdited(const QString &arg1);
void on_fpPortSB_valueChanged(int arg1);
void on_fpPortSB_valueChanged(int arg1);
void on_pacProxyTxt_textChanged(const QString &arg1);
void on_pacProxyTxt_textChanged(const QString &arg1);
void on_checkVCoreSettings_clicked();
void on_checkVCoreSettings_clicked();
void on_httpGroupBox_clicked(bool checked);
void on_httpGroupBox_clicked(bool checked);
void on_socksGroupBox_clicked(bool checked);
void on_socksGroupBox_clicked(bool checked);
void on_pacGroupBox_clicked(bool checked);
void on_pacGroupBox_clicked(bool checked);
void on_fpGroupBox_clicked(bool checked);
void on_fpGroupBox_clicked(bool checked);
void on_maxLogLinesSB_valueChanged(int arg1);
void on_maxLogLinesSB_valueChanged(int arg1);
void on_enableAPI_stateChanged(int arg1);
void on_enableAPI_stateChanged(int arg1);
void on_startWithLoginCB_stateChanged(int arg1);
void on_startWithLoginCB_stateChanged(int arg1);
void on_tProxyGroupBox_clicked(bool checked);
void on_tProxyGroupBox_clicked(bool checked);
private:
void SetAutoStartButtonsState(bool isAutoStart);
// Set ui parameters for a line;
void ShowLineParameters(QvBarLine &line);
QString GetBarLineDescription(QvBarLine line);
//
int CurrentBarLineId;
int CurrentBarPageId;
//
bool IsConnectionPropertyChanged = false;
bool finishedLoading = false;
Qv2rayConfig CurrentConfig;
private:
void SetAutoStartButtonsState(bool isAutoStart);
// Set ui parameters for a line;
void ShowLineParameters(QvBarLine &line);
QString GetBarLineDescription(QvBarLine line);
//
int CurrentBarLineId;
int CurrentBarPageId;
//
bool IsConnectionPropertyChanged = false;
bool finishedLoading = false;
Qv2rayConfig CurrentConfig;
};

View File

@ -1,15 +1,18 @@
#include "w_ScreenShot_Core.hpp"
#include "common/QvHelpers.hpp"
#include <QMessageBox>
#include <QThread>
#include <QStyleFactory>
#include <QThread>
#define QV2RAY_SCREENSHOT_DIM_RATIO 0.6f
ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubberBand::Rectangle, this))
{
setupUi(this);
// Fusion prevents the KDE Plasma Breeze's "Move window when dragging in the empty area" issue
// Fusion prevents the KDE Plasma Breeze's "Move window when dragging in the
// empty area" issue
this->setStyle(QStyleFactory::create("Fusion"));
//
label->setAttribute(Qt::WA_TranslucentBackground);
@ -30,8 +33,9 @@ ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubber
QImage ScreenShotWindow::DoScreenShot()
{
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
// 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);
QApplication::processEvents();
//
@ -45,8 +49,10 @@ QImage ScreenShotWindow::DoScreenShot()
int r, g, b;
auto _xdesktopImg = desktopImage.toImage();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
r = static_cast<int>(qRed(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
g = static_cast<int>(qGreen(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
b = static_cast<int>(qBlue(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
@ -72,16 +78,18 @@ void ScreenShotWindow::pSize()
imgH = abs(end.y() - origin.y());
imgX = origin.x() < end.x() ? origin.x() : end.x();
imgY = origin.y() < end.y() ? origin.y() : end.y();
DEBUG("Capture Mouse Position", QSTRN(imgW) + " " + QSTRN(imgH) + " " + QSTRN(imgX) + " " + QSTRN(imgY))
DEBUG("Capture Mouse Position", QSTRN(imgW) + " " + QSTRN(imgH) + " " + QSTRN(imgX) + " " + QSTRN(imgY))
rubber->setGeometry(imgX, imgY, imgW, imgH);
fg->setGeometry(rubber->geometry());
auto copied = desktopImage.copy(fg->x() * devicePixelRatio(), fg->y() * devicePixelRatio(), fg->width() * devicePixelRatio(), fg->height() * devicePixelRatio());
auto copied = desktopImage.copy(fg->x() * devicePixelRatio(), fg->y() * devicePixelRatio(), fg->width() * devicePixelRatio(),
fg->height() * devicePixelRatio());
fg->setPixmap(copied);
}
bool ScreenShotWindow::event(QEvent *e)
{
if (e->type() == QEvent::Move) {
if (e->type() == QEvent::Move)
{
//
}
@ -90,9 +98,9 @@ bool ScreenShotWindow::event(QEvent *e)
void ScreenShotWindow::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Escape) {
reject();
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (e->key() == Qt::Key_Escape) { reject(); }
else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
{
on_startBtn_clicked();
}
}
@ -103,13 +111,14 @@ void ScreenShotWindow::mousePressEvent(QMouseEvent *e)
rubber->setGeometry(origin.x(), origin.y(), 0, 0);
rubber->show();
rubber->raise();
//label->hide();
//startBtn->hide();
// label->hide();
// startBtn->hide();
}
void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
{
if (e->buttons() & Qt::LeftButton) {
if (e->buttons() & Qt::LeftButton)
{
end = e->pos();
pSize();
//
@ -120,15 +129,15 @@ void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
QRect labelRect(label->contentsRect());
QRect btnRect(startBtn->contentsRect());
if (imgY > labelRect.height()) {
label->move(imgX, imgY - labelRect.height());
} else {
if (imgY > labelRect.height()) { label->move(imgX, imgY - labelRect.height()); }
else
{
label->move(imgX, imgY);
}
if (height() - imgY - imgH > btnRect.height()) {
startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH);
} else {
if (height() - imgY - imgH > btnRect.height()) { startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH); }
else
{
startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH - btnRect.height());
}
@ -137,12 +146,9 @@ void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
}
}
void ScreenShotWindow::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() == Qt::RightButton) {
reject();
}
if (e->button() == Qt::RightButton) { reject(); }
}
ScreenShotWindow::~ScreenShotWindow()

View File

@ -1,46 +1,48 @@
#pragma once
#include <QDialog>
#include <QRubberBand>
#include <QImage>
#include <QLabel>
#include <QMouseEvent>
#include <QScreen>
#include <QKeyEvent>
#include <QPushButton>
#include <QPalette>
#include "ui_w_ScreenShot_Core.h"
class ScreenShotWindow : public QDialog, private Ui::ScreenShot
#include <QDialog>
#include <QImage>
#include <QKeyEvent>
#include <QLabel>
#include <QMouseEvent>
#include <QPalette>
#include <QPushButton>
#include <QRubberBand>
#include <QScreen>
class ScreenShotWindow
: public QDialog
, private Ui::ScreenShot
{
Q_OBJECT
Q_OBJECT
public:
ScreenShotWindow();
~ScreenShotWindow();
QImage DoScreenShot();
//
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
public:
ScreenShotWindow();
~ScreenShotWindow();
QImage DoScreenShot();
//
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
protected:
bool event(QEvent *e) override;
protected:
bool event(QEvent *e) override;
private slots:
void on_startBtn_clicked();
private slots:
void on_startBtn_clicked();
private:
QRubberBand *rubber;
// Desktop Image
QPixmap desktopImage;
QImage windowBg;
QImage resultImage;
//
QPoint origin;
QPoint end;
int imgW, imgH, imgX, imgY;
private:
QRubberBand *rubber;
// Desktop Image
QPixmap desktopImage;
QImage windowBg;
QImage resultImage;
//
QPoint origin;
QPoint end;
int imgW, imgH, imgX, imgY;
void pSize();
void pSize();
};

View File

@ -1,33 +1,31 @@
#include "w_SubscriptionManager.hpp"
#include "common/QvHelpers.hpp"
#include "core/config/ConfigBackend.hpp"
#include "core/handler/ConnectionHandler.hpp"
SubscribeEditor::SubscribeEditor(QWidget *parent) :
QDialog(parent)
SubscribeEditor::SubscribeEditor(QWidget *parent) : QDialog(parent)
{
setupUi(this);
QvMessageBusConnect(SubscribeEditor);
addSubsButton->setIcon(QICON_R("add.png"));
removeSubsButton->setIcon(QICON_R("delete.png"));
for (auto subs : ConnectionManager->Subscriptions()) {
subscriptionList->addTopLevelItem(new QTreeWidgetItem(QStringList() << ConnectionManager->GetDisplayName(subs) << subs.toString()));
}
for (auto subs : ConnectionManager->Subscriptions())
{ subscriptionList->addTopLevelItem(new QTreeWidgetItem(QStringList() << ConnectionManager->GetDisplayName(subs) << subs.toString())); }
}
QvMessageBusSlotImpl(SubscribeEditor)
{
switch (msg) {
MBShowDefaultImpl
MBHideDefaultImpl
MBRetranslateDefaultImpl
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
}
}
QPair<QString, CONFIGROOT> SubscribeEditor::GetSelectedConfig()
{
return QPair<QString, CONFIGROOT> ();
return QPair<QString, CONFIGROOT>();
}
SubscribeEditor::~SubscribeEditor()
@ -46,22 +44,26 @@ void SubscribeEditor::on_addSubsButton_clicked()
void SubscribeEditor::on_updateButton_clicked()
{
//auto newName = subNameTxt->text().trimmed();
//auto newAddress = subAddrTxt->text().trimmed();
//auto newUpdateInterval = updateIntervalSB->value();
//if (currentSubId != newName) {
ConnectionManager->UpdateSubscription(currentSubId, withProxyCB->isChecked());
// auto newName = subNameTxt->text().trimmed();
// auto newAddress = subAddrTxt->text().trimmed();
// auto newUpdateInterval = updateIntervalSB->value();
// if (currentSubId != newName) {
// // Rename needed.
// LOG(MODULE_SUBSCRIPTION, "Renaming a subscription, from " + currentSubId + " to: " + newName)
// bool canGo = true;
// LOG(MODULE_SUBSCRIPTION, "Renaming a subscription, from " +
// currentSubId + " to: " + newName) bool canGo = true;
//
// if (newName.isEmpty() || !IsValidFileName(newName)) {
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("The subscription name is invalid, please try another."));
// canGo = false;
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("The
// subscription name is invalid, please try another.")); canGo =
// false;
// }
//
// if (subscriptionList->findItems(newName, Qt::MatchExactly).count() > 0) {
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("New name of this subscription has been used already, please suggest another one"));
// canGo = false;
// if (subscriptionList->findItems(newName, Qt::MatchExactly).count() >
// 0) {
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("New name
// of this subscription has been used already, please suggest another
// one")); canGo = false;
// }
//
// if (!canGo) {
@ -72,7 +74,8 @@ void SubscribeEditor::on_updateButton_clicked()
// ////bool result = RenameSubscription(currentSubName, newName);
// //
// //if (!result) {
// // QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("Failed to rename a subscription, this is an unknown error."));
// // QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("Failed
// to rename a subscription, this is an unknown error."));
// // return;
// //}
// subscriptions[newName] = subscriptions[currentSubId];
@ -93,68 +96,45 @@ void SubscribeEditor::on_updateButton_clicked()
// // Update thing still down
// subAddrTxt->setText(newAddress);
// updateIntervalSB->setValue(newUpdateInterval);
// QvMessageBoxInfo(this, tr("Renaming a subscription"), tr("Successfully renamed a subscription"));
// QvMessageBoxInfo(this, tr("Renaming a subscription"), tr("Successfully
// renamed a subscription"));
//}
//
//subscriptions[currentSubId].updateInterval = newUpdateInterval;
// subscriptions[currentSubId].updateInterval = newUpdateInterval;
//
//if (subscriptions[currentSubId].address != newAddress) {
// LOG(MODULE_SUBSCRIPTION, "Setting new address, from " + subscriptions[currentSubId].address + " to: " + newAddress)
// if (subscriptions[currentSubId].address != newAddress) {
// LOG(MODULE_SUBSCRIPTION, "Setting new address, from " +
// subscriptions[currentSubId].address + " to: " + newAddress)
// subscriptions[currentSubId].address = newAddress;
//}
//
////SaveConfig();
//
////if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like to reload this subscription from the Url?")) == QMessageBox::Yes) {
//// StartUpdateSubscription(currentSubId);
////if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like
/// to reload this subscription from the Url?")) == QMessageBox::Yes) { /
/// StartUpdateSubscription(currentSubId);
////}
}
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(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."));
//}
//
// auto data = helper.syncget(subscriptions[subscriptionName].address,
// withProxyCB->isChecked()); auto content =
this->setEnabled(true);
}
void SubscribeEditor::on_removeSubsButton_clicked()
{
//if (subscriptionList->currentRow() < 0)
// if (subscriptionList->currentRow() < 0)
// return;
//
//auto name = subscriptionList->currentItem()->text();
//subscriptionList->takeItem(subscriptionList->currentRow());
//subscriptions.remove(name);
// auto name = subscriptionList->currentItem()->text();
// subscriptionList->takeItem(subscriptionList->currentRow());
// subscriptions.remove(name);
//
//if (!name.isEmpty()) {
// if (!name.isEmpty()) {
// QDir(QV2RAY_SUBSCRIPTION_DIR + name).removeRecursively();
//}
//
@ -163,22 +143,22 @@ void SubscribeEditor::on_removeSubsButton_clicked()
//// GlobalConfig.autoStartConfig = QvConnectionObject();
//// SaveGlobalConfig(GlobalConfig);
////}
//groupBox_2->setEnabled(subscriptionList->count() > 0);
//SaveConfig();
// groupBox_2->setEnabled(subscriptionList->count() > 0);
// SaveConfig();
}
void SubscribeEditor::SaveConfig()
{
//QMap<QString, SubscriptionObject_Config> newConf;
// QMap<QString, SubscriptionObject_Config> newConf;
//
//for (auto _ : subscriptions.toStdMap()) {
// for (auto _ : subscriptions.toStdMap()) {
// if (!_.second.address.isEmpty()) {
// newConf[_.first] = _.second;
// }
//}
//
//GlobalConfig.subscriptions = newConf;
//SaveGlobalConfig(GlobalConfig);
// GlobalConfig.subscriptions = newConf;
// SaveGlobalConfig(GlobalConfig);
}
void SubscribeEditor::on_buttonBox_accepted()
@ -195,9 +175,7 @@ void SubscribeEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int
{
Q_UNUSED(column)
if (item == nullptr) {
return;
}
if (item == nullptr) { return; }
currentSubId = GroupId(item->text(1));
//
@ -209,7 +187,5 @@ void SubscribeEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int
//
connectionsList->clear();
for (auto conn : ConnectionManager->Connections(currentSubId)) {
connectionsList->addItem(ConnectionManager->GetDisplayName(conn));
}
for (auto conn : ConnectionManager->Connections(currentSubId)) { connectionsList->addItem(ConnectionManager->GetDisplayName(conn)); }
}

View File

@ -1,40 +1,43 @@
#pragma once
#include <QDialog>
#include "base/Qv2rayBase.hpp"
#include "ui_w_SubscriptionManager.h"
#include "ui/messaging/QvMessageBus.hpp"
#include "core/CoreSafeTypes.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui_w_SubscriptionManager.h"
class SubscribeEditor : public QDialog, private Ui::w_SubscribeEditor
#include <QDialog>
class SubscribeEditor
: public QDialog
, private Ui::w_SubscribeEditor
{
Q_OBJECT
Q_OBJECT
public:
explicit SubscribeEditor(QWidget *parent = nullptr);
~SubscribeEditor();
QPair<QString, CONFIGROOT> GetSelectedConfig();
public:
explicit SubscribeEditor(QWidget *parent = nullptr);
~SubscribeEditor();
QPair<QString, CONFIGROOT> GetSelectedConfig();
public slots:
QvMessageBusSlotDecl
public slots:
QvMessageBusSlotDecl;
private slots:
void on_addSubsButton_clicked();
private slots:
void on_addSubsButton_clicked();
void on_updateButton_clicked();
void on_updateButton_clicked();
void on_removeSubsButton_clicked();
void on_removeSubsButton_clicked();
void on_buttonBox_accepted();
void on_buttonBox_accepted();
void on_subscriptionList_itemSelectionChanged();
void on_subscriptionList_itemSelectionChanged();
void on_subscriptionList_itemClicked(QTreeWidgetItem *item, int column);
void on_subscriptionList_itemClicked(QTreeWidgetItem *item, int column);
private:
void StartUpdateSubscription(const QString &subscriptionName);
void SaveConfig();
private:
void StartUpdateSubscription(const QString &subscriptionName);
void SaveConfig();
bool isUpdateInProgress = false;
GroupId currentSubId = NullGroupId;
bool isUpdateInProgress = false;
GroupId currentSubId = NullGroupId;
};

View File

@ -1,9 +1,10 @@
#include "ConnectionInfoWidget.hpp"
#include "3rdparty/qzxing/src/QZXing.h"
#include "core/CoreUtils.hpp"
#include "core/connection/Serialization.hpp"
#include "3rdparty/qzxing/src/QZXing.h"
ConnectionInfoWidget::ConnectionInfoWidget(QWidget *parent): QWidget(parent)
ConnectionInfoWidget::ConnectionInfoWidget(QWidget *parent) : QWidget(parent)
{
setupUi(this);
duplicateBtn->setIcon(QICON_R("duplicate.png"));
@ -12,7 +13,8 @@ ConnectionInfoWidget::ConnectionInfoWidget(QWidget *parent): QWidget(parent)
editJsonBtn->setIcon(QICON_R("json.png"));
//
shareLinkTxt->setAutoFillBackground(true);
shareLinkTxt->setStyleSheet("border-bottom: 1px solid gray; border-radius: 0px; padding: 2px; background-color: " + this->palette().color(this->backgroundRole()).name(QColor::HexRgb));
shareLinkTxt->setStyleSheet("border-bottom: 1px solid gray; border-radius: 0px; padding: 2px; background-color: " +
this->palette().color(this->backgroundRole()).name(QColor::HexRgb));
shareLinkTxt->setCursor(QCursor(Qt::CursorShape::IBeamCursor));
shareLinkTxt->installEventFilter(this);
//
@ -30,10 +32,12 @@ void ConnectionInfoWidget::ShowDetails(const tuple<GroupId, ConnectionId> &_iden
duplicateBtn->setEnabled(isConnection);
editBtn->setEnabled(isConnection);
if (isConnection) {
if (isConnection)
{
groupLabel->setText(ConnectionManager->GetDisplayName(groupId, 175));
protocolLabel->setText(ConnectionManager->GetConnectionProtocolString(connectionId));
auto [host, port] = ConnectionManager->GetConnectionInfo(connectionId);
auto [protocol, host, port] = ConnectionManager->GetConnectionData(connectionId);
Q_UNUSED(protocol)
addressLabel->setText(host);
portLabel->setNum(port);
//
@ -48,7 +52,9 @@ void ConnectionInfoWidget::ShowDetails(const tuple<GroupId, ConnectionId> &_iden
qrLabel->setPixmap(QPixmap::fromImage(img));
//
connectBtn->setIcon(ConnectionManager->IsConnected(connectionId) ? QICON_R("stop.png") : QICON_R("connect.png"));
} else {
}
else
{
connectBtn->setIcon(QICON_R("connect.png"));
groupLabel->setText(tr("N/A"));
protocolLabel->setText(tr("N/A"));
@ -66,9 +72,9 @@ ConnectionInfoWidget::~ConnectionInfoWidget()
void ConnectionInfoWidget::on_connectBtn_clicked()
{
if (ConnectionManager->IsConnected(connectionId)) {
ConnectionManager->StopConnection();
} else {
if (ConnectionManager->IsConnected(connectionId)) { ConnectionManager->StopConnection(); }
else
{
ConnectionManager->StartConnection(connectionId);
}
}
@ -90,11 +96,11 @@ void ConnectionInfoWidget::on_deleteBtn_clicked()
bool ConnectionInfoWidget::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::MouseButtonRelease) {
if (shareLinkTxt->underMouse()) {
if (!shareLinkTxt->hasSelectedText()) {
shareLinkTxt->selectAll();
}
if (event->type() == QEvent::MouseButtonRelease)
{
if (shareLinkTxt->underMouse())
{
if (!shareLinkTxt->hasSelectedText()) { shareLinkTxt->selectAll(); }
}
}
@ -103,51 +109,50 @@ bool ConnectionInfoWidget::eventFilter(QObject *object, QEvent *event)
void ConnectionInfoWidget::OnConnected(const ConnectionId &id)
{
if (connectionId == id) {
connectBtn->setIcon(QICON_R("stop.png"));
}
if (connectionId == id) { connectBtn->setIcon(QICON_R("stop.png")); }
}
void ConnectionInfoWidget::OnDisConnected(const ConnectionId &id)
{
if (connectionId == id) {
connectBtn->setIcon(QICON_R("connect.png"));
}
if (connectionId == id) { connectBtn->setIcon(QICON_R("connect.png")); }
}
//MWTryPingConnection(CurrentConnectionIdentifier);
// MWTryPingConnection(CurrentConnectionIdentifier);
void ConnectionInfoWidget::on_duplicateBtn_clicked()
{
//QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
//if (!IsSelectionConnectable) {
// QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
// if (!IsSelectionConnectable) {
// return;
//}
//
//auto selectedFirst = connectionListWidget->currentItem();
//auto _identifier = ItemConnectionIdentifier(selectedFirst);
//SUBSCRIPTION_CONFIG_MODIFY_ASK(selectedFirst)
//CONFIGROOT conf;
// auto selectedFirst = connectionListWidget->currentItem();
// auto _identifier = ItemConnectionIdentifier(selectedFirst);
// SUBSCRIPTION_CONFIG_MODIFY_ASK(selectedFirst)
// CONFIGROOT conf;
//// Alias may change.
//QString alias = _identifier.connectionName;
//bool isComplex = IsComplexConfig(connections[_identifier].config);
// QString alias = _identifier.connectionName;
// bool isComplex = IsComplexConfig(connections[_identifier].config);
//
//if (connections[_identifier].configType == CONNECTION_REGULAR) {
// conf = ConvertConfigFromFile(QV2RAY_CONFIG_DIR + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
// if (connections[_identifier].configType == CONNECTION_REGULAR) {
// conf = ConvertConfigFromFile(QV2RAY_CONFIG_DIR +
// _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
//} else {
// conf = ConvertConfigFromFile(QV2RAY_SUBSCRIPTION_DIR + _identifier.subscriptionName + "/" + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
// alias = _identifier.subscriptionName + "_" + _identifier.connectionName;
// conf = ConvertConfigFromFile(QV2RAY_SUBSCRIPTION_DIR +
// _identifier.subscriptionName + "/" + _identifier.connectionName +
// QV2RAY_CONFIG_FILE_EXTENSION, isComplex); alias =
// _identifier.subscriptionName + "_" + _identifier.connectionName;
//}
//
//SaveConnectionConfig(conf, &alias, false);
//GlobalConfig.configs.push_back(alias);
//SaveGlobalConfig(GlobalConfig);
//this->OnConfigListChanged(false);}
// SaveConnectionConfig(conf, &alias, false);
// GlobalConfig.configs.push_back(alias);
// SaveGlobalConfig(GlobalConfig);
// this->OnConfigListChanged(false);}
}
void ConnectionInfoWidget::on_latencyBtn_clicked()
{
if (connectionId != NullConnectionId) {
ConnectionManager->StartLatencyTest(connectionId);
} else {
if (connectionId != NullConnectionId) { ConnectionManager->StartLatencyTest(connectionId); }
else
{
ConnectionManager->StartLatencyTest(groupId);
}
}

View File

@ -1,39 +1,41 @@
#pragma once
#include <QWidget>
#include "ui_ConnectionInfoWidget.h"
#include "core/handler/ConnectionHandler.hpp"
#include "ui_ConnectionInfoWidget.h"
class ConnectionInfoWidget : public QWidget, private Ui::ConnectionInfoWidget
#include <QWidget>
class ConnectionInfoWidget
: public QWidget
, private Ui::ConnectionInfoWidget
{
Q_OBJECT
Q_OBJECT
public:
explicit ConnectionInfoWidget(QWidget *parent = nullptr);
void ShowDetails(const tuple<GroupId, ConnectionId> &_identifier);
~ConnectionInfoWidget();
public:
explicit ConnectionInfoWidget(QWidget *parent = nullptr);
void ShowDetails(const tuple<GroupId, ConnectionId> &_identifier);
~ConnectionInfoWidget();
signals:
void OnEditRequested(const ConnectionId &id);
void OnJsonEditRequested(const ConnectionId &id);
signals:
void OnEditRequested(const ConnectionId &id);
void OnJsonEditRequested(const ConnectionId &id);
private slots:
void on_connectBtn_clicked();
void on_editBtn_clicked();
void on_editJsonBtn_clicked();
void on_deleteBtn_clicked();
private slots:
void on_connectBtn_clicked();
void on_editBtn_clicked();
void on_editJsonBtn_clicked();
void on_deleteBtn_clicked();
protected:
bool eventFilter(QObject *object, QEvent *event) override;
protected:
bool eventFilter(QObject *object, QEvent *event) override;
private slots:
void OnConnected(const ConnectionId &id);
void OnDisConnected(const ConnectionId &id);
void on_duplicateBtn_clicked();
void on_latencyBtn_clicked();
private slots:
void OnConnected(const ConnectionId &id);
void OnDisConnected(const ConnectionId &id);
void on_duplicateBtn_clicked();
void on_latencyBtn_clicked();
private:
ConnectionId connectionId = NullConnectionId;
GroupId groupId = NullGroupId;
private:
ConnectionId connectionId = NullConnectionId;
GroupId groupId = NullGroupId;
};

Some files were not shown because too many files have changed in this diff Show More