mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-19 02:10:28 +08:00
fix: update code style
This commit is contained in:
parent
194f07c027
commit
09de96efe5
306
Qv2ray.astylerc
306
Qv2ray.astylerc
@ -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 pad‑paren,
|
||||
# pad‑paren‑out, pad‑paren‑in, and pad‑header 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 pad‑paren‑in to retain the inside padding. Using only
|
||||
# pad‑paren‑in 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
50
_clang-format
Normal 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
|
||||
|
||||
...
|
@ -1 +1 @@
|
||||
4014
|
||||
4031
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -5,8 +5,9 @@
|
||||
|
||||
namespace Qv2ray::base
|
||||
{
|
||||
struct Qv2rayRuntimeConfig {
|
||||
struct Qv2rayRuntimeConfig
|
||||
{
|
||||
//
|
||||
bool screenShotHideQv2ray = false;
|
||||
};
|
||||
}
|
||||
} // namespace Qv2ray::base
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
284
src/main.cpp
284
src/main.cpp
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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); }
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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)); }
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user