mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-19 10:20:49 +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
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/models/QvConfigModel.hpp"
|
||||||
#include "base/models/QvRuntimeConfig.hpp"
|
#include "base/models/QvRuntimeConfig.hpp"
|
||||||
#include "base/models/QvStartupConfig.hpp"
|
#include "base/models/QvStartupConfig.hpp"
|
||||||
#include "base/models/QvConfigModel.hpp"
|
|
||||||
|
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
||||||
@ -18,4 +18,4 @@ namespace Qv2ray
|
|||||||
inline base::QvStartupOptions StartupOption = base::QvStartupOptions();
|
inline base::QvStartupOptions StartupOption = base::QvStartupOptions();
|
||||||
//
|
//
|
||||||
inline std::unique_ptr<QTranslator> Qv2rayTranslator;
|
inline std::unique_ptr<QTranslator> Qv2rayTranslator;
|
||||||
}
|
} // namespace Qv2ray
|
||||||
|
@ -1,42 +1,42 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define STRINGIZE(arg) STRINGIZE1(arg)
|
#define STRINGIZE(arg) STRINGIZE1(arg)
|
||||||
#define STRINGIZE1(arg) STRINGIZE2(arg)
|
#define STRINGIZE1(arg) STRINGIZE2(arg)
|
||||||
#define STRINGIZE2(arg) #arg
|
#define STRINGIZE2(arg) #arg
|
||||||
|
|
||||||
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
|
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
|
||||||
#define CONCATENATE2(arg1, arg2) arg1##arg2
|
#define CONCATENATE2(arg1, arg2) arg1##arg2
|
||||||
|
|
||||||
#define EXPAND(x) x
|
#define EXPAND(x) x
|
||||||
#define FOR_EACH_1(what, x, ...) what(x)
|
#define FOR_EACH_1(what, x, ...) what(x)
|
||||||
|
|
||||||
#define FOR_EACH_2(what, x, ...)\
|
#define FOR_EACH_2(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
|
||||||
#define FOR_EACH_3(what, x, ...)\
|
#define FOR_EACH_3(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
|
||||||
#define FOR_EACH_4(what, x, ...)\
|
#define FOR_EACH_4(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
|
||||||
#define FOR_EACH_5(what, x, ...)\
|
#define FOR_EACH_5(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
|
||||||
#define FOR_EACH_6(what, x, ...)\
|
#define FOR_EACH_6(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
|
||||||
#define FOR_EACH_7(what, x, ...)\
|
#define FOR_EACH_7(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
|
||||||
#define FOR_EACH_8(what, x, ...)\
|
#define FOR_EACH_8(what, x, ...) \
|
||||||
what(x);\
|
what(x); \
|
||||||
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
|
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
|
||||||
|
|
||||||
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
|
#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_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_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 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_(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 FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
|
||||||
#define JADDEx_(jsonObj, field) jsonObj.insert(#field, field);
|
#define JADDEx_(jsonObj, field) jsonObj.insert(#field, field);
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
//
|
//
|
||||||
#ifndef XTOSTRUCT_QT
|
#ifndef XTOSTRUCT_QT
|
||||||
# define XTOSTRUCT_QT
|
#define XTOSTRUCT_QT
|
||||||
#endif
|
#endif
|
||||||
//
|
//
|
||||||
#include <QtCore>
|
|
||||||
#include <QtGui>
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <vector>
|
#include <QtCore>
|
||||||
|
#include <QtGui>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
// Base support.
|
// Base support.
|
||||||
#include "base/Qv2rayLog.hpp"
|
|
||||||
#include "base/Qv2rayFeatures.hpp"
|
|
||||||
#include "base/JsonHelpers.hpp"
|
|
||||||
#include "base/GlobalInstances.hpp"
|
#include "base/GlobalInstances.hpp"
|
||||||
|
#include "base/JsonHelpers.hpp"
|
||||||
|
#include "base/Qv2rayFeatures.hpp"
|
||||||
|
#include "base/Qv2rayLog.hpp"
|
||||||
// Code Models
|
// Code Models
|
||||||
#include "base/models/QvSafeType.hpp"
|
|
||||||
#include "base/models/CoreObjectModels.hpp"
|
#include "base/models/CoreObjectModels.hpp"
|
||||||
#include "base/models/QvConfigModel.hpp"
|
|
||||||
#include "base/models/QvConfigIdentifier.hpp"
|
#include "base/models/QvConfigIdentifier.hpp"
|
||||||
#include "base/models/QvStartupConfig.hpp"
|
#include "base/models/QvConfigModel.hpp"
|
||||||
#include "base/models/QvRuntimeConfig.hpp"
|
#include "base/models/QvRuntimeConfig.hpp"
|
||||||
|
#include "base/models/QvSafeType.hpp"
|
||||||
|
#include "base/models/QvStartupConfig.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
@ -38,9 +38,9 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
|
|
||||||
// Linux users and DEs should handle the darkMode UI themselves.
|
// Linux users and DEs should handle the darkMode UI themselves.
|
||||||
#ifndef QV2RAY_USE_BUILTIN_DARKTHEME
|
#ifndef QV2RAY_USE_BUILTIN_DARKTHEME
|
||||||
# ifndef Q_OS_LINUX
|
#ifndef Q_OS_LINUX
|
||||||
# define QV2RAY_USE_BUILTIN_DARKTHEME
|
#define QV2RAY_USE_BUILTIN_DARKTHEME
|
||||||
# endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QV2RAY_BUILD_INFO QString(_QV2RAY_BUILD_INFO_STR_)
|
#define QV2RAY_BUILD_INFO QString(_QV2RAY_BUILD_INFO_STR_)
|
||||||
@ -48,9 +48,9 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
|
|
||||||
// Base folder suffix.
|
// Base folder suffix.
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
# define QV2RAY_CONFIG_DIR_SUFFIX "_debug/"
|
#define QV2RAY_CONFIG_DIR_SUFFIX "_debug/"
|
||||||
#else
|
#else
|
||||||
# define QV2RAY_CONFIG_DIR_SUFFIX "/"
|
#define QV2RAY_CONFIG_DIR_SUFFIX "/"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get Configured Config Dir Path
|
// 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_DIR (QV2RAY_CONFIG_DIR + "generated/")
|
||||||
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
|
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
|
||||||
|
|
||||||
#if ! 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/")
|
#define QV2RAY_DEFAULT_VASSETS_PATH (QV2RAY_CONFIG_DIR + "vcore/")
|
||||||
# ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
# define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
|
#define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
|
||||||
# else
|
#else
|
||||||
# define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
|
#define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
|
||||||
# endif
|
#endif
|
||||||
#elif defined (QV2RAY_DEFAULT_VCORE_PATH) && defined (QV2RAY_DEFAULT_VASSETS_PATH)
|
#elif defined(QV2RAY_DEFAULT_VCORE_PATH) && defined(QV2RAY_DEFAULT_VASSETS_PATH)
|
||||||
// ---- Using user-specified VCore and VAssets path
|
// ---- Using user-specified VCore and VAssets path
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#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_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
|
||||||
//# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl.exe")
|
//# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl.exe")
|
||||||
#else
|
#else
|
||||||
# define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
|
#define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
|
||||||
# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl")
|
#define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QV2RAY_VCORE_LOG_DIRNAME "logs/"
|
#define QV2RAY_VCORE_LOG_DIRNAME "logs/"
|
||||||
@ -95,15 +95,15 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
#define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log"
|
#define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log"
|
||||||
|
|
||||||
// GUI TOOLS
|
// GUI TOOLS
|
||||||
#define RED(obj) \
|
#define RED(obj) \
|
||||||
auto _temp = obj->palette(); \
|
auto _temp = obj->palette(); \
|
||||||
_temp.setColor(QPalette::Text, Qt::red); \
|
_temp.setColor(QPalette::Text, Qt::red); \
|
||||||
obj->setPalette(_temp);
|
obj->setPalette(_temp);
|
||||||
|
|
||||||
#define BLACK(obj) \
|
#define BLACK(obj) obj->setPalette(QWidget::palette());
|
||||||
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 QICON_R(file) QIcon(QV2RAY_UI_RESOURCES_ROOT + file)
|
||||||
|
|
||||||
#define QSTRN(num) QString::number(num)
|
#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 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
|
namespace Qv2ray
|
||||||
{
|
{
|
||||||
@ -129,4 +130,4 @@ namespace Qv2ray
|
|||||||
isExiting = true;
|
isExiting = true;
|
||||||
QApplication::quit();
|
QApplication::quit();
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// Always use libgRPC++ on windows platform.
|
// Always use libgRPC++ on windows platform.
|
||||||
#ifndef WITH_LIB_GRPCPP
|
#ifndef WITH_LIB_GRPCPP
|
||||||
# ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define WITH_LIB_GRPCPP
|
#define WITH_LIB_GRPCPP
|
||||||
# endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "Qv2rayLog.hpp"
|
#include "Qv2rayLog.hpp"
|
||||||
|
|
||||||
#include "base/GlobalInstances.hpp"
|
#include "base/GlobalInstances.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace Qv2ray::base
|
namespace Qv2ray::base
|
||||||
@ -15,18 +17,22 @@ namespace Qv2ray::base
|
|||||||
auto logString = "[" + module + "]: " + log;
|
auto logString = "[" + module + "]: " + log;
|
||||||
auto funcPrepend = QString::fromStdString(func + ":" + to_string(line) + " ");
|
auto funcPrepend = QString::fromStdString(func + ":" + to_string(line) + " ");
|
||||||
|
|
||||||
if (isDebugBuild) {
|
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) {
|
// Debug build version, we only print info for DEBUG logs and print
|
||||||
logString = logString.prepend(funcPrepend);
|
// ALL info when debugLog presents,
|
||||||
}
|
if (type == QV2RAY_LOG_DEBUG || StartupOption.debugLog) { logString = logString.prepend(funcPrepend); }
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// We only process DEBUG log in Release mode
|
// We only process DEBUG log in Release mode
|
||||||
if (type == QV2RAY_LOG_DEBUG) {
|
if (type == QV2RAY_LOG_DEBUG)
|
||||||
if (StartupOption.debugLog) {
|
{
|
||||||
logString = logString.prepend(funcPrepend);
|
if (StartupOption.debugLog) { logString = logString.prepend(funcPrepend); }
|
||||||
} else {
|
else
|
||||||
// Discard debug log in non-debug Qv2ray version with no-debugLog mode.
|
{
|
||||||
|
// Discard debug log in non-debug Qv2ray version with
|
||||||
|
// no-debugLog mode.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,4 +56,4 @@ namespace Qv2ray::base
|
|||||||
__purgerBuffer->clear();
|
__purgerBuffer->clear();
|
||||||
return result;
|
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);
|
void __QV2RAY_LOG_FUNC__(int type, const std::string &func, int line, const QString &module, const QString &log);
|
||||||
const QString readLastLog();
|
const QString readLastLog();
|
||||||
}
|
} // namespace Qv2ray::base
|
||||||
|
|
||||||
#define NEWLINE "\r\n"
|
#define NEWLINE "\r\n"
|
||||||
|
|
||||||
#define QV2RAY_LOG_NORMAL 0
|
#define QV2RAY_LOG_NORMAL 0
|
||||||
#define QV2RAY_LOG_DEBUG 1
|
#define QV2RAY_LOG_DEBUG 1
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
#define Qv2ray_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
#define Qv2ray_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||||
#else
|
#else
|
||||||
#define Qv2ray_PRETTY_FUNCTION __FUNCSIG__
|
#define Qv2ray_PRETTY_FUNCTION __FUNCSIG__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __LOG_IMPL(LEVEL, MODULE, MSG) __QV2RAY_LOG_FUNC__(LEVEL, Qv2ray_PRETTY_FUNCTION, __LINE__, MODULE, MSG);
|
#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));
|
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
|
||||||
|
|
||||||
// Log modules used by Qv2ray
|
// Log modules used by Qv2ray
|
||||||
const inline QString MODULE_INIT = "INIT" ;
|
const inline QString MODULE_INIT = "INIT";
|
||||||
const inline QString MODULE_MESSAGING = "BASE-MESSAGING" ;
|
const inline QString MODULE_MESSAGING = "BASE-MESSAGING";
|
||||||
const inline QString MODULE_UI = "CORE-UI" ;
|
const inline QString MODULE_UI = "CORE-UI";
|
||||||
const inline QString MODULE_GRAPH = "CORE-UI-GRAPH" ;
|
const inline QString MODULE_GRAPH = "CORE-UI-GRAPH";
|
||||||
const inline QString MODULE_SETTINGS = "CORE-SETTINGS" ;
|
const inline QString MODULE_SETTINGS = "CORE-SETTINGS";
|
||||||
const inline QString MODULE_VCORE = "CORE-VCORE" ;
|
const inline QString MODULE_VCORE = "CORE-VCORE";
|
||||||
//
|
//
|
||||||
const inline QString MODULE_CONNECTION = "CORE-CONNECTION" ;
|
const inline QString MODULE_CONNECTION = "CORE-CONNECTION";
|
||||||
const inline QString MODULE_SUBSCRIPTION = "CORE-SUBSCRIPTION" ;
|
const inline QString MODULE_SUBSCRIPTION = "CORE-SUBSCRIPTION";
|
||||||
const inline QString MODULE_IMPORT = "CORE-IMPORT" ;
|
const inline QString MODULE_IMPORT = "CORE-IMPORT";
|
||||||
const inline QString MODULE_EXPORT = "CORE-EXPORT" ;
|
const inline QString MODULE_EXPORT = "CORE-EXPORT";
|
||||||
//
|
//
|
||||||
const inline QString MODULE_NETWORK = "COMMON-NETWORK" ;
|
const inline QString MODULE_NETWORK = "COMMON-NETWORK";
|
||||||
const inline QString MODULE_FILEIO = "COMMON-FILEIO" ;
|
const inline QString MODULE_FILEIO = "COMMON-FILEIO";
|
||||||
//
|
//
|
||||||
const inline QString MODULE_PROXY = "COMPONENT-PROXY" ;
|
const inline QString MODULE_PROXY = "COMPONENT-PROXY";
|
||||||
const inline QString MODULE_UPDATE = "COMPONENT-UPDATE" ;
|
const inline QString MODULE_UPDATE = "COMPONENT-UPDATE";
|
||||||
const inline QString MODULE_PLUGIN = "COMPONENT-PLUGIN" ;
|
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
|
#pragma once
|
||||||
#include <QString>
|
#include "3rdparty/x2struct/x2struct.hpp"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include "3rdparty/x2struct/x2struct.hpp"
|
#include <QString>
|
||||||
|
|
||||||
namespace Qv2ray::base::objects
|
namespace Qv2ray::base::objects
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Used in config generation
|
// Used in config generation
|
||||||
struct AccountObject {
|
struct AccountObject
|
||||||
|
{
|
||||||
QString user;
|
QString user;
|
||||||
QString pass;
|
QString pass;
|
||||||
XTOSTRUCT(O(user, pass))
|
XTOSTRUCT(O(user, pass))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct ApiObject {
|
struct ApiObject
|
||||||
|
{
|
||||||
QString tag;
|
QString tag;
|
||||||
QList<QString> services;
|
QList<QString> services;
|
||||||
ApiObject() : tag("api"), services() {}
|
ApiObject() : tag("api"), services()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(tag, services))
|
XTOSTRUCT(O(tag, services))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct SystemPolicyObject {
|
struct SystemPolicyObject
|
||||||
|
{
|
||||||
bool statsInboundUplink;
|
bool statsInboundUplink;
|
||||||
bool statsInboundDownlink;
|
bool statsInboundDownlink;
|
||||||
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink() {}
|
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(statsInboundUplink, statsInboundDownlink))
|
XTOSTRUCT(O(statsInboundUplink, statsInboundDownlink))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct LevelPolicyObject {
|
struct LevelPolicyObject
|
||||||
|
{
|
||||||
int handshake;
|
int handshake;
|
||||||
int connIdle;
|
int connIdle;
|
||||||
int uplinkOnly;
|
int uplinkOnly;
|
||||||
@ -39,20 +48,26 @@ namespace Qv2ray::base::objects
|
|||||||
bool statsUserUplink;
|
bool statsUserUplink;
|
||||||
bool statsUserDownlink;
|
bool statsUserDownlink;
|
||||||
int bufferSize;
|
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))
|
XTOSTRUCT(O(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct PolicyObject {
|
struct PolicyObject
|
||||||
|
{
|
||||||
QMap<QString, LevelPolicyObject> level;
|
QMap<QString, LevelPolicyObject> level;
|
||||||
QList<SystemPolicyObject> system;
|
QList<SystemPolicyObject> system;
|
||||||
PolicyObject(): level(), system() {}
|
PolicyObject() : level(), system()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(level, system))
|
XTOSTRUCT(O(level, system))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct RuleObject {
|
struct RuleObject
|
||||||
|
{
|
||||||
// Added due to the request of @aliyuchang33
|
// Added due to the request of @aliyuchang33
|
||||||
bool QV2RAY_RULE_ENABLED;
|
bool QV2RAY_RULE_ENABLED;
|
||||||
bool QV2RAY_RULE_USE_BALANCER;
|
bool QV2RAY_RULE_USE_BALANCER;
|
||||||
@ -70,65 +85,89 @@ namespace Qv2ray::base::objects
|
|||||||
QString attrs;
|
QString attrs;
|
||||||
QString outboundTag;
|
QString outboundTag;
|
||||||
QString balancerTag;
|
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("") {}
|
RuleObject()
|
||||||
XTOSTRUCT(O(QV2RAY_RULE_ENABLED, QV2RAY_RULE_USE_BALANCER, QV2RAY_RULE_TAG, type, domain, ip, port, network, source, user, inboundTag, protocol, attrs, outboundTag, balancerTag))
|
: 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 {
|
struct BalancerObject
|
||||||
QString tag ;
|
{
|
||||||
|
QString tag;
|
||||||
QList<QString> selector;
|
QList<QString> selector;
|
||||||
BalancerObject() : tag(), selector() {}
|
BalancerObject() : tag(), selector()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(tag, selector))
|
XTOSTRUCT(O(tag, selector))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
namespace transfer
|
namespace transfer
|
||||||
{
|
{
|
||||||
struct HTTPRequestObject {
|
struct HTTPRequestObject
|
||||||
|
{
|
||||||
QString version;
|
QString version;
|
||||||
QString method;
|
QString method;
|
||||||
QList<QString> path;
|
QList<QString> path;
|
||||||
QMap<QString, QList<QString>> headers;
|
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))
|
XTOSTRUCT(O(version, method, path, headers))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct HTTPResponseObject {
|
struct HTTPResponseObject
|
||||||
|
{
|
||||||
QString version;
|
QString version;
|
||||||
QString status;
|
QString status;
|
||||||
QString reason;
|
QString reason;
|
||||||
QMap<QString, QList<QString>> headers;
|
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))
|
XTOSTRUCT(O(version, status, reason, headers))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct TCPHeader_M_Object {
|
struct TCPHeader_M_Object
|
||||||
|
{
|
||||||
QString type;
|
QString type;
|
||||||
HTTPRequestObject request;
|
HTTPRequestObject request;
|
||||||
HTTPResponseObject response;
|
HTTPResponseObject response;
|
||||||
TCPHeader_M_Object(): type("none"), request(), response() {}
|
TCPHeader_M_Object() : type("none"), request(), response()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(type, request, response))
|
XTOSTRUCT(O(type, request, response))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct HeaderObject {
|
struct HeaderObject
|
||||||
|
{
|
||||||
QString type;
|
QString type;
|
||||||
HeaderObject(): type("none") {}
|
HeaderObject() : type("none")
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(type))
|
XTOSTRUCT(O(type))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct TCPObject {
|
struct TCPObject
|
||||||
|
{
|
||||||
TCPHeader_M_Object header;
|
TCPHeader_M_Object header;
|
||||||
TCPObject(): header() {}
|
TCPObject() : header()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(header))
|
XTOSTRUCT(O(header))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct KCPObject {
|
struct KCPObject
|
||||||
|
{
|
||||||
int mtu = 1350;
|
int mtu = 1350;
|
||||||
int tti = 20;
|
int tti = 20;
|
||||||
int uplinkCapacity = 5;
|
int uplinkCapacity = 5;
|
||||||
@ -137,84 +176,111 @@ namespace Qv2ray::base::objects
|
|||||||
int readBufferSize = 1;
|
int readBufferSize = 1;
|
||||||
int writeBufferSize = 1;
|
int writeBufferSize = 1;
|
||||||
HeaderObject header;
|
HeaderObject header;
|
||||||
KCPObject(): header() {}
|
KCPObject() : header()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header))
|
XTOSTRUCT(O(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct WebSocketObject {
|
struct WebSocketObject
|
||||||
|
{
|
||||||
QString path;
|
QString path;
|
||||||
QMap<QString, QString> headers;
|
QMap<QString, QString> headers;
|
||||||
WebSocketObject(): path("/"), headers() {}
|
WebSocketObject() : path("/"), headers()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(path, headers))
|
XTOSTRUCT(O(path, headers))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct HttpObject {
|
struct HttpObject
|
||||||
|
{
|
||||||
QList<QString> host;
|
QList<QString> host;
|
||||||
QString path;
|
QString path;
|
||||||
HttpObject() : host(), path("/") {}
|
HttpObject() : host(), path("/")
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(host, path))
|
XTOSTRUCT(O(host, path))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct DomainSocketObject {
|
struct DomainSocketObject
|
||||||
|
{
|
||||||
QString path;
|
QString path;
|
||||||
DomainSocketObject(): path("/") {}
|
DomainSocketObject() : path("/")
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(path))
|
XTOSTRUCT(O(path))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct QuicObject {
|
struct QuicObject
|
||||||
|
{
|
||||||
QString security;
|
QString security;
|
||||||
QString key;
|
QString key;
|
||||||
HeaderObject header;
|
HeaderObject header;
|
||||||
QuicObject(): security(""), key(""), header() {}
|
QuicObject() : security(""), key(""), header()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(security, key, header))
|
XTOSTRUCT(O(security, key, header))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct SockoptObject {
|
struct SockoptObject
|
||||||
|
{
|
||||||
int mark;
|
int mark;
|
||||||
bool tcpFastOpen;
|
bool tcpFastOpen;
|
||||||
QString tproxy;
|
QString tproxy;
|
||||||
SockoptObject(): mark(0), tcpFastOpen(false), tproxy("off") {}
|
SockoptObject() : mark(0), tcpFastOpen(false), tproxy("off")
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(mark, tcpFastOpen, tproxy))
|
XTOSTRUCT(O(mark, tcpFastOpen, tproxy))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct CertificateObject {
|
struct CertificateObject
|
||||||
|
{
|
||||||
QString usage;
|
QString usage;
|
||||||
QString certificateFile;
|
QString certificateFile;
|
||||||
QString keyFile;
|
QString keyFile;
|
||||||
QList<QString> certificate;
|
QList<QString> certificate;
|
||||||
QList<QString> key;
|
QList<QString> key;
|
||||||
CertificateObject(): usage(), certificateFile(), keyFile(), certificate(), key() {}
|
CertificateObject() : usage(), certificateFile(), keyFile(), certificate(), key()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(usage, certificateFile, keyFile, certificate, key))
|
XTOSTRUCT(O(usage, certificateFile, keyFile, certificate, key))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct TLSObject {
|
struct TLSObject
|
||||||
|
{
|
||||||
QString serverName;
|
QString serverName;
|
||||||
bool allowInsecure;
|
bool allowInsecure;
|
||||||
QList<QString> alpn;
|
QList<QString> alpn;
|
||||||
QList<CertificateObject> certificates;
|
QList<CertificateObject> certificates;
|
||||||
bool disableSystemRoot;
|
bool disableSystemRoot;
|
||||||
TLSObject(): serverName(), allowInsecure(), certificates(), disableSystemRoot() {}
|
TLSObject() : serverName(), allowInsecure(), certificates(), disableSystemRoot()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(serverName, allowInsecure, alpn, certificates, disableSystemRoot))
|
XTOSTRUCT(O(serverName, allowInsecure, alpn, certificates, disableSystemRoot))
|
||||||
};
|
};
|
||||||
}
|
} // namespace transfer
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct SniffingObject {
|
struct SniffingObject
|
||||||
|
{
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
QList<QString> destOverride;
|
QList<QString> destOverride;
|
||||||
SniffingObject(): enabled(), destOverride() {}
|
SniffingObject() : enabled(), destOverride()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(enabled, destOverride))
|
XTOSTRUCT(O(enabled, destOverride))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct StreamSettingsObject {
|
struct StreamSettingsObject
|
||||||
|
{
|
||||||
QString network;
|
QString network;
|
||||||
QString security;
|
QString security;
|
||||||
transfer::SockoptObject sockopt;
|
transfer::SockoptObject sockopt;
|
||||||
@ -225,15 +291,22 @@ namespace Qv2ray::base::objects
|
|||||||
transfer::HttpObject httpSettings;
|
transfer::HttpObject httpSettings;
|
||||||
transfer::DomainSocketObject dsSettings;
|
transfer::DomainSocketObject dsSettings;
|
||||||
transfer::QuicObject quicSettings;
|
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))
|
XTOSTRUCT(O(network, security, sockopt, tcpSettings, tlsSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct MuxObject {
|
struct MuxObject
|
||||||
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
int concurrency;
|
int concurrency;
|
||||||
MuxObject(): enabled(), concurrency() {}
|
MuxObject() : enabled(), concurrency()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(enabled, concurrency))
|
XTOSTRUCT(O(enabled, concurrency))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
@ -241,21 +314,28 @@ namespace Qv2ray::base::objects
|
|||||||
namespace protocol
|
namespace protocol
|
||||||
{
|
{
|
||||||
// DNS, OutBound
|
// DNS, OutBound
|
||||||
struct DNSOut {
|
struct DNSOut
|
||||||
|
{
|
||||||
QString network;
|
QString network;
|
||||||
QString address;
|
QString address;
|
||||||
int port;
|
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))
|
XTOSTRUCT(O(network, address, port))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// MTProto, InBound || OutBound
|
// MTProto, InBound || OutBound
|
||||||
struct MTProtoIn {
|
struct MTProtoIn
|
||||||
struct UserObject {
|
{
|
||||||
|
struct UserObject
|
||||||
|
{
|
||||||
QString email;
|
QString email;
|
||||||
int level;
|
int level;
|
||||||
QString secret;
|
QString secret;
|
||||||
UserObject() : email("user@domain.com"), level(0), secret("") {}
|
UserObject() : email("user@domain.com"), level(0), secret("")
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(email, level, secret))
|
XTOSTRUCT(O(email, level, secret))
|
||||||
};
|
};
|
||||||
QList<UserObject> users;
|
QList<UserObject> users;
|
||||||
@ -263,42 +343,55 @@ namespace Qv2ray::base::objects
|
|||||||
};
|
};
|
||||||
//
|
//
|
||||||
// Socks, OutBound
|
// Socks, OutBound
|
||||||
struct SocksServerObject {
|
struct SocksServerObject
|
||||||
struct UserObject {
|
{
|
||||||
|
struct UserObject
|
||||||
|
{
|
||||||
QString user;
|
QString user;
|
||||||
QString pass;
|
QString pass;
|
||||||
int level;
|
int level;
|
||||||
UserObject(): user("username"), pass("password"), level(0) {}
|
UserObject() : user("username"), pass("password"), level(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(user, pass, level))
|
XTOSTRUCT(O(user, pass, level))
|
||||||
};
|
};
|
||||||
|
|
||||||
QString address;
|
QString address;
|
||||||
int port;
|
int port;
|
||||||
QList<UserObject> users;
|
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))
|
XTOSTRUCT(O(address, port, users))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// VMess Server
|
// VMess Server
|
||||||
struct VMessServerObject {
|
struct VMessServerObject
|
||||||
struct UserObject {
|
{
|
||||||
|
struct UserObject
|
||||||
|
{
|
||||||
QString id;
|
QString id;
|
||||||
int alterId;
|
int alterId;
|
||||||
QString security;
|
QString security;
|
||||||
int level;
|
int level;
|
||||||
UserObject() : id(""), alterId(64), security("auto"), level(0) {}
|
UserObject() : id(""), alterId(64), security("auto"), level(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(id, alterId, security, level))
|
XTOSTRUCT(O(id, alterId, security, level))
|
||||||
};
|
};
|
||||||
|
|
||||||
QString address;
|
QString address;
|
||||||
int port;
|
int port;
|
||||||
QList<UserObject> users;
|
QList<UserObject> users;
|
||||||
VMessServerObject(): address(""), port(0), users() {}
|
VMessServerObject() : address(""), port(0), users()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(address, port, users))
|
XTOSTRUCT(O(address, port, users))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// ShadowSocks Server
|
// ShadowSocks Server
|
||||||
struct ShadowSocksServerObject {
|
struct ShadowSocksServerObject
|
||||||
|
{
|
||||||
QString email;
|
QString email;
|
||||||
QString address;
|
QString address;
|
||||||
QString method;
|
QString method;
|
||||||
@ -306,8 +399,11 @@ namespace Qv2ray::base::objects
|
|||||||
bool ota;
|
bool ota;
|
||||||
int level;
|
int level;
|
||||||
int port;
|
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))
|
XTOSTRUCT(O(email, address, port, method, password, ota, level))
|
||||||
};
|
};
|
||||||
}
|
} // namespace protocol
|
||||||
}
|
} // namespace Qv2ray::base::objects
|
||||||
|
@ -1,38 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "3rdparty/x2struct/x2struct.hpp"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include "3rdparty/x2struct/x2struct.hpp"
|
|
||||||
namespace Qv2ray::base
|
namespace Qv2ray::base
|
||||||
{
|
{
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
// Common struct for Groups and Subscriptions
|
// Common struct for Groups and Subscriptions
|
||||||
struct GroupObject_Config {
|
struct GroupObject_Config
|
||||||
|
{
|
||||||
QString displayName;
|
QString displayName;
|
||||||
QList<QString> connections;
|
QList<QString> connections;
|
||||||
int64_t importDate;
|
int64_t importDate;
|
||||||
GroupObject_Config(): displayName(), connections(), importDate() { }
|
GroupObject_Config() : displayName(), connections(), importDate()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(displayName, connections, importDate))
|
XTOSTRUCT(O(displayName, connections, importDate))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SubscriptionObject_Config : GroupObject_Config {
|
struct SubscriptionObject_Config : GroupObject_Config
|
||||||
|
{
|
||||||
//
|
//
|
||||||
QString address;
|
QString address;
|
||||||
int64_t lastUpdated;
|
int64_t lastUpdated;
|
||||||
float updateInterval;
|
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))
|
XTOSTRUCT(O(lastUpdated, updateInterval, address, connections, displayName, importDate))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectionObject_Config {
|
struct ConnectionObject_Config
|
||||||
|
{
|
||||||
QString displayName;
|
QString displayName;
|
||||||
int64_t importDate;
|
int64_t importDate;
|
||||||
int64_t lastConnected;
|
int64_t lastConnected;
|
||||||
int64_t latency;
|
int64_t latency;
|
||||||
int64_t upLinkData;
|
int64_t upLinkData;
|
||||||
int64_t downLinkData;
|
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))
|
XTOSTRUCT(O(displayName, importDate, lastConnected, latency, upLinkData, downLinkData))
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::base
|
||||||
|
|
||||||
using namespace Qv2ray::base;
|
using namespace Qv2ray::base;
|
||||||
|
@ -2,46 +2,59 @@
|
|||||||
#include "3rdparty/x2struct/x2struct.hpp"
|
#include "3rdparty/x2struct/x2struct.hpp"
|
||||||
#include "base/models/CoreObjectModels.hpp"
|
#include "base/models/CoreObjectModels.hpp"
|
||||||
#include "base/models/QvConfigIdentifier.hpp"
|
#include "base/models/QvConfigIdentifier.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
const int QV2RAY_CONFIG_VERSION = 9;
|
const int QV2RAY_CONFIG_VERSION = 9;
|
||||||
|
|
||||||
namespace Qv2ray::base::config
|
namespace Qv2ray::base::config
|
||||||
{
|
{
|
||||||
struct QvBarLine {
|
struct QvBarLine
|
||||||
|
{
|
||||||
QString Family;
|
QString Family;
|
||||||
bool Bold, Italic;
|
bool Bold, Italic;
|
||||||
int ColorA, ColorR, ColorG, ColorB;
|
int ColorA, ColorR, ColorG, ColorB;
|
||||||
int ContentType;
|
int ContentType;
|
||||||
double Size;
|
double Size;
|
||||||
QString Message;
|
QString Message;
|
||||||
QvBarLine(): Family("Consolas"), Bold(true), Italic(false), ColorA(255), ColorR(255), ColorG(255), ColorB(255),
|
QvBarLine()
|
||||||
ContentType(0), Size(9), Message("") { }
|
: 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))
|
XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QvBarPage {
|
struct QvBarPage
|
||||||
|
{
|
||||||
int OffsetYpx;
|
int OffsetYpx;
|
||||||
QList<QvBarLine> Lines;
|
QList<QvBarLine> Lines;
|
||||||
QvBarPage(): OffsetYpx(5) { }
|
QvBarPage() : OffsetYpx(5)
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(OffsetYpx, Lines))
|
XTOSTRUCT(O(OffsetYpx, Lines))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayToolBarConfig {
|
struct Qv2rayToolBarConfig
|
||||||
|
{
|
||||||
QList<QvBarPage> Pages;
|
QList<QvBarPage> Pages;
|
||||||
XTOSTRUCT(O(Pages))
|
XTOSTRUCT(O(Pages))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayPACConfig {
|
struct Qv2rayPACConfig
|
||||||
|
{
|
||||||
bool enablePAC;
|
bool enablePAC;
|
||||||
int port;
|
int port;
|
||||||
QString localIP;
|
QString localIP;
|
||||||
bool useSocksProxy;
|
bool useSocksProxy;
|
||||||
Qv2rayPACConfig(): enablePAC(false), port(8989), useSocksProxy(false) { }
|
Qv2rayPACConfig() : enablePAC(false), port(8989), useSocksProxy(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
|
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayForwardProxyConfig {
|
struct Qv2rayForwardProxyConfig
|
||||||
|
{
|
||||||
bool enableForwardProxy;
|
bool enableForwardProxy;
|
||||||
QString type;
|
QString type;
|
||||||
QString serverAddress;
|
QString serverAddress;
|
||||||
@ -49,12 +62,15 @@ namespace Qv2ray::base::config
|
|||||||
bool useAuth;
|
bool useAuth;
|
||||||
QString username;
|
QString username;
|
||||||
QString password;
|
QString password;
|
||||||
Qv2rayForwardProxyConfig(): enableForwardProxy(false), type("http"), serverAddress("127.0.0.1"), port(8008),
|
Qv2rayForwardProxyConfig()
|
||||||
useAuth(false), username(), password() { }
|
: enableForwardProxy(false), type("http"), serverAddress("127.0.0.1"), port(8008), useAuth(false), username(), password()
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
|
XTOSTRUCT(O(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayInboundsConfig {
|
struct Qv2rayInboundsConfig
|
||||||
|
{
|
||||||
QString listenip;
|
QString listenip;
|
||||||
bool setSystemProxy;
|
bool setSystemProxy;
|
||||||
Qv2rayPACConfig pacConfig;
|
Qv2rayPACConfig pacConfig;
|
||||||
@ -72,42 +88,56 @@ namespace Qv2ray::base::config
|
|||||||
bool http_useAuth;
|
bool http_useAuth;
|
||||||
objects::AccountObject httpAccount;
|
objects::AccountObject httpAccount;
|
||||||
|
|
||||||
Qv2rayInboundsConfig():
|
Qv2rayInboundsConfig()
|
||||||
listenip("127.0.0.1"), setSystemProxy(false), pacConfig(),
|
: listenip("127.0.0.1"), setSystemProxy(false), pacConfig(), useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true),
|
||||||
useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true), socksLocalIP("127.0.0.1"), socksAccount(),
|
socksLocalIP("127.0.0.1"), socksAccount(), useHTTP(true), http_port(8888), http_useAuth(false), httpAccount()
|
||||||
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 theme;
|
||||||
QString language;
|
QString language;
|
||||||
bool useDarkTheme;
|
bool useDarkTheme;
|
||||||
bool useDarkTrayIcon;
|
bool useDarkTrayIcon;
|
||||||
int maximumLogLines;
|
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))
|
XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon, maximumLogLines))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayConnectionConfig {
|
struct Qv2rayConnectionConfig
|
||||||
|
{
|
||||||
bool bypassCN;
|
bool bypassCN;
|
||||||
bool enableProxy;
|
bool enableProxy;
|
||||||
bool withLocalDNS;
|
bool withLocalDNS;
|
||||||
QList<QString> dnsList;
|
QList<QString> dnsList;
|
||||||
Qv2rayForwardProxyConfig forwardProxyConfig;
|
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))
|
XTOSTRUCT(O(bypassCN, enableProxy, withLocalDNS, dnsList, forwardProxyConfig))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayAPIConfig {
|
struct Qv2rayAPIConfig
|
||||||
|
{
|
||||||
bool enableAPI;
|
bool enableAPI;
|
||||||
int statsPort;
|
int statsPort;
|
||||||
Qv2rayAPIConfig(): enableAPI(true), statsPort(15490) { }
|
Qv2rayAPIConfig() : enableAPI(true), statsPort(15490)
|
||||||
|
{
|
||||||
|
}
|
||||||
XTOSTRUCT(O(enableAPI, statsPort))
|
XTOSTRUCT(O(enableAPI, statsPort))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayConfig {
|
struct Qv2rayConfig
|
||||||
|
{
|
||||||
int config_version;
|
int config_version;
|
||||||
bool tProxySupport;
|
bool tProxySupport;
|
||||||
int logLevel;
|
int logLevel;
|
||||||
@ -129,23 +159,13 @@ namespace Qv2ray::base::config
|
|||||||
Qv2rayInboundsConfig inboundConfig;
|
Qv2rayInboundsConfig inboundConfig;
|
||||||
Qv2rayConnectionConfig connectionConfig;
|
Qv2rayConnectionConfig connectionConfig;
|
||||||
|
|
||||||
Qv2rayConfig():
|
Qv2rayConfig()
|
||||||
config_version(QV2RAY_CONFIG_VERSION),
|
: config_version(QV2RAY_CONFIG_VERSION), tProxySupport(false), logLevel(), v2CorePath(), v2AssetsPath(), ignoredVersion(), groups(),
|
||||||
tProxySupport(false),
|
subscriptions(), connections(), uiConfig(), apiConfig(), toolBarConfig(), inboundConfig(), connectionConfig()
|
||||||
logLevel(),
|
{
|
||||||
v2CorePath(),
|
}
|
||||||
v2AssetsPath(),
|
|
||||||
ignoredVersion(),
|
|
||||||
groups(),
|
|
||||||
subscriptions(),
|
|
||||||
connections(),
|
|
||||||
uiConfig(), apiConfig(), toolBarConfig(), inboundConfig(), connectionConfig() { }
|
|
||||||
|
|
||||||
XTOSTRUCT(O(config_version, ignoredVersion,
|
XTOSTRUCT(O(config_version, ignoredVersion, tProxySupport, logLevel, uiConfig, v2CorePath, v2AssetsPath, groups, connections,
|
||||||
tProxySupport,
|
subscriptions, autoStartId, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
|
||||||
logLevel, uiConfig,
|
|
||||||
v2CorePath, v2AssetsPath,
|
|
||||||
groups, connections, subscriptions,
|
|
||||||
autoStartId, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
|
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::base::config
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
|
|
||||||
namespace Qv2ray::base
|
namespace Qv2ray::base
|
||||||
{
|
{
|
||||||
struct Qv2rayRuntimeConfig {
|
struct Qv2rayRuntimeConfig
|
||||||
|
{
|
||||||
//
|
//
|
||||||
bool screenShotHideQv2ray = false;
|
bool screenShotHideQv2ray = false;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::base
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
#define SAFE_TYPEDEF_EXTRA(Base, name, extra) \
|
#define SAFE_TYPEDEF_EXTRA(Base, name, extra) \
|
||||||
class name : public Base { \
|
class name : public Base \
|
||||||
public: \
|
{ \
|
||||||
template <class... Args> \
|
public: \
|
||||||
explicit name (Args... args) : Base(args...) {} \
|
template<class... Args> \
|
||||||
const Base& raw() const { return *this; } \
|
explicit name(Args... args) : Base(args...) \
|
||||||
extra };
|
{ \
|
||||||
|
} \
|
||||||
|
const Base &raw() const \
|
||||||
|
{ \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
extra \
|
||||||
|
};
|
||||||
|
|
||||||
#define nothing
|
#define nothing
|
||||||
#define SAFE_TYPEDEF(Base, name) SAFE_TYPEDEF_EXTRA(Base, name, 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(QJsonObject, ROUTERULE)
|
||||||
SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
|
SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
|
||||||
SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
|
SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
|
||||||
}
|
} // namespace Qv2ray::base::safetype
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ namespace Qv2ray
|
|||||||
{
|
{
|
||||||
namespace base
|
namespace base
|
||||||
{
|
{
|
||||||
struct QvStartupOptions {
|
struct QvStartupOptions
|
||||||
|
{
|
||||||
/// No API subsystem
|
/// No API subsystem
|
||||||
bool noAPI;
|
bool noAPI;
|
||||||
/// Explicitly run as root user.
|
/// Explicitly run as root user.
|
||||||
@ -14,5 +15,5 @@ namespace Qv2ray
|
|||||||
/// Enable Network toolbar plugin.
|
/// Enable Network toolbar plugin.
|
||||||
bool enableToolbarPlguin;
|
bool enableToolbarPlguin;
|
||||||
};
|
};
|
||||||
}
|
} // namespace base
|
||||||
}
|
} // namespace Qv2ray
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
#include "CommandArgs.hpp"
|
#include "CommandArgs.hpp"
|
||||||
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
QvCommandArgParser::QvCommandArgParser() : QObject(),
|
QvCommandArgParser::QvCommandArgParser()
|
||||||
noAPIOption("noAPI", QObject::tr("Disable gRPC API subsystems.")),
|
: QObject(), noAPIOption("noAPI", QObject::tr("Disable gRPC API subsystems.")),
|
||||||
runAsRootOption("I-just-wanna-run-with-root", QObject::tr("Explicitly run Qv2ray as root.")),
|
runAsRootOption("I-just-wanna-run-with-root", QObject::tr("Explicitly run Qv2ray as root.")),
|
||||||
debugOption("debug", QObject::tr("Enable Debug Output")),
|
debugOption("debug", QObject::tr("Enable Debug Output")),
|
||||||
withToolbarOption("withToolbarPlugin", QObject::tr("Enable Qv2ray network toolbar plugin")),
|
withToolbarOption("withToolbarPlugin", QObject::tr("Enable Qv2ray network toolbar plugin")),
|
||||||
//
|
//
|
||||||
helpOption("FAKE"), versionOption("FAKE")
|
helpOption("FAKE"), versionOption("FAKE")
|
||||||
{
|
{
|
||||||
parser.setApplicationDescription(QObject::tr("Qv2ray - A cross-platform Qt frontend for V2ray."));
|
parser.setApplicationDescription(QObject::tr("Qv2ray - A cross-platform Qt frontend for V2ray."));
|
||||||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||||
@ -24,33 +25,36 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
CommandLineParseResult QvCommandArgParser::ParseCommandLine(QString *errorMessage)
|
CommandLineParseResult QvCommandArgParser::ParseCommandLine(QString *errorMessage)
|
||||||
{
|
{
|
||||||
if (!parser.parse(QCoreApplication::arguments())) {
|
if (!parser.parse(QCoreApplication::arguments()))
|
||||||
|
{
|
||||||
*errorMessage = parser.errorText();
|
*errorMessage = parser.errorText();
|
||||||
return CommandLineError;
|
return CommandLineError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(versionOption))
|
if (parser.isSet(versionOption)) return CommandLineVersionRequested;
|
||||||
return CommandLineVersionRequested;
|
|
||||||
|
|
||||||
if (parser.isSet(helpOption))
|
if (parser.isSet(helpOption)) return CommandLineHelpRequested;
|
||||||
return CommandLineHelpRequested;
|
|
||||||
|
|
||||||
if (parser.isSet(noAPIOption)) {
|
if (parser.isSet(noAPIOption))
|
||||||
|
{
|
||||||
DEBUG(MODULE_INIT, "noAPIOption is set.")
|
DEBUG(MODULE_INIT, "noAPIOption is set.")
|
||||||
StartupOption.noAPI = true;
|
StartupOption.noAPI = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(runAsRootOption)) {
|
if (parser.isSet(runAsRootOption))
|
||||||
|
{
|
||||||
DEBUG(MODULE_INIT, "runAsRootOption is set.")
|
DEBUG(MODULE_INIT, "runAsRootOption is set.")
|
||||||
StartupOption.forceRunAsRootUser = true;
|
StartupOption.forceRunAsRootUser = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(debugOption)) {
|
if (parser.isSet(debugOption))
|
||||||
|
{
|
||||||
DEBUG(MODULE_INIT, "debugOption is set.")
|
DEBUG(MODULE_INIT, "debugOption is set.")
|
||||||
StartupOption.debugLog = true;
|
StartupOption.debugLog = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(withToolbarOption)) {
|
if (parser.isSet(withToolbarOption))
|
||||||
|
{
|
||||||
DEBUG(MODULE_INIT, "withToolbarOption is set.")
|
DEBUG(MODULE_INIT, "withToolbarOption is set.")
|
||||||
StartupOption.enableToolbarPlguin = true;
|
StartupOption.enableToolbarPlguin = true;
|
||||||
}
|
}
|
||||||
@ -58,4 +62,4 @@ namespace Qv2ray::common
|
|||||||
return CommandLineOk;
|
return CommandLineOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
enum CommandLineParseResult {
|
enum CommandLineParseResult
|
||||||
|
{
|
||||||
CommandLineOk,
|
CommandLineOk,
|
||||||
CommandLineError,
|
CommandLineError,
|
||||||
CommandLineVersionRequested,
|
CommandLineVersionRequested,
|
||||||
@ -12,24 +13,24 @@ namespace Qv2ray::common
|
|||||||
};
|
};
|
||||||
class QvCommandArgParser : public QObject
|
class QvCommandArgParser : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QvCommandArgParser();
|
QvCommandArgParser();
|
||||||
CommandLineParseResult ParseCommandLine(QString *errorMessage);
|
CommandLineParseResult ParseCommandLine(QString *errorMessage);
|
||||||
const QCommandLineParser *Parser()
|
const QCommandLineParser *Parser()
|
||||||
{
|
{
|
||||||
return &parser;
|
return &parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
QCommandLineOption noAPIOption;
|
QCommandLineOption noAPIOption;
|
||||||
QCommandLineOption runAsRootOption;
|
QCommandLineOption runAsRootOption;
|
||||||
QCommandLineOption debugOption;
|
QCommandLineOption debugOption;
|
||||||
QCommandLineOption withToolbarOption;
|
QCommandLineOption withToolbarOption;
|
||||||
QCommandLineOption helpOption;
|
QCommandLineOption helpOption;
|
||||||
QCommandLineOption versionOption;
|
QCommandLineOption versionOption;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
|
||||||
using namespace Qv2ray::common;
|
using namespace Qv2ray::common;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#include "HTTPRequestHelper.hpp"
|
#include "HTTPRequestHelper.hpp"
|
||||||
|
|
||||||
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include "base/Qv2rayBase.hpp"
|
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
@ -18,7 +20,8 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
QUrl qUrl = QUrl(url);
|
QUrl qUrl = QUrl(url);
|
||||||
|
|
||||||
if (!qUrl.isValid()) {
|
if (!qUrl.isValid())
|
||||||
|
{
|
||||||
LOG(MODULE_NETWORK, "Provided URL is invalid: " + url)
|
LOG(MODULE_NETWORK, "Provided URL is invalid: " + url)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -37,11 +40,14 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
this->setUrl(url);
|
this->setUrl(url);
|
||||||
|
|
||||||
if (useProxy) {
|
if (useProxy)
|
||||||
|
{
|
||||||
auto proxy = QNetworkProxyFactory::systemProxyForQuery();
|
auto proxy = QNetworkProxyFactory::systemProxyForQuery();
|
||||||
accessManager.setProxy(proxy.first());
|
accessManager.setProxy(proxy.first());
|
||||||
LOG(MODULE_NETWORK, "Sync get is using system proxy settings")
|
LOG(MODULE_NETWORK, "Sync get is using system proxy settings")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
|
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,28 +68,34 @@ namespace Qv2ray::common
|
|||||||
void QvHttpRequestHelper::get(const QString &url)
|
void QvHttpRequestHelper::get(const QString &url)
|
||||||
{
|
{
|
||||||
this->setUrl(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);
|
reply = accessManager.get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
|
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
|
||||||
connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
|
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);
|
// this->setUrl(url);
|
||||||
// request.setRawHeader("Content-Type", "application/json");
|
// request.setRawHeader("Content-Type", "application/json");
|
||||||
// reply = accessManager.post(request, data);
|
// reply = accessManager.post(request, data);
|
||||||
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
|
// connect(reply, &QNetworkReply::finished, this,
|
||||||
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
|
// &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);
|
// this->setUrl(url);
|
||||||
// request.setRawHeader("Content-Type", "application/json");
|
// request.setRawHeader("Content-Type", "application/json");
|
||||||
// reply = accessManager.put(request, data);
|
// reply = accessManager.put(request, data);
|
||||||
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
|
// connect(reply, &QNetworkReply::finished, this,
|
||||||
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
|
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
|
||||||
|
// &QNetworkReply::readyRead, this,
|
||||||
|
// &QvHttpRequestHelper::onReadyRead);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// void QvHttpRequestHelper::del(const QString &url)
|
// void QvHttpRequestHelper::del(const QString &url)
|
||||||
@ -91,26 +103,31 @@ namespace Qv2ray::common
|
|||||||
// this->setUrl(url);
|
// this->setUrl(url);
|
||||||
// request.setRawHeader("Content-Type", "application/json");
|
// request.setRawHeader("Content-Type", "application/json");
|
||||||
// reply = accessManager.deleteResource(request);
|
// reply = accessManager.deleteResource(request);
|
||||||
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
|
// connect(reply, &QNetworkReply::finished, this,
|
||||||
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
|
// &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);
|
// this->setUrl(url);
|
||||||
// request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
|
// request.setRawHeader("Content-Type",
|
||||||
// reply = accessManager.post(request, data);
|
// "application/x-www-form-urlencoded"); reply =
|
||||||
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished);
|
// accessManager.post(request, data); connect(reply,
|
||||||
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
|
// &QNetworkReply::finished, this,
|
||||||
|
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
|
||||||
|
// &QNetworkReply::readyRead, this,
|
||||||
|
// &QvHttpRequestHelper::onReadyRead);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
void QvHttpRequestHelper::onRequestFinished_p()
|
void QvHttpRequestHelper::onRequestFinished_p()
|
||||||
{
|
{
|
||||||
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) {
|
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) { DEBUG(MODULE_NETWORK, "HTTP/2 was used.") }
|
||||||
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());
|
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
|
||||||
LOG(MODULE_NETWORK, "Network request error string: " + error)
|
LOG(MODULE_NETWORK, "Network request error string: " + error)
|
||||||
QByteArray empty;
|
QByteArray empty;
|
||||||
@ -125,4 +142,4 @@ namespace Qv2ray::common
|
|||||||
DEBUG(MODULE_NETWORK, "A request is now ready read")
|
DEBUG(MODULE_NETWORK, "A request is now ready read")
|
||||||
this->data += reply->readAll();
|
this->data += reply->readAll();
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
@ -18,45 +18,46 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
class QvHttpRequestHelper : public QObject
|
class QvHttpRequestHelper : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QvHttpRequestHelper();
|
explicit QvHttpRequestHelper();
|
||||||
~QvHttpRequestHelper();
|
~QvHttpRequestHelper();
|
||||||
bool setUrl(const QString &url);
|
bool setUrl(const QString &url);
|
||||||
void setHeader(const QByteArray &key, const QByteArray &value);
|
void setHeader(const QByteArray &key, const QByteArray &value);
|
||||||
// get
|
// get
|
||||||
QByteArray syncget(const QString &url, bool useProxy);
|
QByteArray syncget(const QString &url, bool useProxy);
|
||||||
void get(const QString &url);
|
void get(const QString &url);
|
||||||
//// insert
|
//// insert
|
||||||
//void post(const QString &url, const QByteArray &data);
|
// void post(const QString &url, const QByteArray &data);
|
||||||
//// update
|
//// update
|
||||||
//void put(const QString &url, const QByteArray &data);
|
// void put(const QString &url, const QByteArray &data);
|
||||||
//// delete
|
//// delete
|
||||||
//void del(const QString &url);
|
// void del(const QString &url);
|
||||||
//void login(const QString &url, const QByteArray &data);
|
// void login(const QString &url, const QByteArray &data);
|
||||||
signals:
|
signals:
|
||||||
void httpRequestFinished(QByteArray &data);
|
void httpRequestFinished(QByteArray &data);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onRequestFinished_p();
|
void onRequestFinished_p();
|
||||||
private slots:
|
private slots:
|
||||||
void onReadyRead();
|
void onReadyRead();
|
||||||
private:
|
|
||||||
QByteArray data;
|
private:
|
||||||
QUrl url;
|
QByteArray data;
|
||||||
QNetworkReply *reply;
|
QUrl url;
|
||||||
QNetworkRequest request;
|
QNetworkReply *reply;
|
||||||
QNetworkAccessManager accessManager;
|
QNetworkRequest request;
|
||||||
|
QNetworkAccessManager accessManager;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
|
||||||
using namespace Qv2ray::common;
|
using namespace Qv2ray::common;
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
#include "LogHighlighter.hpp"
|
#include "LogHighlighter.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
#define TO_EOL "(([\\s\\S]*)|([\\d\\D]*)|([\\w\\W]*))$"
|
#define TO_EOL "(([\\s\\S]*)|([\\d\\D]*)|([\\w\\W]*))$"
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
SyntaxHighlighter::SyntaxHighlighter(bool darkMode, QTextDocument *parent)
|
SyntaxHighlighter::SyntaxHighlighter(bool darkMode, QTextDocument *parent) : QSyntaxHighlighter(parent)
|
||||||
: QSyntaxHighlighter(parent)
|
|
||||||
{
|
{
|
||||||
HighlightingRule rule;
|
HighlightingRule rule;
|
||||||
keywordFormat.setForeground(darkMode ? Qt::darkMagenta : Qt::magenta);
|
keywordFormat.setForeground(darkMode ? Qt::darkMagenta : Qt::magenta);
|
||||||
keywordFormat.setFontWeight(QFont::Bold);
|
keywordFormat.setFontWeight(QFont::Bold);
|
||||||
const QString keywordPatterns[] = {
|
const QString keywordPatterns[] = { "tcp", "udp" };
|
||||||
"tcp", "udp"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const QString &pattern : keywordPatterns) {
|
for (const QString &pattern : keywordPatterns)
|
||||||
|
{
|
||||||
rule.pattern = QRegularExpression(pattern);
|
rule.pattern = QRegularExpression(pattern);
|
||||||
rule.format = keywordFormat;
|
rule.format = keywordFormat;
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (darkMode) {
|
if (darkMode)
|
||||||
|
{
|
||||||
ipHostFormat.setForeground(Qt::yellow);
|
ipHostFormat.setForeground(Qt::yellow);
|
||||||
warningFormat.setForeground(QColor(230, 180, 0));
|
warningFormat.setForeground(QColor(230, 180, 0));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ipHostFormat.setForeground(Qt::black);
|
ipHostFormat.setForeground(Qt::black);
|
||||||
ipHostFormat.setFontWeight(QFont::Bold);
|
ipHostFormat.setFontWeight(QFont::Bold);
|
||||||
warningFormat.setForeground(Qt::white);
|
warningFormat.setForeground(Qt::white);
|
||||||
@ -49,7 +51,7 @@ namespace Qv2ray::common
|
|||||||
rule.format = debugFormat;
|
rule.format = debugFormat;
|
||||||
highlightingRules.append(rule);
|
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.pattern = QRegularExpression("\\[[Ii]nfo\\]" TO_EOL);
|
||||||
rule.format = infoFormat;
|
rule.format = infoFormat;
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
@ -119,10 +121,12 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
void SyntaxHighlighter::highlightBlock(const QString &text)
|
void SyntaxHighlighter::highlightBlock(const QString &text)
|
||||||
{
|
{
|
||||||
for (const HighlightingRule &rule : qAsConst(highlightingRules)) {
|
for (const HighlightingRule &rule : qAsConst(highlightingRules))
|
||||||
|
{
|
||||||
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
|
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
|
||||||
|
|
||||||
while (matchIterator.hasNext()) {
|
while (matchIterator.hasNext())
|
||||||
|
{
|
||||||
QRegularExpressionMatch match = matchIterator.next();
|
QRegularExpressionMatch match = matchIterator.next();
|
||||||
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
|
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
|
||||||
}
|
}
|
||||||
@ -130,4 +134,4 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
setCurrentBlockState(0);
|
setCurrentBlockState(0);
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
@ -49,45 +49,46 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QSyntaxHighlighter>
|
#include <QSyntaxHighlighter>
|
||||||
#include <QTextCharFormat>
|
#include <QTextCharFormat>
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
class SyntaxHighlighter : public QSyntaxHighlighter
|
class SyntaxHighlighter : public QSyntaxHighlighter
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
|
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void highlightBlock(const QString &text) override;
|
void highlightBlock(const QString &text) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct HighlightingRule {
|
struct HighlightingRule
|
||||||
QRegularExpression pattern;
|
{
|
||||||
QTextCharFormat format;
|
QRegularExpression pattern;
|
||||||
};
|
QTextCharFormat format;
|
||||||
QVector<HighlightingRule> highlightingRules;
|
};
|
||||||
|
QVector<HighlightingRule> highlightingRules;
|
||||||
|
|
||||||
QTextCharFormat keywordFormat;
|
QTextCharFormat keywordFormat;
|
||||||
QTextCharFormat dateFormat;
|
QTextCharFormat dateFormat;
|
||||||
QTextCharFormat acceptedFormat;
|
QTextCharFormat acceptedFormat;
|
||||||
QTextCharFormat rejectedFormat;
|
QTextCharFormat rejectedFormat;
|
||||||
QTextCharFormat failedFormat;
|
QTextCharFormat failedFormat;
|
||||||
QTextCharFormat warningFormat;
|
QTextCharFormat warningFormat;
|
||||||
QTextCharFormat infoFormat;
|
QTextCharFormat infoFormat;
|
||||||
QTextCharFormat debugFormat;
|
QTextCharFormat debugFormat;
|
||||||
QTextCharFormat timeFormat;
|
QTextCharFormat timeFormat;
|
||||||
QTextCharFormat ipHostFormat;
|
QTextCharFormat ipHostFormat;
|
||||||
QTextCharFormat v2rayComponentFormat;
|
QTextCharFormat v2rayComponentFormat;
|
||||||
//
|
//
|
||||||
QTextCharFormat qvAppLogFormat;
|
QTextCharFormat qvAppLogFormat;
|
||||||
QTextCharFormat qvAppDebugLogFormat;
|
QTextCharFormat qvAppDebugLogFormat;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
|
||||||
using namespace Qv2ray::common;
|
using namespace Qv2ray::common;
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
@ -23,10 +23,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "QJsonModel.hpp"
|
#include "QJsonModel.hpp"
|
||||||
#include <QFile>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QFont>
|
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFont>
|
||||||
|
|
||||||
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
|
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
|
||||||
{
|
{
|
||||||
@ -60,8 +60,7 @@ int QJsonTreeItem::childCount() const
|
|||||||
|
|
||||||
int QJsonTreeItem::row() const
|
int QJsonTreeItem::row() const
|
||||||
{
|
{
|
||||||
if (mParent)
|
if (mParent) return mParent->mChilds.indexOf(const_cast<QJsonTreeItem *>(this));
|
||||||
return mParent->mChilds.indexOf(const_cast<QJsonTreeItem *>(this));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -101,27 +100,34 @@ QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *paren
|
|||||||
QJsonTreeItem *rootItem = new QJsonTreeItem(parent);
|
QJsonTreeItem *rootItem = new QJsonTreeItem(parent);
|
||||||
rootItem->setKey("root");
|
rootItem->setKey("root");
|
||||||
|
|
||||||
if (value.isObject()) {
|
if (value.isObject())
|
||||||
//Get all QJsonValue childs
|
{
|
||||||
for (QString key : value.toObject().keys()) {
|
// Get all QJsonValue childs
|
||||||
|
for (QString key : value.toObject().keys())
|
||||||
|
{
|
||||||
QJsonValue v = value.toObject().value(key);
|
QJsonValue v = value.toObject().value(key);
|
||||||
QJsonTreeItem *child = load(v, rootItem);
|
QJsonTreeItem *child = load(v, rootItem);
|
||||||
child->setKey(key);
|
child->setKey(key);
|
||||||
child->setType(v.type());
|
child->setType(v.type());
|
||||||
rootItem->appendChild(child);
|
rootItem->appendChild(child);
|
||||||
}
|
}
|
||||||
} else if (value.isArray()) {
|
}
|
||||||
//Get all QJsonValue childs
|
else if (value.isArray())
|
||||||
|
{
|
||||||
|
// Get all QJsonValue childs
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (QJsonValue v : value.toArray()) {
|
for (QJsonValue v : value.toArray())
|
||||||
|
{
|
||||||
QJsonTreeItem *child = load(v, rootItem);
|
QJsonTreeItem *child = load(v, rootItem);
|
||||||
child->setKey(QString::number(index));
|
child->setKey(QString::number(index));
|
||||||
child->setType(v.type());
|
child->setType(v.type());
|
||||||
rootItem->appendChild(child);
|
rootItem->appendChild(child);
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rootItem->setValue(value.toVariant().toString());
|
rootItem->setValue(value.toVariant().toString());
|
||||||
rootItem->setType(value.type());
|
rootItem->setType(value.type());
|
||||||
}
|
}
|
||||||
@ -131,35 +137,27 @@ QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *paren
|
|||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
QJsonModel::QJsonModel(QObject *parent)
|
QJsonModel::QJsonModel(QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||||
: QAbstractItemModel(parent)
|
|
||||||
, mRootItem{new QJsonTreeItem}
|
|
||||||
{
|
{
|
||||||
mHeaders.append("key");
|
mHeaders.append("key");
|
||||||
mHeaders.append("value");
|
mHeaders.append("value");
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonModel::QJsonModel(const QString &fileName, QObject *parent)
|
QJsonModel::QJsonModel(const QString &fileName, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||||
: QAbstractItemModel(parent)
|
|
||||||
, mRootItem{new QJsonTreeItem}
|
|
||||||
{
|
{
|
||||||
mHeaders.append("key");
|
mHeaders.append("key");
|
||||||
mHeaders.append("value");
|
mHeaders.append("value");
|
||||||
load(fileName);
|
load(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonModel::QJsonModel(QIODevice *device, QObject *parent)
|
QJsonModel::QJsonModel(QIODevice *device, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||||
: QAbstractItemModel(parent)
|
|
||||||
, mRootItem{new QJsonTreeItem}
|
|
||||||
{
|
{
|
||||||
mHeaders.append("key");
|
mHeaders.append("key");
|
||||||
mHeaders.append("value");
|
mHeaders.append("value");
|
||||||
load(device);
|
load(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent)
|
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||||
: QAbstractItemModel(parent)
|
|
||||||
, mRootItem{new QJsonTreeItem}
|
|
||||||
{
|
{
|
||||||
mHeaders.append("key");
|
mHeaders.append("key");
|
||||||
mHeaders.append("value");
|
mHeaders.append("value");
|
||||||
@ -176,10 +174,13 @@ bool QJsonModel::load(const QString &fileName)
|
|||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
success = load(&file);
|
success = load(&file);
|
||||||
file.close();
|
file.close();
|
||||||
} else success = false;
|
}
|
||||||
|
else
|
||||||
|
success = false;
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -193,14 +194,18 @@ bool QJsonModel::loadJson(const QByteArray &json)
|
|||||||
{
|
{
|
||||||
auto const &jdoc = QJsonDocument::fromJson(json);
|
auto const &jdoc = QJsonDocument::fromJson(json);
|
||||||
|
|
||||||
if (!jdoc.isNull()) {
|
if (!jdoc.isNull())
|
||||||
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
delete mRootItem;
|
delete mRootItem;
|
||||||
|
|
||||||
if (jdoc.isArray()) {
|
if (jdoc.isArray())
|
||||||
|
{
|
||||||
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.array()));
|
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.array()));
|
||||||
mRootItem->setType(QJsonValue::Array);
|
mRootItem->setType(QJsonValue::Array);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.object()));
|
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.object()));
|
||||||
mRootItem->setType(QJsonValue::Object);
|
mRootItem->setType(QJsonValue::Object);
|
||||||
}
|
}
|
||||||
@ -213,24 +218,21 @@ bool QJsonModel::loadJson(const QByteArray &json)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QVariant QJsonModel::data(const QModelIndex &index, int role) const
|
QVariant QJsonModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid()) return QVariant();
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||||
|
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole)
|
||||||
if (index.column() == 0)
|
{
|
||||||
return QString("%1").arg(item->key());
|
if (index.column() == 0) return QString("%1").arg(item->key());
|
||||||
|
|
||||||
if (index.column() == 1)
|
if (index.column() == 1) return QString("%1").arg(item->value());
|
||||||
return QString("%1").arg(item->value());
|
}
|
||||||
} else if (Qt::EditRole == role) {
|
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()); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -240,11 +242,13 @@ bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int ro
|
|||||||
{
|
{
|
||||||
int col = index.column();
|
int col = index.column();
|
||||||
|
|
||||||
if (Qt::EditRole == role) {
|
if (Qt::EditRole == role)
|
||||||
if (col == 1) {
|
{
|
||||||
|
if (col == 1)
|
||||||
|
{
|
||||||
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||||
item->setValue(value.toString());
|
item->setValue(value.toString());
|
||||||
emit dataChanged(index, index, {Qt::EditRole});
|
emit dataChanged(index, index, { Qt::EditRole });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,49 +256,40 @@ bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int ro
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if (role != Qt::DisplayRole)
|
if (role != Qt::DisplayRole) return QVariant();
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
if (orientation == Qt::Horizontal) {
|
if (orientation == Qt::Horizontal) { return mHeaders.value(section); }
|
||||||
return mHeaders.value(section);
|
else
|
||||||
} else
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (!hasIndex(row, column, parent))
|
if (!hasIndex(row, column, parent)) return QModelIndex();
|
||||||
return QModelIndex();
|
|
||||||
|
|
||||||
QJsonTreeItem *parentItem;
|
QJsonTreeItem *parentItem;
|
||||||
|
|
||||||
if (!parent.isValid())
|
if (!parent.isValid()) parentItem = mRootItem;
|
||||||
parentItem = mRootItem;
|
|
||||||
else
|
else
|
||||||
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
|
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
|
||||||
|
|
||||||
QJsonTreeItem *childItem = parentItem->child(row);
|
QJsonTreeItem *childItem = parentItem->child(row);
|
||||||
|
|
||||||
if (childItem)
|
if (childItem) return createIndex(row, column, childItem);
|
||||||
return createIndex(row, column, childItem);
|
|
||||||
else
|
else
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex QJsonModel::parent(const QModelIndex &index) const
|
QModelIndex QJsonModel::parent(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid()) return QModelIndex();
|
||||||
return QModelIndex();
|
|
||||||
|
|
||||||
QJsonTreeItem *childItem = static_cast<QJsonTreeItem *>(index.internalPointer());
|
QJsonTreeItem *childItem = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||||
QJsonTreeItem *parentItem = childItem->parent();
|
QJsonTreeItem *parentItem = childItem->parent();
|
||||||
|
|
||||||
if (parentItem == mRootItem)
|
if (parentItem == mRootItem) return QModelIndex();
|
||||||
return QModelIndex();
|
|
||||||
|
|
||||||
return createIndex(parentItem->row(), 0, parentItem);
|
return createIndex(parentItem->row(), 0, parentItem);
|
||||||
}
|
}
|
||||||
@ -303,11 +298,9 @@ int QJsonModel::rowCount(const QModelIndex &parent) const
|
|||||||
{
|
{
|
||||||
QJsonTreeItem *parentItem;
|
QJsonTreeItem *parentItem;
|
||||||
|
|
||||||
if (parent.column() > 0)
|
if (parent.column() > 0) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!parent.isValid())
|
if (!parent.isValid()) parentItem = mRootItem;
|
||||||
parentItem = mRootItem;
|
|
||||||
else
|
else
|
||||||
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
|
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
|
Qt::ItemFlags QJsonModel::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
int col = index.column();
|
int col = index.column();
|
||||||
auto item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
auto item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||||
auto isArray = QJsonValue::Array == item->type();
|
auto isArray = QJsonValue::Array == item->type();
|
||||||
auto isObject = QJsonValue::Object == item->type();
|
auto isObject = QJsonValue::Object == item->type();
|
||||||
|
|
||||||
if ((col == 1) && !(isArray || isObject)) {
|
if ((col == 1) && !(isArray || isObject)) { return Qt::ItemIsEditable | QAbstractItemModel::flags(index); }
|
||||||
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
|
else
|
||||||
} else {
|
{
|
||||||
return QAbstractItemModel::flags(index);
|
return QAbstractItemModel::flags(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,40 +332,47 @@ QJsonDocument QJsonModel::json() const
|
|||||||
auto v = genJson(mRootItem);
|
auto v = genJson(mRootItem);
|
||||||
QJsonDocument doc;
|
QJsonDocument doc;
|
||||||
|
|
||||||
if (v.isObject()) {
|
if (v.isObject()) { doc = QJsonDocument(v.toObject()); }
|
||||||
doc = QJsonDocument(v.toObject());
|
else
|
||||||
} else {
|
{
|
||||||
doc = QJsonDocument(v.toArray());
|
doc = QJsonDocument(v.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const
|
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const
|
||||||
{
|
{
|
||||||
auto type = item->type();
|
auto type = item->type();
|
||||||
int nchild = item->childCount();
|
int nchild = item->childCount();
|
||||||
|
|
||||||
if (QJsonValue::Object == type) {
|
if (QJsonValue::Object == type)
|
||||||
|
{
|
||||||
QJsonObject jo;
|
QJsonObject jo;
|
||||||
|
|
||||||
for (int i = 0; i < nchild; ++i) {
|
for (int i = 0; i < nchild; ++i)
|
||||||
|
{
|
||||||
auto ch = item->child(i);
|
auto ch = item->child(i);
|
||||||
auto key = ch->key();
|
auto key = ch->key();
|
||||||
jo.insert(key, genJson(ch));
|
jo.insert(key, genJson(ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
return jo;
|
return jo;
|
||||||
} else if (QJsonValue::Array == type) {
|
}
|
||||||
|
else if (QJsonValue::Array == type)
|
||||||
|
{
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
|
|
||||||
for (int i = 0; i < nchild; ++i) {
|
for (int i = 0; i < nchild; ++i)
|
||||||
|
{
|
||||||
auto ch = item->child(i);
|
auto ch = item->child(i);
|
||||||
arr.append(genJson(ch));
|
arr.append(genJson(ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
QJsonValue va(item->value());
|
QJsonValue va(item->value());
|
||||||
return va;
|
return va;
|
||||||
}
|
}
|
||||||
|
@ -1,101 +1,94 @@
|
|||||||
/*
|
/*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 SCHUTZ Sacha
|
* Copyright (c) 2011 SCHUTZ Sacha
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
* copies or substantial portions of the Software.
|
* copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* 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
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
class QJsonModel;
|
class QJsonModel;
|
||||||
class QJsonItem;
|
class QJsonItem;
|
||||||
|
|
||||||
class QJsonTreeItem
|
class QJsonTreeItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QJsonTreeItem(QJsonTreeItem *parent = nullptr);
|
QJsonTreeItem(QJsonTreeItem *parent = nullptr);
|
||||||
~QJsonTreeItem();
|
~QJsonTreeItem();
|
||||||
void appendChild(QJsonTreeItem *item);
|
void appendChild(QJsonTreeItem *item);
|
||||||
QJsonTreeItem *child(int row);
|
QJsonTreeItem *child(int row);
|
||||||
QJsonTreeItem *parent();
|
QJsonTreeItem *parent();
|
||||||
int childCount() const;
|
int childCount() const;
|
||||||
int row() const;
|
int row() const;
|
||||||
void setKey(const QString &key);
|
void setKey(const QString &key);
|
||||||
void setValue(const QString &value);
|
void setValue(const QString &value);
|
||||||
void setType(const QJsonValue::Type &type);
|
void setType(const QJsonValue::Type &type);
|
||||||
QString key() const;
|
QString key() const;
|
||||||
QString value() const;
|
QString value() const;
|
||||||
QJsonValue::Type type() 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;
|
|
||||||
|
|
||||||
|
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
|
class QJsonModel : public QAbstractItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QJsonModel(QObject *parent = nullptr);
|
explicit QJsonModel(QObject *parent = nullptr);
|
||||||
QJsonModel(const QString &fileName, QObject *parent = nullptr);
|
QJsonModel(const QString &fileName, QObject *parent = nullptr);
|
||||||
QJsonModel(QIODevice *device, QObject *parent = nullptr);
|
QJsonModel(QIODevice *device, QObject *parent = nullptr);
|
||||||
QJsonModel(const QByteArray &json, QObject *parent = nullptr);
|
QJsonModel(const QByteArray &json, QObject *parent = nullptr);
|
||||||
~QJsonModel();
|
~QJsonModel();
|
||||||
bool load(const QString &fileName);
|
bool load(const QString &fileName);
|
||||||
bool load(QIODevice *device);
|
bool load(QIODevice *device);
|
||||||
bool loadJson(const QByteArray &json);
|
bool loadJson(const QByteArray &json);
|
||||||
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
|
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;
|
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;
|
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 index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||||
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
|
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||||
int columnCount(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;
|
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
|
||||||
QJsonDocument json() const;
|
QJsonDocument json() const;
|
||||||
|
|
||||||
private:
|
|
||||||
QJsonValue genJson(QJsonTreeItem *) const;
|
|
||||||
|
|
||||||
QJsonTreeItem *mRootItem;
|
|
||||||
QStringList mHeaders;
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
QJsonValue genJson(QJsonTreeItem *) const;
|
||||||
|
|
||||||
|
QJsonTreeItem *mRootItem;
|
||||||
|
QStringList mHeaders;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
@ -8,7 +9,8 @@ namespace Qv2ray::common
|
|||||||
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||||
QString randomString;
|
QString randomString;
|
||||||
|
|
||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
uint rand = QRandomGenerator::system()->generate();
|
uint rand = QRandomGenerator::system()->generate();
|
||||||
uint max = static_cast<uint>(possibleCharacters.length());
|
uint max = static_cast<uint>(possibleCharacters.length());
|
||||||
QChar nextChar = possibleCharacters[rand % max];
|
QChar nextChar = possibleCharacters[rand % max];
|
||||||
@ -73,9 +75,9 @@ namespace Qv2ray::common
|
|||||||
QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error);
|
QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error);
|
||||||
Q_UNUSED(doc)
|
Q_UNUSED(doc)
|
||||||
|
|
||||||
if (error.error == QJsonParseError::NoError) {
|
if (error.error == QJsonParseError::NoError) { return ""; }
|
||||||
return "";
|
else
|
||||||
} else {
|
{
|
||||||
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString())
|
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString())
|
||||||
return error.errorString();
|
return error.errorString();
|
||||||
}
|
}
|
||||||
@ -108,16 +110,16 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
list<string> list;
|
list<string> list;
|
||||||
|
|
||||||
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) {
|
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) { list.push_back(line.toStdString()); }
|
||||||
list.push_back(line.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList GetFileList(QDir dir)
|
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)
|
bool FileExistsIn(QDir dir, QString fileName)
|
||||||
@ -147,8 +149,7 @@ namespace Qv2ray::common
|
|||||||
int i;
|
int i;
|
||||||
double dblByte = bytes;
|
double dblByte = bytes;
|
||||||
|
|
||||||
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024)
|
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024) dblByte = bytes / 1024.0;
|
||||||
dblByte = bytes / 1024.0;
|
|
||||||
|
|
||||||
sprintf(str, "%.2f", dblByte);
|
sprintf(str, "%.2f", dblByte);
|
||||||
return QString(str) + " " + QString(sizes[i]);
|
return QString(str) + " " + QString(sizes[i]);
|
||||||
@ -163,9 +164,8 @@ namespace Qv2ray::common
|
|||||||
QString RemoveInvalidFileName(const QString &fileName)
|
QString RemoveInvalidFileName(const QString &fileName)
|
||||||
{
|
{
|
||||||
std::string _name = fileName.toStdString();
|
std::string _name = fileName.toStdString();
|
||||||
std::replace_if(_name.begin(), _name.end(), [](char c) {
|
std::replace_if(
|
||||||
return std::string::npos != string(R"("/\?%&^*;:|><)").find(c);
|
_name.begin(), _name.end(), [](char c) { return std::string::npos != string(R"("/\?%&^*;:|><)").find(c); }, '_');
|
||||||
}, '_');
|
|
||||||
return QString::fromStdString(_name);
|
return QString::fromStdString(_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,20 +174,25 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
if (!QDir(baseDir).exists()) {
|
if (!QDir(baseDir).exists())
|
||||||
|
{
|
||||||
QDir(baseDir).mkpath(baseDir);
|
QDir(baseDir).mkpath(baseDir);
|
||||||
LOG(MODULE_FILEIO, "Making path: " + baseDir)
|
LOG(MODULE_FILEIO, "Making path: " + baseDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true)
|
||||||
if (!QFile(baseDir + "/" + fileName + "_" + QSTRN(i) + extension).exists()) {
|
{
|
||||||
|
if (!QFile(baseDir + "/" + fileName + "_" + QSTRN(i) + extension).exists())
|
||||||
|
{
|
||||||
*fileName = *fileName + "_" + QSTRN(i);
|
*fileName = *fileName + "_" + QSTRN(i);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
DEBUG(MODULE_FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists")
|
DEBUG(MODULE_FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#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_IPV6_ADDR \
|
||||||
#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]))"
|
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])*)"
|
#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
|
namespace Qv2ray::common
|
||||||
@ -19,7 +22,8 @@ namespace Qv2ray::common
|
|||||||
//
|
//
|
||||||
void QvMessageBoxWarn(QWidget *parent, QString title, QString text);
|
void QvMessageBoxWarn(QWidget *parent, QString title, QString text);
|
||||||
void QvMessageBoxInfo(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(const QString &filePath);
|
||||||
QString StringFromFile(QFile *source);
|
QString StringFromFile(QFile *source);
|
||||||
@ -40,16 +44,16 @@ namespace Qv2ray::common
|
|||||||
inline QString GenerateUuid()
|
inline QString GenerateUuid()
|
||||||
{
|
{
|
||||||
return GenerateRandomString().toLower();
|
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)
|
QString StructToJsonString(const TYPE t)
|
||||||
{
|
{
|
||||||
return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' '));
|
return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' '));
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
template <typename TYPE>
|
template<typename TYPE>
|
||||||
TYPE StructFromJsonString(const QString &str)
|
TYPE StructFromJsonString(const QString &str)
|
||||||
{
|
{
|
||||||
TYPE v;
|
TYPE v;
|
||||||
@ -68,9 +72,7 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
QString t = str;
|
QString t = str;
|
||||||
t.truncate(limit);
|
t.truncate(limit);
|
||||||
return (limit == -1 || str.length() < limit)
|
return (limit == -1 || str.length() < limit) ? str : (t + suffix);
|
||||||
? str
|
|
||||||
: (t + suffix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace validation
|
namespace validation
|
||||||
@ -92,7 +94,7 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
return IsIPv4Address(addr) || IsIPv6Address(addr);
|
return IsIPv4Address(addr) || IsIPv6Address(addr);
|
||||||
}
|
}
|
||||||
}
|
} // namespace validation
|
||||||
|
|
||||||
inline QString timeToString(const time_t &t)
|
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);
|
strftime(MY_TIME, sizeof(MY_TIME), "%x - %I:%M%p", _tm);
|
||||||
return QString(MY_TIME);
|
return QString(MY_TIME);
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::common
|
||||||
|
|
||||||
using namespace Qv2ray::common;
|
using namespace Qv2ray::common;
|
||||||
|
@ -7,15 +7,15 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
class QvTranslator
|
class QvTranslator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QvTranslator(const QString &lang)
|
QvTranslator(const QString &lang)
|
||||||
{
|
{
|
||||||
QTranslator *translator = new QTranslator();
|
QTranslator *translator = new QTranslator();
|
||||||
translator->load(lang + ".qm", ":/translations/");
|
translator->load(lang + ".qm", ":/translations/");
|
||||||
this->pTranslator.reset(translator);
|
this->pTranslator.reset(translator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<QTranslator> pTranslator;
|
std::unique_ptr<QTranslator> pTranslator;
|
||||||
};
|
};
|
||||||
} // namespace Qv2ray::common
|
} // namespace Qv2ray::common
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#include "QvAutoLaunch.hpp"
|
#include "QvAutoLaunch.hpp"
|
||||||
#include <QSettings>
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QSettings>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
// macOS headers (possibly OBJ-c)
|
// macOS headers (possibly OBJ-c)
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
#include <CoreServices/CoreServices.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreServices/CoreServices.h>
|
||||||
#endif
|
#endif
|
||||||
namespace Qv2ray::components::autolaunch
|
namespace Qv2ray::components::autolaunch
|
||||||
{
|
{
|
||||||
@ -34,8 +35,10 @@ namespace Qv2ray::components::autolaunch
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined Q_OS_MAC
|
#elif defined Q_OS_MAC
|
||||||
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
|
// From
|
||||||
// this is quite some duplicate code with setLaunchOnStartup, at some point we should fix this FIXME.
|
// 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;
|
bool returnValue = false;
|
||||||
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
|
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
|
||||||
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
|
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
|
||||||
@ -49,16 +52,16 @@ namespace Qv2ray::components::autolaunch
|
|||||||
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
||||||
CFStringRef appUrlRefString = CFURLGetString(urlRef); // no need for release
|
CFStringRef appUrlRefString = CFURLGetString(urlRef); // no need for release
|
||||||
|
|
||||||
for (int i = 0; i < CFArrayGetCount(itemsArray); i++) {
|
for (int i = 0; i < CFArrayGetCount(itemsArray); i++)
|
||||||
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(itemsArray, i);
|
{
|
||||||
|
LSSharedFileListItemRef item = (LSSharedFileListItemRef) CFArrayGetValueAtIndex(itemsArray, i);
|
||||||
CFURLRef itemUrlRef = NULL;
|
CFURLRef itemUrlRef = NULL;
|
||||||
|
|
||||||
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef) {
|
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef)
|
||||||
|
{
|
||||||
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
|
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
|
||||||
|
|
||||||
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) {
|
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) { returnValue = true; }
|
||||||
returnValue = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(itemUrlRef);
|
CFRelease(itemUrlRef);
|
||||||
}
|
}
|
||||||
@ -86,16 +89,20 @@ namespace Qv2ray::components::autolaunch
|
|||||||
QString appName = QApplication::applicationName();
|
QString appName = QApplication::applicationName();
|
||||||
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||||
|
|
||||||
if (enable) {
|
if (enable)
|
||||||
|
{
|
||||||
QString strAppPath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
|
QString strAppPath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
|
||||||
reg.setValue(appName, strAppPath);
|
reg.setValue(appName, strAppPath);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
reg.remove(appName);
|
reg.remove(appName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined Q_OS_MAC
|
#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();
|
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
|
||||||
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
|
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
|
||||||
CFURLRef urlRef = CFURLCreateWithFileSystemPath(0, folderCFStr, kCFURLPOSIXPathStyle, true);
|
CFURLRef urlRef = CFURLCreateWithFileSystemPath(0, folderCFStr, kCFURLPOSIXPathStyle, true);
|
||||||
@ -103,30 +110,31 @@ namespace Qv2ray::components::autolaunch
|
|||||||
|
|
||||||
if (loginItems && enable)
|
if (loginItems && enable)
|
||||||
{
|
{
|
||||||
//Insert an item to the list.
|
// Insert an item to the list.
|
||||||
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems,
|
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, 0, 0, urlRef, 0, 0);
|
||||||
kLSSharedFileListItemLast, 0, 0,
|
|
||||||
urlRef, 0, 0);
|
|
||||||
|
|
||||||
if (item)
|
if (item) CFRelease(item);
|
||||||
CFRelease(item);
|
|
||||||
|
|
||||||
CFRelease(loginItems);
|
CFRelease(loginItems);
|
||||||
} else if (loginItems && !enable)
|
}
|
||||||
|
else if (loginItems && !enable)
|
||||||
{
|
{
|
||||||
// We need to iterate over the items and check which one is "ours".
|
// We need to iterate over the items and check which one is "ours".
|
||||||
UInt32 seedValue;
|
UInt32 seedValue;
|
||||||
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
||||||
CFStringRef appUrlRefString = CFURLGetString(urlRef);
|
CFStringRef appUrlRefString = CFURLGetString(urlRef);
|
||||||
|
|
||||||
for (int i = 0; i < CFArrayGetCount(itemsArray); i++) {
|
for (int i = 0; i < CFArrayGetCount(itemsArray); i++)
|
||||||
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(itemsArray, i);
|
{
|
||||||
|
LSSharedFileListItemRef item = (LSSharedFileListItemRef) CFArrayGetValueAtIndex(itemsArray, i);
|
||||||
CFURLRef itemUrlRef = NULL;
|
CFURLRef itemUrlRef = NULL;
|
||||||
|
|
||||||
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef) {
|
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef)
|
||||||
|
{
|
||||||
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
|
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
|
||||||
|
|
||||||
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) {
|
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo)
|
||||||
|
{
|
||||||
LSSharedFileListItemRemove(loginItems, item); // remove it!
|
LSSharedFileListItemRemove(loginItems, item); // remove it!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,22 +151,27 @@ namespace Qv2ray::components::autolaunch
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined Q_OS_LINUX
|
#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 appName = QApplication::applicationName();
|
||||||
QString userAutoStartPath = getUserAutostartDir_private();
|
QString userAutoStartPath = getUserAutostartDir_private();
|
||||||
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
|
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath)) {
|
if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath))
|
||||||
// qCWarning(lcUtility) << "Could not create autostart folder" << userAutoStartPath;
|
{
|
||||||
|
// qCWarning(lcUtility) << "Could not create autostart folder"
|
||||||
|
// << userAutoStartPath;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile iniFile(desktopFileLocation);
|
QFile iniFile(desktopFileLocation);
|
||||||
|
|
||||||
if (!iniFile.open(QIODevice::WriteOnly)) {
|
if (!iniFile.open(QIODevice::WriteOnly))
|
||||||
// qCWarning(lcUtility) << "Could not write auto start entry" << desktopFileLocation;
|
{
|
||||||
|
// qCWarning(lcUtility) << "Could not write auto start entry" <<
|
||||||
|
// desktopFileLocation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,13 +187,15 @@ namespace Qv2ray::components::autolaunch
|
|||||||
<< QLatin1String("Type=") << "Application" << endl
|
<< QLatin1String("Type=") << "Application" << endl
|
||||||
<< QLatin1String("StartupNotify=") << "false" << endl
|
<< QLatin1String("StartupNotify=") << "false" << endl
|
||||||
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl;
|
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (!QFile::remove(desktopFileLocation)) {
|
if (!QFile::remove(desktopFileLocation))
|
||||||
// qCWarning(lcUtility) << "Could not remove autostart desktop file";
|
{
|
||||||
|
// qCWarning(lcUtility) << "Could not remove autostart desktop
|
||||||
|
// file";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
} // namespace Qv2ray::components::autolaunch
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ namespace Qv2ray::components::autolaunch
|
|||||||
{
|
{
|
||||||
bool GetLaunchAtLoginStatus();
|
bool GetLaunchAtLoginStatus();
|
||||||
void SetLaunchAtLoginStatus(bool enable);
|
void SetLaunchAtLoginStatus(bool enable);
|
||||||
}
|
} // namespace Qv2ray::components::autolaunch
|
||||||
|
|
||||||
using namespace Qv2ray::components;
|
using namespace Qv2ray::components;
|
||||||
using namespace Qv2ray::components::autolaunch;
|
using namespace Qv2ray::components::autolaunch;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "QvGeositeReader.hpp"
|
#include "QvGeositeReader.hpp"
|
||||||
|
|
||||||
#include "libs/gen/v2ray_geosite.pb.h"
|
#include "libs/gen/v2ray_geosite.pb.h"
|
||||||
|
|
||||||
namespace Qv2ray::components::geosite
|
namespace Qv2ray::components::geosite
|
||||||
@ -13,7 +14,8 @@ namespace Qv2ray::components::geosite
|
|||||||
QFile f(filepath);
|
QFile f(filepath);
|
||||||
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
|
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
|
||||||
|
|
||||||
if (!opened) {
|
if (!opened)
|
||||||
|
{
|
||||||
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
|
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -24,7 +26,8 @@ namespace Qv2ray::components::geosite
|
|||||||
GeoSiteList sites;
|
GeoSiteList sites;
|
||||||
sites.ParseFromArray(content.data(), content.size());
|
sites.ParseFromArray(content.data(), content.size());
|
||||||
|
|
||||||
for (auto e : sites.entry()) {
|
for (auto e : sites.entry())
|
||||||
|
{
|
||||||
// We want to use lower string.
|
// We want to use lower string.
|
||||||
list << QString::fromStdString(e.country_code()).toLower();
|
list << QString::fromStdString(e.country_code()).toLower();
|
||||||
}
|
}
|
||||||
@ -34,4 +37,4 @@ namespace Qv2ray::components::geosite
|
|||||||
google::protobuf::ShutdownProtobufLibrary();
|
google::protobuf::ShutdownProtobufLibrary();
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::components::geosite
|
||||||
|
@ -1,41 +1,38 @@
|
|||||||
#include "ICMPPinger.hpp"
|
#include "ICMPPinger.hpp"
|
||||||
|
|
||||||
ICMPPinger::ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT) {
|
ICMPPinger::ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT)
|
||||||
|
{
|
||||||
// create icmp handle
|
// create icmp handle
|
||||||
if ((this->hIcmpFile = IcmpCreateFile()) == INVALID_HANDLE_VALUE) {
|
if ((this->hIcmpFile = IcmpCreateFile()) == INVALID_HANDLE_VALUE) { throw "IcmpCreateFile failed"; }
|
||||||
throw "IcmpCreateFile failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
// remember the timeout
|
// remember the timeout
|
||||||
this->timeout = timeout;
|
this->timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
ICMPPinger::~ICMPPinger() {
|
ICMPPinger::~ICMPPinger()
|
||||||
|
{
|
||||||
// release the handle on destruction
|
// release the handle on destruction
|
||||||
IcmpCloseHandle(this->hIcmpFile);
|
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
|
// convert network address
|
||||||
const auto addr = inet_addr(ipAddr.c_str());
|
const auto addr = inet_addr(ipAddr.c_str());
|
||||||
if (addr == INADDR_NONE) {
|
if (addr == INADDR_NONE) { return std::pair(std::nullopt, "invalid ip address: " + ipAddr); }
|
||||||
return std::pair(std::nullopt, "invalid ip address: " + ipAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// request buffer
|
// request buffer
|
||||||
const static char bufRequest[] = "echo test";
|
const static char bufRequest[] = "echo test";
|
||||||
|
|
||||||
// response buffer
|
// response buffer
|
||||||
const auto responseSize = sizeof(ICMP_ECHO_REPLY) + sizeof(bufRequest);
|
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
|
// 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
|
// ret == 0: failed
|
||||||
if (ret == 0) {
|
if (ret == 0) { return std::pair(std::nullopt, "IcmpSendEcho returned error"); }
|
||||||
return std::pair(std::nullopt, "IcmpSendEcho returned error");
|
|
||||||
}
|
|
||||||
|
|
||||||
// read round-trip time
|
// read round-trip time
|
||||||
PICMP_ECHO_REPLY pReply = (PICMP_ECHO_REPLY) bufRecv.get();
|
PICMP_ECHO_REPLY pReply = (PICMP_ECHO_REPLY) bufRecv.get();
|
||||||
|
@ -6,27 +6,26 @@
|
|||||||
* License: WTFPL
|
* License: WTFPL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include<winsock2.h>
|
#include <icmpapi.h>
|
||||||
#include<iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#include<icmpapi.h>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
#include<utility>
|
class ICMPPinger
|
||||||
#include<optional>
|
{
|
||||||
#include<memory>
|
public:
|
||||||
|
ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT);
|
||||||
|
~ICMPPinger();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const UINT64 DEFAULT_TIMEOUT = 10000U;
|
||||||
|
|
||||||
class ICMPPinger {
|
public:
|
||||||
public:
|
std::pair<std::optional<UINT64>, std::optional<std::string>> ping(const std::string &ipAddr);
|
||||||
ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT);
|
|
||||||
~ICMPPinger();
|
|
||||||
|
|
||||||
public:
|
private:
|
||||||
static const UINT64 DEFAULT_TIMEOUT = 10000U;
|
HANDLE hIcmpFile;
|
||||||
|
UINT64 timeout = DEFAULT_TIMEOUT;
|
||||||
public:
|
|
||||||
std::pair<std::optional<UINT64>, std::optional<std::string>> ping(const std::string& ipAddr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
HANDLE hIcmpFile;
|
|
||||||
UINT64 timeout = DEFAULT_TIMEOUT;
|
|
||||||
};
|
};
|
||||||
|
@ -21,29 +21,23 @@ namespace Qv2ray::components::pac
|
|||||||
bool passRule1 = originLine.find("|") != string::npos; // Proxy Lines
|
bool passRule1 = originLine.find("|") != string::npos; // Proxy Lines
|
||||||
bool passRule2 = originLine.find(".") != string::npos; // Link-Contained Lines
|
bool passRule2 = originLine.find(".") != string::npos; // Link-Contained Lines
|
||||||
|
|
||||||
if (originLine[endPosition] == '\n') {
|
if (originLine[endPosition] == '\n') { endPosition -= 1; }
|
||||||
endPosition -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (originLine.find("http://") != string::npos) {
|
if (originLine.find("http://") != string::npos) { startPosition += 8; }
|
||||||
startPosition += 8;
|
else if (originLine.find("https://") != string::npos)
|
||||||
} else if (originLine.find("https://") != string::npos) {
|
{
|
||||||
startPosition += 9;
|
startPosition += 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip unrelated lines
|
// Skip unrelated lines
|
||||||
if (skipRule1 || skipRule2 || skipRule3 || skipRule4) {
|
if (skipRule1 || skipRule2 || skipRule3 || skipRule4) { return ""; }
|
||||||
return "";
|
else if (passRule2)
|
||||||
} else if (passRule2) {
|
{
|
||||||
if (passRule1) {
|
if (passRule1) { startPosition += originLine.find_last_of("|") + 1; }
|
||||||
startPosition += originLine.find_last_of("|") + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (originLine[startPosition] == '\n') startPosition += 1;
|
if (originLine[startPosition] == '\n') startPosition += 1;
|
||||||
|
|
||||||
for (size_t i = startPosition; i < endPosition; ++i) {
|
for (size_t i = startPosition; i < endPosition; ++i) { returnBuffer += originLine[i]; }
|
||||||
returnBuffer += originLine[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnBuffer;
|
return returnBuffer;
|
||||||
@ -52,19 +46,19 @@ namespace Qv2ray::components::pac
|
|||||||
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString)
|
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString)
|
||||||
{
|
{
|
||||||
auto rawFileContent = Base64Decode(rawContent).toStdString();
|
auto rawFileContent = Base64Decode(rawContent).toStdString();
|
||||||
string readBuffer = ""; //cleanup
|
string readBuffer = ""; // cleanup
|
||||||
string writeBuffer;
|
string writeBuffer;
|
||||||
string domainListCache = "";
|
string domainListCache = "";
|
||||||
|
|
||||||
for (size_t i = 0; i < rawFileContent.size(); ++i) {
|
for (size_t i = 0; i < rawFileContent.size(); ++i)
|
||||||
|
{
|
||||||
readBuffer += rawFileContent[i];
|
readBuffer += rawFileContent[i];
|
||||||
|
|
||||||
if (rawFileContent[i + 1] == '\n') {
|
if (rawFileContent[i + 1] == '\n')
|
||||||
|
{
|
||||||
writeBuffer = getRawDomain(readBuffer);
|
writeBuffer = getRawDomain(readBuffer);
|
||||||
|
|
||||||
if (writeBuffer != "") {
|
if (writeBuffer != "") { domainListCache += writeBuffer + "\n"; }
|
||||||
domainListCache += writeBuffer + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
readBuffer = "";
|
readBuffer = "";
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -72,19 +66,22 @@ namespace Qv2ray::components::pac
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t rotatorTwo = 0;
|
size_t rotatorTwo = 0;
|
||||||
string readDomainBuffer = "";
|
string readDomainBuffer = "";
|
||||||
bool isFirstLine = true;
|
bool isFirstLine = true;
|
||||||
string outputContent = "";
|
string outputContent = "";
|
||||||
//Header
|
// Header
|
||||||
outputContent += "var domains = {\n";
|
outputContent += "var domains = {\n";
|
||||||
|
|
||||||
//Read and process output content line by line
|
// Read and process output content line by line
|
||||||
while (rotatorTwo < domainListCache.size()) {
|
while (rotatorTwo < domainListCache.size())
|
||||||
while (true) {
|
{
|
||||||
//Get Domain
|
while (true)
|
||||||
|
{
|
||||||
|
// Get Domain
|
||||||
readDomainBuffer += domainListCache[rotatorTwo];
|
readDomainBuffer += domainListCache[rotatorTwo];
|
||||||
|
|
||||||
if (domainListCache[rotatorTwo + 1] == '\n') {
|
if (domainListCache[rotatorTwo + 1] == '\n')
|
||||||
|
{
|
||||||
rotatorTwo += 2;
|
rotatorTwo += 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -92,9 +89,10 @@ namespace Qv2ray::components::pac
|
|||||||
rotatorTwo++;
|
rotatorTwo++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Format
|
// Format
|
||||||
if (!isFirstLine) outputContent += ",\n";
|
if (!isFirstLine) outputContent += ",\n";
|
||||||
else isFirstLine = false;
|
else
|
||||||
|
isFirstLine = false;
|
||||||
|
|
||||||
outputContent += "\t\"";
|
outputContent += "\t\"";
|
||||||
outputContent += readDomainBuffer;
|
outputContent += readDomainBuffer;
|
||||||
@ -102,32 +100,18 @@ namespace Qv2ray::components::pac
|
|||||||
readDomainBuffer = "";
|
readDomainBuffer = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
//End Message
|
// End Message
|
||||||
outputContent +=
|
outputContent += NEWLINE "};" NEWLINE "" NEWLINE " var proxy = \"" + customProxyString.toStdString() + ";\";" +
|
||||||
NEWLINE "};"
|
NEWLINE " var direct = 'DIRECT;';" NEWLINE " function FindProxyForURL(url, host) {" NEWLINE
|
||||||
NEWLINE ""
|
" var suffix;" NEWLINE " var pos = host.lastIndexOf('.');" NEWLINE
|
||||||
NEWLINE " var proxy = \"" + customProxyString.toStdString() + ";\";" +
|
" pos = host.lastIndexOf('.', pos - 1);" NEWLINE " //" NEWLINE " while (1) {" NEWLINE
|
||||||
NEWLINE " var direct = 'DIRECT;';"
|
" if (domains[host] != undefined) {" NEWLINE " return proxy;" NEWLINE
|
||||||
NEWLINE " function FindProxyForURL(url, host) {"
|
" }" NEWLINE " else if (pos <= 0) {" NEWLINE
|
||||||
NEWLINE " var suffix;"
|
" return domains['.' + host] != undefined ? proxy : direct;" NEWLINE " }" NEWLINE
|
||||||
NEWLINE " var pos = host.lastIndexOf('.');"
|
" suffix = host.substring(pos);" NEWLINE " if (domains[suffix] != undefined) {" NEWLINE
|
||||||
NEWLINE " pos = host.lastIndexOf('.', pos - 1);"
|
" return proxy;" NEWLINE " }" NEWLINE
|
||||||
NEWLINE " //"
|
" pos = host.lastIndexOf('.', pos - 1);" NEWLINE " }" 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);
|
return QString::fromStdString(outputContent);
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::components::pac
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "QvPACHandler.hpp"
|
#include "QvPACHandler.hpp"
|
||||||
|
|
||||||
|
#include "common/QvHelpers.hpp"
|
||||||
|
#include "core/CoreUtils.hpp"
|
||||||
#include "qhttprequest.h"
|
#include "qhttprequest.h"
|
||||||
#include "qhttpresponse.h"
|
#include "qhttpresponse.h"
|
||||||
#include "core/CoreUtils.hpp"
|
|
||||||
#include "common/QvHelpers.hpp"
|
|
||||||
|
|
||||||
namespace Qv2ray::components::pac
|
namespace Qv2ray::components::pac
|
||||||
{
|
{
|
||||||
@ -13,9 +14,7 @@ namespace Qv2ray::components::pac
|
|||||||
}
|
}
|
||||||
PACServer::~PACServer()
|
PACServer::~PACServer()
|
||||||
{
|
{
|
||||||
if (isStarted) {
|
if (isStarted) { pacServer.close(); }
|
||||||
pacServer.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void PACServer::SetProxyString(const QString &proxyString)
|
void PACServer::SetProxyString(const QString &proxyString)
|
||||||
{
|
{
|
||||||
@ -36,10 +35,13 @@ namespace Qv2ray::components::pac
|
|||||||
//
|
//
|
||||||
auto result = pacServer.listen(QHostAddress(address), static_cast<ushort>(port));
|
auto result = pacServer.listen(QHostAddress(address), static_cast<ushort>(port));
|
||||||
|
|
||||||
if (result) {
|
if (result)
|
||||||
|
{
|
||||||
isStarted = true;
|
isStarted = true;
|
||||||
DEBUG(MODULE_PROXY, "Started PAC handler")
|
DEBUG(MODULE_PROXY, "Started PAC handler")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Failed to listen on port " + QSTRN(port) + ", possible permission denied.")
|
LOG(MODULE_PROXY, "Failed to listen on port " + QSTRN(port) + ", possible permission denied.")
|
||||||
QvMessageBoxWarn(nullptr, tr("PAC Handler"), tr("Failed to listen PAC request on this port, please verify the permissions"));
|
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()
|
void PACServer::StopServer()
|
||||||
{
|
{
|
||||||
if (isStarted) {
|
if (isStarted)
|
||||||
|
{
|
||||||
pacServer.close();
|
pacServer.close();
|
||||||
DEBUG(MODULE_PROXY, "PAC Handler stopped.")
|
DEBUG(MODULE_PROXY, "PAC Handler stopped.")
|
||||||
isStarted = false;
|
isStarted = false;
|
||||||
@ -58,22 +61,28 @@ namespace Qv2ray::components::pac
|
|||||||
{
|
{
|
||||||
rsp->setHeader("Server", "Qv2ray/" QV2RAY_VERSION_STRING " PAC_Handler");
|
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.")
|
DEBUG(MODULE_PROXY, "Serving PAC file request.")
|
||||||
//
|
//
|
||||||
rsp->setHeader("Content-Type", "application/javascript; charset=utf-8");
|
rsp->setHeader("Content-Type", "application/javascript; charset=utf-8");
|
||||||
rsp->writeHead(QHttpResponse::StatusCode::STATUS_OK);
|
rsp->writeHead(QHttpResponse::StatusCode::STATUS_OK);
|
||||||
rsp->end(pacContent.toUtf8());
|
rsp->end(pacContent.toUtf8());
|
||||||
DEBUG(MODULE_PROXY, "Serving a pac file...")
|
DEBUG(MODULE_PROXY, "Serving a pac file...")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rsp->writeHead(QHttpResponse::StatusCode::STATUS_NOT_FOUND);
|
rsp->writeHead(QHttpResponse::StatusCode::STATUS_NOT_FOUND);
|
||||||
rsp->end("NOT FOUND");
|
rsp->end("NOT FOUND");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rsp->writeHead(QHttpResponse::StatusCode::STATUS_METHOD_NOT_ALLOWED);
|
rsp->writeHead(QHttpResponse::StatusCode::STATUS_METHOD_NOT_ALLOWED);
|
||||||
rsp->end("PAC ONLY SUPPORT GET");
|
rsp->end("PAC ONLY SUPPORT GET");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::components::pac
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "qhttpserver.h"
|
#include "qhttpserver.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -8,26 +9,26 @@ namespace Qv2ray::components::pac
|
|||||||
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString);
|
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString);
|
||||||
class PACServer : public QObject
|
class PACServer : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit PACServer();
|
explicit PACServer();
|
||||||
~PACServer();
|
~PACServer();
|
||||||
void SetProxyString(const QString &proxyString);
|
void SetProxyString(const QString &proxyString);
|
||||||
void StartListen();
|
void StartListen();
|
||||||
void StopServer();
|
void StopServer();
|
||||||
|
|
||||||
QString gfwFilePath;
|
QString gfwFilePath;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onNewRequest(QHttpRequest *request, QHttpResponse *response);
|
void onNewRequest(QHttpRequest *request, QHttpResponse *response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isStarted;
|
bool isStarted;
|
||||||
QHttpServer pacServer;
|
QHttpServer pacServer;
|
||||||
QString pacContent;
|
QString pacContent;
|
||||||
QString proxyString;
|
QString proxyString;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::components::pac
|
||||||
|
|
||||||
using namespace Qv2ray::components;
|
using namespace Qv2ray::components;
|
||||||
using namespace Qv2ray::components::pac;
|
using namespace Qv2ray::components::pac;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include "ui/w_MainWindow.hpp"
|
|
||||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
#include "components/plugins/toolbar/QvToolbar.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
#include "ui/w_MainWindow.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::components::plugins
|
namespace Qv2ray::components::plugins
|
||||||
{
|
{
|
||||||
@ -31,118 +32,137 @@ namespace Qv2ray::components::plugins
|
|||||||
QString GetAnswerToRequest(const QString &pchRequest)
|
QString GetAnswerToRequest(const QString &pchRequest)
|
||||||
{
|
{
|
||||||
auto instance = MainWindow::mwInstance;
|
auto instance = MainWindow::mwInstance;
|
||||||
//if (instance == nullptr || instance->vinstance == nullptr) {
|
// if (instance == nullptr || instance->vinstance == nullptr) {
|
||||||
// LOG(PLUGIN, "MainWindow != nullptr Assertion failed!")
|
// LOG(PLUGIN, "MainWindow != nullptr Assertion failed!")
|
||||||
// return "{}";
|
// return "{}";
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//auto vinstance = instance->vinstance;
|
// auto vinstance = instance->vinstance;
|
||||||
//
|
//
|
||||||
auto req = pchRequest.trimmed();
|
auto req = pchRequest.trimmed();
|
||||||
QString reply = "{}";
|
QString reply = "{}";
|
||||||
|
|
||||||
if (req == "START") {
|
if (req == "START") { emit instance->Connect(); }
|
||||||
emit instance->Connect();
|
else if (req == "STOP")
|
||||||
} else if (req == "STOP") {
|
{
|
||||||
emit instance->DisConnect();
|
emit instance->DisConnect();
|
||||||
} else if (req == "RESTART") {
|
}
|
||||||
|
else if (req == "RESTART")
|
||||||
|
{
|
||||||
emit instance->ReConnect();
|
emit instance->ReConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BarConfig = GlobalConfig.toolBarConfig;
|
auto BarConfig = GlobalConfig.toolBarConfig;
|
||||||
|
|
||||||
for (auto i = 0; i < BarConfig.Pages.size(); i++) {
|
for (auto i = 0; i < BarConfig.Pages.size(); i++)
|
||||||
for (auto j = 0; j < BarConfig.Pages[i].Lines.size(); j++) {
|
{
|
||||||
|
for (auto j = 0; j < BarConfig.Pages[i].Lines.size(); j++)
|
||||||
|
{
|
||||||
#define CL BarConfig.Pages[i].Lines[j]
|
#define CL BarConfig.Pages[i].Lines[j]
|
||||||
|
|
||||||
switch (CL.ContentType) {
|
switch (CL.ContentType)
|
||||||
case 0: {
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
// Custom Text
|
// Custom Text
|
||||||
// We do nothing...
|
// We do nothing...
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 101: {
|
case 101:
|
||||||
|
{
|
||||||
// Current Time
|
// Current Time
|
||||||
CL.Message = QTime().currentTime().toString("hh:mm:ss");
|
CL.Message = QTime().currentTime().toString("hh:mm:ss");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 102: {
|
case 102:
|
||||||
|
{
|
||||||
// Current Date
|
// Current Date
|
||||||
CL.Message = QDate().currentDate().toString("yyyy-MM-dd");
|
CL.Message = QDate().currentDate().toString("yyyy-MM-dd");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 103: {
|
case 103:
|
||||||
|
{
|
||||||
// Current Qv2ray Version
|
// Current Qv2ray Version
|
||||||
CL.Message = QV2RAY_VERSION_STRING;
|
CL.Message = QV2RAY_VERSION_STRING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//case 104: {
|
// case 104: {
|
||||||
// // Current Connection Name
|
// // Current Connection Name
|
||||||
// CL.Message = instance->GetCurrentConnectedConfigName();
|
// CL.Message =
|
||||||
// break;
|
// instance->GetCurrentConnectedConfigName();
|
||||||
//}
|
// break;
|
||||||
//
|
//}
|
||||||
//case 105: {
|
//
|
||||||
// // Current Connection Status
|
// case 105: {
|
||||||
// CL.Message = instance->vinstance->KernelStarted
|
// // Current Connection Status
|
||||||
// ? QObject::tr("Connected")
|
// CL.Message =
|
||||||
// : QObject::tr("Disconnected");
|
// instance->vinstance->KernelStarted
|
||||||
// break;
|
// ? QObject::tr("Connected")
|
||||||
//}
|
// : QObject::tr("Disconnected");
|
||||||
//
|
// break;
|
||||||
//case 201: {
|
//}
|
||||||
// // Total upload speed;
|
//
|
||||||
// CL.Message = FormatBytes(vinstance->getAllSpeedUp()) + "/s";
|
// case 201: {
|
||||||
// break;
|
// // Total upload speed;
|
||||||
//}
|
// CL.Message =
|
||||||
//
|
// FormatBytes(vinstance->getAllSpeedUp()) +
|
||||||
//case 202: {
|
// "/s"; break;
|
||||||
// // Total download speed;
|
//}
|
||||||
// CL.Message = FormatBytes(vinstance->getAllSpeedDown()) + "/s";
|
//
|
||||||
// break;
|
// case 202: {
|
||||||
//}
|
// // Total download speed;
|
||||||
//
|
// CL.Message =
|
||||||
//case 203: {
|
// FormatBytes(vinstance->getAllSpeedDown()) +
|
||||||
// // Upload speed for tag
|
// "/s"; break;
|
||||||
// CL.Message = FormatBytes(vinstance->getTagSpeedUp(CL.Message)) + "/s";
|
//}
|
||||||
// break;
|
//
|
||||||
//}
|
// case 203: {
|
||||||
//
|
// // Upload speed for tag
|
||||||
//case 204: {
|
// CL.Message =
|
||||||
// // Download speed for tag
|
// FormatBytes(vinstance->getTagSpeedUp(CL.Message))
|
||||||
// CL.Message = FormatBytes(vinstance->getTagSpeedDown(CL.Message)) + "/s";
|
// + "/s"; break;
|
||||||
// break;
|
//}
|
||||||
//}
|
//
|
||||||
//
|
// case 204: {
|
||||||
//case 301: {
|
// // Download speed for tag
|
||||||
// // Total Upload
|
// CL.Message =
|
||||||
// CL.Message = FormatBytes(vinstance->getAllDataUp());
|
// FormatBytes(vinstance->getTagSpeedDown(CL.Message))
|
||||||
// break;
|
// + "/s"; break;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//case 302: {
|
// case 301: {
|
||||||
// // Total download
|
// // Total Upload
|
||||||
// CL.Message = FormatBytes(vinstance->getAllDataDown());
|
// CL.Message =
|
||||||
// break;
|
// FormatBytes(vinstance->getAllDataUp()); break;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//case 303: {
|
// case 302: {
|
||||||
// // Upload for tag
|
// // Total download
|
||||||
// CL.Message = FormatBytes(vinstance->getTagDataUp(CL.Message));
|
// CL.Message =
|
||||||
// break;
|
// FormatBytes(vinstance->getAllDataDown());
|
||||||
//}
|
// break;
|
||||||
//
|
//}
|
||||||
//case 304: {
|
//
|
||||||
// // Download for tag
|
// case 303: {
|
||||||
// CL.Message = FormatBytes(vinstance->getTagDataDown(CL.Message));
|
// // Upload for tag
|
||||||
// break;
|
// 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?";
|
CL.Message = "Not Supported?";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -153,5 +173,5 @@ namespace Qv2ray::components::plugins
|
|||||||
reply = StructToJsonString(BarConfig);
|
reply = StructToJsonString(BarConfig);
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Toolbar
|
||||||
}
|
} // namespace Qv2ray::components::plugins
|
||||||
|
@ -9,25 +9,23 @@ namespace Qv2ray::components::plugins
|
|||||||
namespace Toolbar
|
namespace Toolbar
|
||||||
{
|
{
|
||||||
/// NO NOT CHANGE THE ORDER
|
/// NO NOT CHANGE THE ORDER
|
||||||
static const QMap<int, QString> NetSpeedPluginMessages {
|
static const QMap<int, QString> NetSpeedPluginMessages{ { 0, QObject::tr("Custom Text") },
|
||||||
{ 0, QObject::tr("Custom Text")},
|
// Current Status
|
||||||
// Current Status
|
{ 101, QObject::tr("Current Time") },
|
||||||
{ 101, QObject::tr("Current Time") },
|
{ 102, QObject::tr("Current Date") },
|
||||||
{ 102, QObject::tr("Current Date") },
|
{ 103, QObject::tr("Current Qv2ray Version") },
|
||||||
{ 103, QObject::tr("Current Qv2ray Version") },
|
{ 104, QObject::tr("Current Connection Name") },
|
||||||
{ 104, QObject::tr("Current Connection Name") },
|
{ 105, QObject::tr("Current Connection Status") },
|
||||||
{ 105, QObject::tr("Current Connection Status") },
|
// Speeds
|
||||||
// Speeds
|
{ 201, QObject::tr("Total Upload Speed") },
|
||||||
{ 201, QObject::tr("Total Upload Speed") },
|
{ 202, QObject::tr("Total Download Speed") },
|
||||||
{ 202, QObject::tr("Total Download Speed") },
|
{ 203, QObject::tr("Upload Speed for Specific Tag") },
|
||||||
{ 203, QObject::tr("Upload Speed for Specific Tag") },
|
{ 204, QObject::tr("Download Speed for Specific Tag") },
|
||||||
{ 204, QObject::tr("Download Speed for Specific Tag") },
|
// Datas
|
||||||
// Datas
|
{ 301, QObject::tr("Total Uploaded Data") },
|
||||||
{ 301, QObject::tr("Total Uploaded Data") },
|
{ 302, QObject::tr("Total Downloaded Data") },
|
||||||
{ 302, QObject::tr("Total Downloaded Data") },
|
{ 303, QObject::tr("Uploaded Data for Specific Tag") },
|
||||||
{ 303, QObject::tr("Uploaded Data for Specific Tag") },
|
{ 304, QObject::tr("Downloaded Data for Specific Tag") } };
|
||||||
{ 304, QObject::tr("Downloaded Data for Specific Tag") }
|
|
||||||
};
|
|
||||||
void StartProcessingPlugins();
|
void StartProcessingPlugins();
|
||||||
void StopProcessingPlugins();
|
void StopProcessingPlugins();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@ -35,7 +33,7 @@ namespace Qv2ray::components::plugins
|
|||||||
{
|
{
|
||||||
void StartNamedPipeThread();
|
void StartNamedPipeThread();
|
||||||
void KillNamedPipeThread();
|
void KillNamedPipeThread();
|
||||||
}
|
} // namespace _win
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
namespace _linux
|
namespace _linux
|
||||||
@ -45,13 +43,12 @@ namespace Qv2ray::components::plugins
|
|||||||
void StartMessageQThread();
|
void StartMessageQThread();
|
||||||
void StopMessageQThread();
|
void StopMessageQThread();
|
||||||
|
|
||||||
}
|
} // namespace _linux
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString GetAnswerToRequest(const QString &pchRequest);
|
QString GetAnswerToRequest(const QString &pchRequest);
|
||||||
}
|
} // namespace Toolbar
|
||||||
}
|
} // namespace Qv2ray::components::plugins
|
||||||
|
|
||||||
using namespace Qv2ray::components;
|
using namespace Qv2ray::components;
|
||||||
using namespace Qv2ray::components::plugins::Toolbar;
|
using namespace Qv2ray::components::plugins::Toolbar;
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "components/plugins/toolbar/QvToolbar.hpp"
|
||||||
#include <QLocalSocket>
|
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
namespace Qv2ray::components::plugins::Toolbar
|
namespace Qv2ray::components::plugins::Toolbar
|
||||||
{
|
{
|
||||||
namespace _linux
|
namespace _linux
|
||||||
@ -16,35 +17,43 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
{
|
{
|
||||||
QLocalSocket *socket = server->nextPendingConnection();
|
QLocalSocket *socket = server->nextPendingConnection();
|
||||||
|
|
||||||
if (!socket->waitForConnected() || !socket->waitForReadyRead())
|
if (!socket->waitForConnected() || !socket->waitForReadyRead()) return;
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
try
|
||||||
while (!isExiting && socket->isOpen() && socket->isValid() && socket->waitForReadyRead()) {
|
{
|
||||||
|
while (!isExiting && socket->isOpen() && socket->isValid() && socket->waitForReadyRead())
|
||||||
|
{
|
||||||
// CANNOT PROPERLY READ...
|
// CANNOT PROPERLY READ...
|
||||||
// Temp-ly fixed (but why and how?)
|
// Temp-ly fixed (but why and how?)
|
||||||
auto in = QString(socket->readAll());
|
auto in = QString(socket->readAll());
|
||||||
|
|
||||||
if (!isExiting && !in.isEmpty()) {
|
if (!isExiting && !in.isEmpty())
|
||||||
|
{
|
||||||
auto out = GetAnswerToRequest(in);
|
auto out = GetAnswerToRequest(in);
|
||||||
//
|
//
|
||||||
socket->write(out.toUtf8());
|
socket->write(out.toUtf8());
|
||||||
socket->flush();
|
socket->flush();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
QThread::msleep(200);
|
QThread::msleep(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
LOG(MODULE_PLUGIN, "Closing a broken socket.")
|
LOG(MODULE_PLUGIN, "Closing a broken socket.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DataMessageQThread()
|
void DataMessageQThread()
|
||||||
{
|
{
|
||||||
server = new QLocalServer();
|
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);
|
bool listening = server->listen(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_LINUX);
|
||||||
|
|
||||||
while (!isExiting && !listening) {
|
while (!isExiting && !listening)
|
||||||
|
{
|
||||||
QThread::msleep(500);
|
QThread::msleep(500);
|
||||||
listening = server->listen(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_LINUX);
|
listening = server->listen(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_LINUX);
|
||||||
}
|
}
|
||||||
@ -53,7 +62,8 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
server->setSocketOptions(QLocalServer::WorldAccessOption);
|
server->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||||
QObject::connect(server, &QLocalServer::newConnection, &qobject_proxy);
|
QObject::connect(server, &QLocalServer::newConnection, &qobject_proxy);
|
||||||
|
|
||||||
while (!isExiting) {
|
while (!isExiting)
|
||||||
|
{
|
||||||
bool result = server->waitForNewConnection(5000, &timeOut);
|
bool result = server->waitForNewConnection(5000, &timeOut);
|
||||||
DEBUG(MODULE_PLUGIN, "Plugin thread listening failed: " + server->errorString())
|
DEBUG(MODULE_PLUGIN, "Plugin thread listening failed: " + server->errorString())
|
||||||
DEBUG(MODULE_PLUGIN, "waitForNewConnection: " + QString(result ? "true" : "false") + ", " + QString(timeOut ? "true" : "false"))
|
DEBUG(MODULE_PLUGIN, "waitForNewConnection: " + QString(result ? "true" : "false") + ", " + QString(timeOut ? "true" : "false"))
|
||||||
@ -72,13 +82,14 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
{
|
{
|
||||||
isExiting = true;
|
isExiting = true;
|
||||||
|
|
||||||
if (linuxWorkerThread->isRunning()) {
|
if (linuxWorkerThread->isRunning())
|
||||||
|
{
|
||||||
LOG(MODULE_PLUGIN, "Waiting for linuxWorkerThread to stop.")
|
LOG(MODULE_PLUGIN, "Waiting for linuxWorkerThread to stop.")
|
||||||
linuxWorkerThread->wait();
|
linuxWorkerThread->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete _linux::linuxWorkerThread;
|
delete _linux::linuxWorkerThread;
|
||||||
}
|
}
|
||||||
}
|
} // namespace _linux
|
||||||
}
|
} // namespace Qv2ray::components::plugins::Toolbar
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "components/plugins/toolbar/QvToolbar.hpp"
|
||||||
#include <windows.h>
|
|
||||||
|
#include <windows.h>
|
||||||
namespace Qv2ray::components::plugins::Toolbar
|
namespace Qv2ray::components::plugins::Toolbar
|
||||||
{
|
{
|
||||||
namespace _win
|
namespace _win
|
||||||
@ -25,40 +26,53 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
{
|
{
|
||||||
auto hThread = CreateThread(nullptr, 0, NamedPipeMasterThread, nullptr, 0, nullptr);
|
auto hThread = CreateThread(nullptr, 0, NamedPipeMasterThread, nullptr, 0, nullptr);
|
||||||
|
|
||||||
if (hThread == nullptr) {
|
if (hThread == nullptr)
|
||||||
|
{
|
||||||
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
|
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
|
||||||
return;
|
return;
|
||||||
} else CloseHandle(hThread);
|
}
|
||||||
|
else
|
||||||
|
CloseHandle(hThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI NamedPipeMasterThread(LPVOID lpvParam)
|
DWORD WINAPI NamedPipeMasterThread(LPVOID lpvParam)
|
||||||
{
|
{
|
||||||
Q_UNUSED(lpvParam)
|
Q_UNUSED(lpvParam)
|
||||||
BOOL fConnected = FALSE;
|
BOOL fConnected = FALSE;
|
||||||
DWORD dwThreadId = 0;
|
DWORD dwThreadId = 0;
|
||||||
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
||||||
auto lpszPipename = QString(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_WIN).toStdWString();
|
auto lpszPipename = QString(QV2RAY_NETSPEED_PLUGIN_PIPE_NAME_WIN).toStdWString();
|
||||||
|
|
||||||
while (!isExiting) {
|
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);
|
// 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()))
|
LOG(MODULE_PLUGIN, "CreateNamedPipe failed, GLE=" + QSTRN(GetLastError()))
|
||||||
return static_cast<DWORD>(-1);
|
return static_cast<DWORD>(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fConnected = ConnectNamedPipe(hPipe, nullptr) ? true : (GetLastError() == ERROR_PIPE_CONNECTED);
|
fConnected = ConnectNamedPipe(hPipe, nullptr) ? true : (GetLastError() == ERROR_PIPE_CONNECTED);
|
||||||
|
|
||||||
if (fConnected) {
|
if (fConnected)
|
||||||
|
{
|
||||||
LOG(MODULE_PLUGIN, "Client connected, creating a processing thread")
|
LOG(MODULE_PLUGIN, "Client connected, creating a processing thread")
|
||||||
ThreadHandle = CreateThread(nullptr, 0, InstanceThread, hPipe, 0, &dwThreadId);
|
ThreadHandle = CreateThread(nullptr, 0, InstanceThread, hPipe, 0, &dwThreadId);
|
||||||
|
|
||||||
if (ThreadHandle == nullptr) {
|
if (ThreadHandle == nullptr)
|
||||||
|
{
|
||||||
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
|
LOG(MODULE_PLUGIN, "CreateThread failed, GLE=" + QSTRN(GetLastError()))
|
||||||
return static_cast<DWORD>(-1);
|
return static_cast<DWORD>(-1);
|
||||||
} else CloseHandle(ThreadHandle);
|
}
|
||||||
} else CloseHandle(hPipe);
|
else
|
||||||
|
CloseHandle(ThreadHandle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CloseHandle(hPipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -71,13 +85,16 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
HANDLE hPipe = static_cast<HANDLE>(lpvParam);
|
HANDLE hPipe = static_cast<HANDLE>(lpvParam);
|
||||||
TCHAR pchRequest[BUFSIZE] = { 0 };
|
TCHAR pchRequest[BUFSIZE] = { 0 };
|
||||||
|
|
||||||
while (!isExiting) {
|
while (!isExiting)
|
||||||
|
{
|
||||||
fSuccess = ReadFile(hPipe, pchRequest, BUFSIZE * sizeof(TCHAR), &cbBytesRead, nullptr);
|
fSuccess = ReadFile(hPipe, pchRequest, BUFSIZE * sizeof(TCHAR), &cbBytesRead, nullptr);
|
||||||
|
|
||||||
if (!fSuccess || cbBytesRead == 0) {
|
if (!fSuccess || cbBytesRead == 0)
|
||||||
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
{
|
||||||
LOG(MODULE_PLUGIN, "InstanceThread: client disconnected, GLE=" + QSTRN(GetLastError()))
|
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||||
} else {
|
{ LOG(MODULE_PLUGIN, "InstanceThread: client disconnected, GLE=" + QSTRN(GetLastError())) }
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_PLUGIN, "InstanceThread ReadFile failed, GLE=" + QSTRN(GetLastError()))
|
LOG(MODULE_PLUGIN, "InstanceThread ReadFile failed, GLE=" + QSTRN(GetLastError()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,17 +104,20 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
auto req = QString::fromStdWString(pchRequest);
|
auto req = QString::fromStdWString(pchRequest);
|
||||||
QString replyQString = "{}";
|
QString replyQString = "{}";
|
||||||
|
|
||||||
if (!isExiting) {
|
if (!isExiting)
|
||||||
|
{
|
||||||
replyQString = GetAnswerToRequest(req);
|
replyQString = GetAnswerToRequest(req);
|
||||||
//
|
//
|
||||||
// REPLY as std::string
|
// REPLY as std::string
|
||||||
std::string pchReply = replyQString.toUtf8().constData();
|
std::string pchReply = replyQString.toUtf8().constData();
|
||||||
cbReplyBytes = static_cast<DWORD>(pchReply.length() + 1) * sizeof(CHAR);
|
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);
|
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()))
|
LOG(MODULE_PLUGIN, "InstanceThread WriteFile failed, GLE=" + QSTRN(GetLastError()))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -109,6 +129,6 @@ namespace Qv2ray::components::plugins::Toolbar
|
|||||||
CloseHandle(hPipe);
|
CloseHandle(hPipe);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
} // namespace _win
|
||||||
}
|
} // namespace Qv2ray::components::plugins::Toolbar
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "QvProxyConfigurator.hpp"
|
#include "QvProxyConfigurator.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "wininet.h"
|
#include "wininet.h"
|
||||||
#include <windows.h>
|
|
||||||
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Qv2ray::components::proxy
|
namespace Qv2ray::components::proxy
|
||||||
@ -23,11 +25,10 @@ namespace Qv2ray::components::proxy
|
|||||||
QStringList result;
|
QStringList result;
|
||||||
|
|
||||||
// Start from 1 since first line is unneeded.
|
// 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.
|
// * means disabled.
|
||||||
if (!lines[i].contains("*")) {
|
if (!lines[i].contains("*")) { result << (lines[i].contains(" ") ? "\"" + lines[i] + "\"" : lines[i]); }
|
||||||
result << (lines[i].contains(" ") ? "\"" + lines[i] + "\"" : lines[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(MODULE_PROXY, "Found " + QSTRN(result.size()) + " network services: " + result.join(";"))
|
LOG(MODULE_PROXY, "Found " + QSTRN(result.size()) + " network services: " + result.join(";"))
|
||||||
@ -35,8 +36,9 @@ namespace Qv2ray::components::proxy
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#define NO_CONST(expr) const_cast<wchar_t *>(expr)
|
#define NO_CONST(expr) const_cast<wchar_t *>(expr)
|
||||||
//static auto DEFAULT_CONNECTION_NAME = NO_CONST(L"DefaultConnectionSettings");
|
// static auto DEFAULT_CONNECTION_NAME =
|
||||||
|
// NO_CONST(L"DefaultConnectionSettings");
|
||||||
///
|
///
|
||||||
/// INTERNAL FUNCTION
|
/// INTERNAL FUNCTION
|
||||||
bool __QueryProxyOptions()
|
bool __QueryProxyOptions()
|
||||||
@ -52,81 +54,64 @@ namespace Qv2ray::components::proxy
|
|||||||
Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
|
Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
|
||||||
//
|
//
|
||||||
List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
|
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.dwOptionCount = 5;
|
||||||
List.dwOptionError = 0;
|
List.dwOptionError = 0;
|
||||||
List.pOptions = Option;
|
List.pOptions = Option;
|
||||||
|
|
||||||
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
|
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
|
||||||
LOG(MODULE_PROXY, "InternetQueryOption failed, GLE=" + QSTRN(GetLastError()))
|
{ LOG(MODULE_PROXY, "InternetQueryOption failed, GLE=" + QSTRN(GetLastError())) }
|
||||||
}
|
|
||||||
|
|
||||||
LOG(MODULE_PROXY, "System default proxy info:")
|
LOG(MODULE_PROXY, "System default proxy info:")
|
||||||
|
|
||||||
if (Option[0].Value.pszValue != nullptr) {
|
if (Option[0].Value.pszValue != nullptr) { LOG(MODULE_PROXY, QString::fromWCharArray(Option[0].Value.pszValue)) }
|
||||||
LOG(MODULE_PROXY, QString::fromWCharArray(Option[0].Value.pszValue))
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == 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")
|
{ LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_PROXY_URL") }
|
||||||
}
|
|
||||||
|
|
||||||
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) {
|
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) { LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_DETECT") }
|
||||||
LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_DETECT")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) {
|
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) { LOG(MODULE_PROXY, "PROXY_TYPE_DIRECT") }
|
||||||
LOG(MODULE_PROXY, "PROXY_TYPE_DIRECT")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) {
|
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) { LOG(MODULE_PROXY, "PROXY_TYPE_PROXY") }
|
||||||
LOG(MODULE_PROXY, "PROXY_TYPE_PROXY")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
|
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
|
||||||
LOG(MODULE_PROXY, "InternetQueryOption failed,GLE=" + QSTRN(GetLastError()))
|
{ LOG(MODULE_PROXY, "InternetQueryOption failed,GLE=" + QSTRN(GetLastError())) }
|
||||||
}
|
|
||||||
|
|
||||||
if (Option[4].Value.pszValue != nullptr) {
|
if (Option[4].Value.pszValue != nullptr) { LOG(MODULE_PROXY, QString::fromStdWString(Option[4].Value.pszValue)) }
|
||||||
LOG(MODULE_PROXY, QString::fromStdWString(Option[4].Value.pszValue))
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNET_VERSION_INFO Version;
|
INTERNET_VERSION_INFO Version;
|
||||||
nSize = sizeof(INTERNET_VERSION_INFO);
|
nSize = sizeof(INTERNET_VERSION_INFO);
|
||||||
InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize);
|
InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize);
|
||||||
|
|
||||||
if (Option[0].Value.pszValue != nullptr) {
|
if (Option[0].Value.pszValue != nullptr) { GlobalFree(Option[0].Value.pszValue); }
|
||||||
GlobalFree(Option[0].Value.pszValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Option[3].Value.pszValue != nullptr) {
|
if (Option[3].Value.pszValue != nullptr) { GlobalFree(Option[3].Value.pszValue); }
|
||||||
GlobalFree(Option[3].Value.pszValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Option[4].Value.pszValue != nullptr) {
|
if (Option[4].Value.pszValue != nullptr) { GlobalFree(Option[4].Value.pszValue); }
|
||||||
GlobalFree(Option[4].Value.pszValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC)
|
bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC)
|
||||||
{
|
{
|
||||||
INTERNET_PER_CONN_OPTION_LIST list;
|
INTERNET_PER_CONN_OPTION_LIST list;
|
||||||
BOOL bReturn;
|
BOOL bReturn;
|
||||||
DWORD dwBufSize = sizeof(list);
|
DWORD dwBufSize = sizeof(list);
|
||||||
// Fill the list structure.
|
// Fill the list structure.
|
||||||
list.dwSize = sizeof(list);
|
list.dwSize = sizeof(list);
|
||||||
// NULL == LAN, otherwise connectoid name.
|
// NULL == LAN, otherwise connectoid name.
|
||||||
list.pszConnection = nullptr;
|
list.pszConnection = nullptr;
|
||||||
|
|
||||||
if (isPAC) {
|
if (isPAC)
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Setting system proxy for PAC")
|
LOG(MODULE_PROXY, "Setting system proxy for PAC")
|
||||||
//
|
//
|
||||||
list.dwOptionCount = 2;
|
list.dwOptionCount = 2;
|
||||||
list.pOptions = new INTERNET_PER_CONN_OPTION[2];
|
list.pOptions = new INTERNET_PER_CONN_OPTION[2];
|
||||||
|
|
||||||
// Ensure that the memory was allocated.
|
// Ensure that the memory was allocated.
|
||||||
if (nullptr == list.pOptions) {
|
if (nullptr == list.pOptions)
|
||||||
|
{
|
||||||
// Return FALSE if the memory wasn't allocated.
|
// Return FALSE if the memory wasn't allocated.
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -137,15 +122,15 @@ namespace Qv2ray::components::proxy
|
|||||||
// Set proxy name.
|
// Set proxy name.
|
||||||
list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
|
list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
|
||||||
list.pOptions[1].Value.pszValue = proxy_full_addr;
|
list.pOptions[1].Value.pszValue = proxy_full_addr;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Setting system proxy for Global Proxy")
|
LOG(MODULE_PROXY, "Setting system proxy for Global Proxy")
|
||||||
//
|
//
|
||||||
list.dwOptionCount = 3;
|
list.dwOptionCount = 3;
|
||||||
list.pOptions = new INTERNET_PER_CONN_OPTION[3];
|
list.pOptions = new INTERNET_PER_CONN_OPTION[3];
|
||||||
|
|
||||||
if (nullptr == list.pOptions) {
|
if (nullptr == list.pOptions) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set flags.
|
// Set flags.
|
||||||
list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
|
list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
|
||||||
@ -161,7 +146,7 @@ namespace Qv2ray::components::proxy
|
|||||||
|
|
||||||
// Set the options on the connection.
|
// Set the options on the connection.
|
||||||
bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
|
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_SETTINGS_CHANGED, nullptr, 0);
|
||||||
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
||||||
return bReturn;
|
return bReturn;
|
||||||
@ -173,29 +158,26 @@ namespace Qv2ray::components::proxy
|
|||||||
bool hasHTTP = (httpPort != 0);
|
bool hasHTTP = (httpPort != 0);
|
||||||
bool hasSOCKS = (socksPort != 0);
|
bool hasSOCKS = (socksPort != 0);
|
||||||
|
|
||||||
if (!(hasHTTP || hasSOCKS || usePAC)) {
|
if (!(hasHTTP || hasSOCKS || usePAC))
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Nothing?")
|
LOG(MODULE_PROXY, "Nothing?")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usePAC) {
|
if (usePAC) { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use PAC file") }
|
||||||
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use PAC file")
|
else
|
||||||
} else {
|
{
|
||||||
if (hasHTTP) {
|
if (hasHTTP) { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use HTTP") }
|
||||||
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use HTTP")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasSOCKS) {
|
if (hasSOCKS) { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use SOCKS") }
|
||||||
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use SOCKS")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QString __a;
|
QString __a;
|
||||||
|
|
||||||
if (usePAC) {
|
if (usePAC) { __a = address; }
|
||||||
__a = address;
|
else
|
||||||
} else {
|
{
|
||||||
__a = (hasHTTP ? "http://" : "socks5://") + address + ":" + QSTRN(httpPort);
|
__a = (hasHTTP ? "http://" : "socks5://") + address + ":" + QSTRN(httpPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,9 +187,7 @@ namespace Qv2ray::components::proxy
|
|||||||
//
|
//
|
||||||
__QueryProxyOptions();
|
__QueryProxyOptions();
|
||||||
|
|
||||||
if (!__SetProxyOptions(proxyStrW, usePAC)) {
|
if (!__SetProxyOptions(proxyStrW, usePAC)) { LOG(MODULE_PROXY, "Failed to set proxy.") }
|
||||||
LOG(MODULE_PROXY, "Failed to set proxy.")
|
|
||||||
}
|
|
||||||
|
|
||||||
__QueryProxyOptions();
|
__QueryProxyOptions();
|
||||||
#elif defined(Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX)
|
||||||
@ -215,18 +195,21 @@ namespace Qv2ray::components::proxy
|
|||||||
auto proxyMode = usePAC ? "auto" : "manual";
|
auto proxyMode = usePAC ? "auto" : "manual";
|
||||||
actions << QString("gsettings set org.gnome.system.proxy mode '%1'").arg(proxyMode);
|
actions << QString("gsettings set org.gnome.system.proxy mode '%1'").arg(proxyMode);
|
||||||
|
|
||||||
if (usePAC) {
|
if (usePAC) { actions << QString("gsettings set org.gnome.system.proxy autoconfig-url '%1'").arg(address); }
|
||||||
actions << QString("gsettings set org.gnome.system.proxy autoconfig-url '%1'").arg(address);
|
else
|
||||||
} else {
|
{
|
||||||
if (hasHTTP) {
|
if (hasHTTP)
|
||||||
|
{
|
||||||
actions << QString("gsettings set org.gnome.system.proxy.http host '%1'").arg(address);
|
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.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 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 host '%1'").arg(address);
|
||||||
actions << QString("gsettings set org.gnome.system.proxy.socks port %1").arg(socksPort);
|
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,
|
// note: do not use std::all_of / any_of / none_of,
|
||||||
// because those are short-circuit and cannot guarantee atomicity.
|
// because those are short-circuit and cannot guarantee atomicity.
|
||||||
auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString & action) {
|
auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString &action) {
|
||||||
DEBUG(MODULE_PROXY, action)
|
DEBUG(MODULE_PROXY, action)
|
||||||
return QProcess::execute(action) == QProcess::NormalExit;
|
return QProcess::execute(action) == QProcess::NormalExit;
|
||||||
}) == actions.size();
|
}) == actions.size();
|
||||||
|
|
||||||
if (!result) {
|
if (!result)
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Something wrong happens when setting system proxy -> Gnome ONLY.")
|
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.")
|
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);
|
Q_UNUSED(result);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
for (auto service : macOSgetNetworkServices()) {
|
for (auto service : macOSgetNetworkServices())
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Setting proxy for interface: " + service)
|
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 -setautoproxystate " + service + " on");
|
||||||
QProcess::execute("/usr/sbin/networksetup -setautoproxyurl " + service + " " + address);
|
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 -setwebproxystate " + service + " on");
|
||||||
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxystate " + 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 -setwebproxy " + service + " " + address + " " + QSTRN(httpPort));
|
||||||
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxy " + 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 -setsocksfirewallproxystate " + service + " on");
|
||||||
QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxy " + service + " " + address + " " + QSTRN(socksPort));
|
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];
|
list.pOptions = new INTERNET_PER_CONN_OPTION[list.dwOptionCount];
|
||||||
|
|
||||||
// Make sure the memory was allocated.
|
// Make sure the memory was allocated.
|
||||||
if (nullptr == list.pOptions) {
|
if (nullptr == list.pOptions)
|
||||||
|
{
|
||||||
// Return FALSE if the memory wasn't allocated.
|
// Return FALSE if the memory wasn't allocated.
|
||||||
LOG(MODULE_PROXY, "Failed to allocat memory in DisableConnectionProxy()")
|
LOG(MODULE_PROXY, "Failed to allocat memory in DisableConnectionProxy()")
|
||||||
}
|
}
|
||||||
@ -298,14 +289,15 @@ namespace Qv2ray::components::proxy
|
|||||||
//
|
//
|
||||||
// Set the options on the connection.
|
// Set the options on the connection.
|
||||||
bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
|
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_SETTINGS_CHANGED, nullptr, 0);
|
||||||
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
||||||
#elif defined(Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX)
|
||||||
QProcess::execute("gsettings set org.gnome.system.proxy mode 'none'");
|
QProcess::execute("gsettings set org.gnome.system.proxy mode 'none'");
|
||||||
#else
|
#else
|
||||||
|
|
||||||
for (auto service : macOSgetNetworkServices()) {
|
for (auto service : macOSgetNetworkServices())
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Clearing proxy for interface: " + service)
|
LOG(MODULE_PROXY, "Clearing proxy for interface: " + service)
|
||||||
QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " off");
|
QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " off");
|
||||||
QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " off");
|
QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " off");
|
||||||
@ -315,4 +307,4 @@ namespace Qv2ray::components::proxy
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::components::proxy
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
//
|
//
|
||||||
namespace Qv2ray::components::proxy
|
namespace Qv2ray::components::proxy
|
||||||
{
|
{
|
||||||
void ClearSystemProxy();
|
void ClearSystemProxy();
|
||||||
void SetSystemProxy(const QString &address, int http_port, int socks_port, bool usePAC);
|
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;
|
||||||
using namespace Qv2ray::components::proxy;
|
using namespace Qv2ray::components::proxy;
|
||||||
|
@ -14,39 +14,40 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* 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
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
* 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),
|
* 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
|
* 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
|
* License in all respects for all of the code used other than "OpenSSL". If
|
||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* you modify file(s), you may extend this exception to your version of the
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||||
* exception statement from your version.
|
* delete this exception statement from your version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "speedplotview.hpp"
|
#include "speedplotview.hpp"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPen>
|
#include <QPen>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
|
|
||||||
#define VIEWABLE 120
|
#define VIEWABLE 120
|
||||||
|
|
||||||
// use binary prefix standards from IEC 60027-2
|
// use binary prefix standards from IEC 60027-2
|
||||||
// see http://en.wikipedia.org/wiki/Kilobyte
|
// see http://en.wikipedia.org/wiki/Kilobyte
|
||||||
enum class SizeUnit {
|
enum class SizeUnit
|
||||||
Byte, // 1024^0,
|
{
|
||||||
KibiByte, // 1024^1,
|
Byte, // 1024^0,
|
||||||
MebiByte, // 1024^2,
|
KibiByte, // 1024^1,
|
||||||
GibiByte, // 1024^3,
|
MebiByte, // 1024^2,
|
||||||
TebiByte, // 1024^4,
|
GibiByte, // 1024^3,
|
||||||
PebiByte, // 1024^5,
|
TebiByte, // 1024^4,
|
||||||
ExbiByte // 1024^6,
|
PebiByte, // 1024^5,
|
||||||
|
ExbiByte // 1024^6,
|
||||||
// int64 is used for sizes and thus the next units can not be handled
|
// int64 is used for sizes and thus the next units can not be handled
|
||||||
// ZebiByte, // 1024^7,
|
// ZebiByte, // 1024^7,
|
||||||
// YobiByte, // 1024^8
|
// YobiByte, // 1024^8
|
||||||
@ -54,27 +55,25 @@ enum class SizeUnit {
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const struct {
|
const struct
|
||||||
|
{
|
||||||
const char *source;
|
const char *source;
|
||||||
const char *comment;
|
const char *comment;
|
||||||
} units[] = {
|
} units[] = { QT_TRANSLATE_NOOP3("misc", "B", "bytes"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "B", "bytes"),
|
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
|
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
|
QT_TRANSLATE_NOOP3("misc", "GiB", "gibibytes (1024 mibibytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "GiB", "gibibytes (1024 mibibytes)"),
|
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)"),
|
QT_TRANSLATE_NOOP3("misc", "PiB", "pebibytes (1024 tebibytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "PiB", "pebibytes (1024 tebibytes)"),
|
QT_TRANSLATE_NOOP3("misc", "EiB", "exbibytes (1024 pebibytes)") };
|
||||||
QT_TRANSLATE_NOOP3("misc", "EiB", "exbibytes (1024 pebibytes)")
|
} // namespace
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
QString unitString(const SizeUnit unit, const bool isSpeed)
|
QString unitString(const SizeUnit unit, const bool isSpeed)
|
||||||
{
|
{
|
||||||
const auto &unitString = units[static_cast<int>(unit)];
|
const auto &unitString = units[static_cast<int>(unit)];
|
||||||
QString ret = QCoreApplication::translate("misc", unitString.source, unitString.comment);
|
QString ret = QCoreApplication::translate("misc", unitString.source, unitString.comment);
|
||||||
|
|
||||||
if (isSpeed)
|
if (isSpeed) ret += QCoreApplication::translate("misc", "/s", "per second");
|
||||||
ret += QCoreApplication::translate("misc", "/s", "per second");
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -82,36 +81,34 @@ QString unitString(const SizeUnit unit, const bool isSpeed)
|
|||||||
int friendlyUnitPrecision(const SizeUnit unit)
|
int friendlyUnitPrecision(const SizeUnit unit)
|
||||||
{
|
{
|
||||||
// friendlyUnit's number of digits after the decimal point
|
// friendlyUnit's number of digits after the decimal point
|
||||||
switch (unit) {
|
switch (unit)
|
||||||
case SizeUnit::Byte:
|
{
|
||||||
return 0;
|
case SizeUnit::Byte: return 0;
|
||||||
|
|
||||||
case SizeUnit::KibiByte:
|
case SizeUnit::KibiByte:
|
||||||
case SizeUnit::MebiByte:
|
case SizeUnit::MebiByte: return 1;
|
||||||
return 1;
|
|
||||||
|
|
||||||
case SizeUnit::GibiByte:
|
case SizeUnit::GibiByte: return 2;
|
||||||
return 2;
|
|
||||||
|
|
||||||
default:
|
default: return 3;
|
||||||
return 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qlonglong sizeInBytes(qreal size, const SizeUnit unit)
|
qlonglong sizeInBytes(qreal size, const SizeUnit unit)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < static_cast<int>(unit); ++i)
|
for (int i = 0; i < static_cast<int>(unit); ++i) size *= 1024;
|
||||||
size *= 1024;
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// table of supposed nice steps for grid marks to get nice looking quarters of scale
|
// table of supposed nice steps for grid marks to get nice looking quarters
|
||||||
const double roundingTable[] = {1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8};
|
// 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;
|
double arg;
|
||||||
SizeUnit unit;
|
SizeUnit unit;
|
||||||
qint64 sizeInBytes() const
|
qint64 sizeInBytes() const
|
||||||
@ -122,56 +119,53 @@ namespace
|
|||||||
|
|
||||||
SplittedValue getRoundedYScale(double value)
|
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;
|
SizeUnit calculatedUnit = SizeUnit::Byte;
|
||||||
|
|
||||||
while (value > 1024) {
|
while (value > 1024)
|
||||||
|
{
|
||||||
value /= 1024;
|
value /= 1024;
|
||||||
calculatedUnit = static_cast<SizeUnit>(static_cast<int>(calculatedUnit) + 1);
|
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;
|
int roundedValue = static_cast<int>(value / 40) * 40;
|
||||||
|
|
||||||
while (roundedValue < value)
|
while (roundedValue < value) roundedValue += 40;
|
||||||
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;
|
int roundedValue = static_cast<int>(value / 4) * 4;
|
||||||
|
|
||||||
while (roundedValue < value)
|
while (roundedValue < value) roundedValue += 4;
|
||||||
roundedValue += 4;
|
|
||||||
|
|
||||||
return {static_cast<double>(roundedValue), calculatedUnit};
|
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &roundedValue : roundingTable) {
|
for (const auto &roundedValue : roundingTable)
|
||||||
if (value <= roundedValue)
|
{
|
||||||
return {roundedValue, calculatedUnit};
|
if (value <= roundedValue) return { roundedValue, calculatedUnit };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {10.0, calculatedUnit};
|
return { 10.0, calculatedUnit };
|
||||||
}
|
}
|
||||||
|
|
||||||
QString formatLabel(const double argValue, const SizeUnit unit)
|
QString formatLabel(const double argValue, const SizeUnit unit)
|
||||||
{
|
{
|
||||||
// check is there need for digits after decimal separator
|
// check is there need for digits after decimal separator
|
||||||
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
|
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
|
||||||
return QLocale::system().toString(argValue, 'f', precision)
|
return QLocale::system().toString(argValue, 'f', precision) + QString::fromUtf8(" ") + unitString(unit, true);
|
||||||
+ QString::fromUtf8(" ")
|
|
||||||
+ unitString(unit, true);
|
|
||||||
}
|
}
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
SpeedPlotView::SpeedPlotView(QWidget *parent)
|
SpeedPlotView::SpeedPlotView(QWidget *parent) : QGraphicsView(parent), m_currentData(&m_datahalfMin)
|
||||||
: QGraphicsView(parent)
|
|
||||||
, m_currentData(&m_datahalfMin)
|
|
||||||
{
|
{
|
||||||
QPen greenPen;
|
QPen greenPen;
|
||||||
greenPen.setWidthF(1.5);
|
greenPen.setWidthF(1.5);
|
||||||
@ -193,9 +187,7 @@ void SpeedPlotView::pushPoint(const SpeedPlotView::PointData &point)
|
|||||||
{
|
{
|
||||||
m_datahalfMin.push_back(point);
|
m_datahalfMin.push_back(point);
|
||||||
|
|
||||||
while (m_datahalfMin.length() > VIEWABLE) {
|
while (m_datahalfMin.length() > VIEWABLE) { m_datahalfMin.removeFirst(); }
|
||||||
m_datahalfMin.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpeedPlotView::replot()
|
void SpeedPlotView::replot()
|
||||||
@ -213,11 +205,12 @@ quint64 SpeedPlotView::maxYValue()
|
|||||||
auto &queue = getCurrentData();
|
auto &queue = getCurrentData();
|
||||||
quint64 maxYValue = 0;
|
quint64 maxYValue = 0;
|
||||||
|
|
||||||
for (int id = UP; id < NB_GRAPHS; ++id) {
|
for (int id = UP; id < NB_GRAPHS; ++id)
|
||||||
|
{
|
||||||
// 30 is half min
|
// 30 is half min
|
||||||
for (int i = queue.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j) {
|
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];
|
if (queue[i].y[id] > maxYValue) maxYValue = queue[i].y[id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,12 +237,12 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
|||||||
int yAxisWidth = 0;
|
int yAxisWidth = 0;
|
||||||
|
|
||||||
for (const QString &label : speedLabels)
|
for (const QString &label : speedLabels)
|
||||||
if (fontMetrics.horizontalAdvance(label) > yAxisWidth)
|
if (fontMetrics.horizontalAdvance(label) > yAxisWidth) yAxisWidth = fontMetrics.horizontalAdvance(label);
|
||||||
yAxisWidth = fontMetrics.horizontalAdvance(label);
|
|
||||||
|
|
||||||
int i = 0;
|
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()),
|
QRectF labelRect(rect.topLeft() + QPointF(-yAxisWidth, (i++) * 0.25 * rect.height() - fontMetrics.height()),
|
||||||
QSizeF(2 * yAxisWidth, fontMetrics.height()));
|
QSizeF(2 * yAxisWidth, fontMetrics.height()));
|
||||||
painter.drawText(labelRect, label, Qt::AlignRight | Qt::AlignTop);
|
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());
|
painter.drawLine(fullRect.left(), rect.bottom(), rect.right(), rect.bottom());
|
||||||
const int TIME_AXIS_DIVISIONS = 6;
|
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;
|
const int x = rect.left() + (i * rect.width()) / TIME_AXIS_DIVISIONS;
|
||||||
painter.drawLine(x, fullRect.top(), x, fullRect.bottom());
|
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;
|
const double xTickSize = static_cast<double>(rect.width()) / VIEWABLE;
|
||||||
auto &queue = getCurrentData();
|
auto &queue = getCurrentData();
|
||||||
|
|
||||||
for (int id = UP; id < NB_GRAPHS; ++id) {
|
for (int id = UP; id < NB_GRAPHS; ++id)
|
||||||
|
{
|
||||||
QVector<QPoint> points;
|
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 newX = rect.right() - j * xTickSize;
|
||||||
int newY = rect.bottom() - queue[i].y[id] * yMultiplier;
|
int newY = rect.bottom() - queue[i].y[id] * yMultiplier;
|
||||||
points.push_back(QPoint(newX, newY));
|
points.push_back(QPoint(newX, newY));
|
||||||
@ -300,27 +296,28 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
|||||||
double legendHeight = 0;
|
double legendHeight = 0;
|
||||||
int legendWidth = 0;
|
int legendWidth = 0;
|
||||||
|
|
||||||
for (const auto &property : m_properties) {
|
for (const auto &property : m_properties)
|
||||||
if (fontMetrics.horizontalAdvance(property.name) > legendWidth)
|
{
|
||||||
legendWidth = fontMetrics.horizontalAdvance(property.name);
|
if (fontMetrics.horizontalAdvance(property.name) > legendWidth) legendWidth = fontMetrics.horizontalAdvance(property.name);
|
||||||
|
|
||||||
legendHeight += 1.5 * fontMetrics.height();
|
legendHeight += 1.5 * fontMetrics.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF legendBackgroundRect(QPoint(legendTopLeft.x() - 4, legendTopLeft.y() - 4), QSizeF(legendWidth + 8, legendHeight + 8));
|
QRectF legendBackgroundRect(QPoint(legendTopLeft.x() - 4, legendTopLeft.y() - 4), QSizeF(legendWidth + 8, legendHeight + 8));
|
||||||
QColor legendBackgroundColor = QWidget::palette().color(QWidget::backgroundRole());
|
QColor legendBackgroundColor = QWidget::palette().color(QWidget::backgroundRole());
|
||||||
legendBackgroundColor.setAlpha(128); // 50% transparent
|
legendBackgroundColor.setAlpha(128); // 50% transparent
|
||||||
painter.fillRect(legendBackgroundRect, legendBackgroundColor);
|
painter.fillRect(legendBackgroundRect, legendBackgroundColor);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
for (const auto &property : m_properties) {
|
for (const auto &property : m_properties)
|
||||||
|
{
|
||||||
int nameSize = fontMetrics.horizontalAdvance(property.name);
|
int nameSize = fontMetrics.horizontalAdvance(property.name);
|
||||||
double indent = 1.5 * (i++) * fontMetrics.height();
|
double indent = 1.5 * (i++) * fontMetrics.height();
|
||||||
painter.setPen(property.pen);
|
painter.setPen(property.pen);
|
||||||
painter.drawLine(legendTopLeft + QPointF(0, indent + fontMetrics.height()),
|
painter.drawLine(legendTopLeft + QPointF(0, indent + fontMetrics.height()),
|
||||||
legendTopLeft + QPointF(nameSize, indent + fontMetrics.height()));
|
legendTopLeft + QPointF(nameSize, indent + fontMetrics.height()));
|
||||||
painter.drawText(QRectF(legendTopLeft + QPointF(0, indent), QSizeF(2 * nameSize, fontMetrics.height())),
|
painter.drawText(QRectF(legendTopLeft + QPointF(0, indent), QSizeF(2 * nameSize, fontMetrics.height())), property.name,
|
||||||
property.name, QTextOption(Qt::AlignVCenter));
|
QTextOption(Qt::AlignVCenter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,8 +325,6 @@ SpeedPlotView::GraphProperties::GraphProperties()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SpeedPlotView::GraphProperties::GraphProperties(const QString &name, const QPen &pen)
|
SpeedPlotView::GraphProperties::GraphProperties(const QString &name, const QPen &pen) : name(name), pen(pen)
|
||||||
: name(name)
|
|
||||||
, pen(pen)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -36,43 +36,46 @@ class QPen;
|
|||||||
|
|
||||||
class SpeedPlotView : public QGraphicsView
|
class SpeedPlotView : public QGraphicsView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum GraphID {
|
enum GraphID
|
||||||
UP = 0,
|
{
|
||||||
DOWN,
|
UP = 0,
|
||||||
NB_GRAPHS
|
DOWN,
|
||||||
};
|
NB_GRAPHS
|
||||||
|
};
|
||||||
|
|
||||||
struct PointData {
|
struct PointData
|
||||||
qint64 x;
|
{
|
||||||
quint64 y[NB_GRAPHS];
|
qint64 x;
|
||||||
};
|
quint64 y[NB_GRAPHS];
|
||||||
|
};
|
||||||
|
|
||||||
explicit SpeedPlotView(QWidget *parent = nullptr);
|
explicit SpeedPlotView(QWidget *parent = nullptr);
|
||||||
void pushPoint(const PointData &point);
|
void pushPoint(const PointData &point);
|
||||||
void Clear();
|
void Clear();
|
||||||
void replot();
|
void replot();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct GraphProperties {
|
struct GraphProperties
|
||||||
GraphProperties();
|
{
|
||||||
GraphProperties(const QString &name, const QPen &pen);
|
GraphProperties();
|
||||||
|
GraphProperties(const QString &name, const QPen &pen);
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
QPen pen;
|
QPen pen;
|
||||||
};
|
};
|
||||||
|
|
||||||
quint64 maxYValue();
|
quint64 maxYValue();
|
||||||
QList<PointData> &getCurrentData();
|
QList<PointData> &getCurrentData();
|
||||||
QList<PointData> m_datahalfMin;
|
QList<PointData> m_datahalfMin;
|
||||||
QList<PointData> *m_currentData;
|
QList<PointData> *m_currentData;
|
||||||
|
|
||||||
QMap<GraphID, GraphProperties> m_properties;
|
QMap<GraphID, GraphProperties> m_properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SPEEDPLOTVIEW_H
|
#endif // SPEEDPLOTVIEW_H
|
||||||
|
@ -14,20 +14,23 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* 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
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
* 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),
|
* 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
|
* 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
|
* License in all respects for all of the code used other than "OpenSSL". If
|
||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* you modify file(s), you may extend this exception to your version of the
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||||
* exception statement from your version.
|
* delete this exception statement from your version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "speedwidget.hpp"
|
#include "speedwidget.hpp"
|
||||||
|
|
||||||
|
#include "speedplotview.hpp"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@ -35,10 +38,7 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "speedplotview.hpp"
|
SpeedWidget::SpeedWidget(QWidget *parent) : QWidget(parent)
|
||||||
|
|
||||||
SpeedWidget::SpeedWidget(QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
{
|
||||||
m_layout = new QVBoxLayout(this);
|
m_layout = new QVBoxLayout(this);
|
||||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
@ -52,7 +52,9 @@ SpeedWidget::SpeedWidget(QWidget *parent)
|
|||||||
m_plot->show();
|
m_plot->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
SpeedWidget::~SpeedWidget() {}
|
SpeedWidget::~SpeedWidget()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void SpeedWidget::AddPointData(long up, long down)
|
void SpeedWidget::AddPointData(long up, long down)
|
||||||
{
|
{
|
||||||
|
@ -41,17 +41,18 @@ class SpeedPlotView;
|
|||||||
|
|
||||||
class SpeedWidget : public QWidget
|
class SpeedWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SpeedWidget(QWidget *parent);
|
explicit SpeedWidget(QWidget *parent);
|
||||||
~SpeedWidget();
|
~SpeedWidget();
|
||||||
void AddPointData(long up, long down);
|
void AddPointData(long up, long down);
|
||||||
void Clear();
|
void Clear();
|
||||||
private:
|
|
||||||
QVBoxLayout *m_layout;
|
private:
|
||||||
QHBoxLayout *m_hlayout;
|
QVBoxLayout *m_layout;
|
||||||
SpeedPlotView *m_plot;
|
QHBoxLayout *m_hlayout;
|
||||||
|
SpeedPlotView *m_plot;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SPEEDWIDGET_H
|
#endif // SPEEDWIDGET_H
|
||||||
|
@ -1,38 +1,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QHashFunctions>
|
|
||||||
|
|
||||||
#include "base/models/QvConfigIdentifier.hpp"
|
#include "base/models/QvConfigIdentifier.hpp"
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QHashFunctions>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
namespace Qv2ray::core
|
namespace Qv2ray::core
|
||||||
{
|
{
|
||||||
template <typename T>
|
template<typename T>
|
||||||
class IDType
|
class IDType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit IDType(const QString &id): m_id(id) {}
|
explicit IDType() : m_id("null")
|
||||||
friend bool operator==(const IDType<T> &lhs, const IDType<T> &rhs)
|
{
|
||||||
{
|
}
|
||||||
return lhs.m_id == rhs.m_id;
|
explicit IDType(const QString &id) : m_id(id)
|
||||||
}
|
{
|
||||||
friend bool operator!=(const IDType<T> &lhs, const IDType<T> &rhs)
|
}
|
||||||
{
|
friend bool operator==(const IDType<T> &lhs, const IDType<T> &rhs)
|
||||||
return lhs.toString() != rhs.toString();
|
{
|
||||||
}
|
return lhs.m_id == rhs.m_id;
|
||||||
const QString &toString() const
|
}
|
||||||
{
|
friend bool operator!=(const IDType<T> &lhs, const IDType<T> &rhs)
|
||||||
return m_id;
|
{
|
||||||
}
|
return lhs.toString() != rhs.toString();
|
||||||
uint qHash(uint seed) const
|
}
|
||||||
{
|
const QString &toString() const
|
||||||
return ::qHash(m_id, seed);
|
{
|
||||||
}
|
return m_id;
|
||||||
private:
|
}
|
||||||
QString m_id;
|
uint qHash(uint seed) const
|
||||||
};
|
{
|
||||||
|
return ::qHash(m_id, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_id;
|
||||||
|
};
|
||||||
|
|
||||||
// Define several safetypes to prevent misuse of QString.
|
// Define several safetypes to prevent misuse of QString.
|
||||||
class __QvGroup;
|
class __QvGroup;
|
||||||
@ -48,9 +53,7 @@ namespace Qv2ray::core
|
|||||||
{
|
{
|
||||||
QList<IDType> list;
|
QList<IDType> list;
|
||||||
|
|
||||||
for (auto str : strings) {
|
for (auto str : strings) { list << IDType(str); }
|
||||||
list << IDType(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -60,21 +63,23 @@ namespace Qv2ray::core
|
|||||||
{
|
{
|
||||||
QList<QString> list;
|
QList<QString> list;
|
||||||
|
|
||||||
for (auto id : ids) {
|
for (auto id : ids) { list << id.toString(); }
|
||||||
list << id.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
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);
|
return key.qHash(seed);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
/// Metadata object representing a connection.
|
/// Metadata object representing a connection.
|
||||||
struct ConnectionMetaObject : ConnectionObject_Config {
|
struct ConnectionMetaObject : ConnectionObject_Config
|
||||||
|
{
|
||||||
GroupId groupId = NullGroupId;
|
GroupId groupId = NullGroupId;
|
||||||
ConnectionMetaObject(): ConnectionObject_Config() { }
|
ConnectionMetaObject() : ConnectionObject_Config()
|
||||||
|
{
|
||||||
|
}
|
||||||
// Suger for down casting.
|
// Suger for down casting.
|
||||||
ConnectionMetaObject(const ConnectionObject_Config &base) : ConnectionMetaObject()
|
ConnectionMetaObject(const ConnectionObject_Config &base) : ConnectionMetaObject()
|
||||||
{
|
{
|
||||||
@ -88,13 +93,16 @@ namespace Qv2ray::core
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Metadata object representing a group.
|
/// 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.
|
// Implicit base of two types, since group object is actually the group base object.
|
||||||
bool isSubscription;
|
bool isSubscription;
|
||||||
QList<ConnectionId> connections;
|
QList<ConnectionId> connections;
|
||||||
// Suger for down casting.
|
// Suger for down casting.
|
||||||
GroupMetaObject(): connections() {}
|
GroupMetaObject() : connections()
|
||||||
GroupMetaObject(const GroupObject_Config &base): GroupMetaObject()
|
{
|
||||||
|
}
|
||||||
|
GroupMetaObject(const GroupObject_Config &base) : GroupMetaObject()
|
||||||
{
|
{
|
||||||
this->isSubscription = false;
|
this->isSubscription = false;
|
||||||
this->displayName = base.displayName;
|
this->displayName = base.displayName;
|
||||||
@ -102,7 +110,7 @@ namespace Qv2ray::core
|
|||||||
this->connections = StringsToIdList<ConnectionId>(base.connections);
|
this->connections = StringsToIdList<ConnectionId>(base.connections);
|
||||||
}
|
}
|
||||||
// Suger for down casting.
|
// 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->address = base.address;
|
||||||
this->lastUpdated = base.lastUpdated;
|
this->lastUpdated = base.lastUpdated;
|
||||||
@ -110,6 +118,6 @@ namespace Qv2ray::core
|
|||||||
this->isSubscription = true;
|
this->isSubscription = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::core
|
||||||
|
|
||||||
using namespace Qv2ray::core;
|
using namespace Qv2ray::core;
|
||||||
|
@ -24,26 +24,33 @@ namespace Qv2ray::core
|
|||||||
*port = 0;
|
*port = 0;
|
||||||
*protocol = out["protocol"].toString(QObject::tr("N/A")).toLower();
|
*protocol = out["protocol"].toString(QObject::tr("N/A")).toLower();
|
||||||
|
|
||||||
if (*protocol == "vmess") {
|
if (*protocol == "vmess")
|
||||||
auto Server = StructFromJsonString<VMessServerObject>(JsonToString(out["settings"].toObject()["vnext"].toArray().first().toObject()));
|
{
|
||||||
|
auto Server =
|
||||||
|
StructFromJsonString<VMessServerObject>(JsonToString(out["settings"].toObject()["vnext"].toArray().first().toObject()));
|
||||||
*host = Server.address;
|
*host = Server.address;
|
||||||
*port = Server.port;
|
*port = Server.port;
|
||||||
return true;
|
return true;
|
||||||
} else if (*protocol == "shadowsocks") {
|
}
|
||||||
|
else if (*protocol == "shadowsocks")
|
||||||
|
{
|
||||||
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
||||||
auto Server = StructFromJsonString<ShadowSocksServerObject>(x);
|
auto Server = StructFromJsonString<ShadowSocksServerObject>(x);
|
||||||
*host = Server.address;
|
*host = Server.address;
|
||||||
*port = Server.port;
|
*port = Server.port;
|
||||||
return true;
|
return true;
|
||||||
} else if (*protocol == "socks") {
|
}
|
||||||
|
else if (*protocol == "socks")
|
||||||
|
{
|
||||||
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
||||||
auto Server = StructFromJsonString<SocksServerObject>(x);
|
auto Server = StructFromJsonString<SocksServerObject>(x);
|
||||||
*host = Server.address;
|
*host = Server.address;
|
||||||
*port = Server.port;
|
*port = Server.port;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::core
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <base/models/QvSafeType.hpp>
|
|
||||||
#include <base/models/CoreObjectModels.hpp>
|
#include <base/models/CoreObjectModels.hpp>
|
||||||
|
#include <base/models/QvSafeType.hpp>
|
||||||
|
|
||||||
namespace Qv2ray::core
|
namespace Qv2ray::core
|
||||||
{
|
{
|
||||||
@ -26,6 +26,6 @@ namespace Qv2ray::core
|
|||||||
|
|
||||||
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol);
|
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol);
|
||||||
bool IsComplexConfig(const CONFIGROOT &root);
|
bool IsComplexConfig(const CONFIGROOT &root);
|
||||||
}
|
} // namespace Qv2ray::core
|
||||||
|
|
||||||
using namespace Qv2ray::core;
|
using namespace Qv2ray::core;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "ConfigBackend.hpp"
|
#include "ConfigBackend.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::config
|
namespace Qv2ray::core::config
|
||||||
@ -14,10 +15,8 @@ namespace Qv2ray::core::config
|
|||||||
{
|
{
|
||||||
Qv2rayConfigPath = path;
|
Qv2rayConfigPath = path;
|
||||||
|
|
||||||
if (!path.endsWith("/")) {
|
if (!path.endsWith("/")) { Qv2rayConfigPath += "/"; }
|
||||||
Qv2rayConfigPath += "/";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::core::config
|
||||||
|
|
||||||
using namespace Qv2ray::core::config;
|
using namespace Qv2ray::core::config;
|
||||||
|
@ -4,7 +4,7 @@ namespace Qv2ray::core::config
|
|||||||
{
|
{
|
||||||
void SaveGlobalConfig(const Qv2rayConfig &conf);
|
void SaveGlobalConfig(const Qv2rayConfig &conf);
|
||||||
void SetConfigDirPath(const QString &path);
|
void SetConfigDirPath(const QString &path);
|
||||||
}
|
} // namespace Qv2ray::core::config
|
||||||
|
|
||||||
using namespace Qv2ray::core;
|
using namespace Qv2ray::core;
|
||||||
using namespace Qv2ray::core::config;
|
using namespace Qv2ray::core::config;
|
||||||
|
@ -13,11 +13,14 @@ namespace Qv2ray
|
|||||||
// Private member
|
// Private member
|
||||||
QJsonObject UpgradeConfig_Inc(int fromVersion, QJsonObject root)
|
QJsonObject UpgradeConfig_Inc(int fromVersion, QJsonObject root)
|
||||||
{
|
{
|
||||||
switch (fromVersion) {
|
switch (fromVersion)
|
||||||
|
{
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Below is for Qv2ray version 2
|
// Below is for Qv2ray version 2
|
||||||
case 4: {
|
case 4:
|
||||||
// We changed the "proxyCN" to "bypassCN" as it's easier to understand....
|
{
|
||||||
|
// We changed the "proxyCN" to "bypassCN" as it's easier to
|
||||||
|
// understand....
|
||||||
auto v2_oldProxyCN = root["proxyCN"].toBool();
|
auto v2_oldProxyCN = root["proxyCN"].toBool();
|
||||||
//
|
//
|
||||||
// From 3 to 4, we changed 'runAsRoot' to 'tProxySupport'
|
// From 3 to 4, we changed 'runAsRoot' to 'tProxySupport'
|
||||||
@ -38,7 +41,7 @@ namespace Qv2ray
|
|||||||
root.remove("inBoundSettings");
|
root.remove("inBoundSettings");
|
||||||
UPGRADELOG("Renamed inBoundSettings to inboundConfig.")
|
UPGRADELOG("Renamed inBoundSettings to inboundConfig.")
|
||||||
//
|
//
|
||||||
//connectionConfig
|
// connectionConfig
|
||||||
QJsonObject o;
|
QJsonObject o;
|
||||||
o["dnsList"] = root["dnsList"];
|
o["dnsList"] = root["dnsList"];
|
||||||
o["withLocalDNS"] = root["withLocalDNS"];
|
o["withLocalDNS"] = root["withLocalDNS"];
|
||||||
@ -66,13 +69,15 @@ namespace Qv2ray
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Qv2ray version 2, RC 2
|
// Qv2ray version 2, RC 2
|
||||||
case 5: {
|
case 5:
|
||||||
|
{
|
||||||
// Added subscription auto update
|
// Added subscription auto update
|
||||||
auto subs = root["subscribes"].toObject();
|
auto subs = root["subscribes"].toObject();
|
||||||
root.remove("subscribes");
|
root.remove("subscribes");
|
||||||
QJsonObject newSubscriptions;
|
QJsonObject newSubscriptions;
|
||||||
|
|
||||||
for (auto item = subs.begin(); item != subs.end(); item++) {
|
for (auto item = subs.begin(); item != subs.end(); item++)
|
||||||
|
{
|
||||||
auto key = item.key();
|
auto key = item.key();
|
||||||
SubscriptionObject_Config _conf;
|
SubscriptionObject_Config _conf;
|
||||||
_conf.address = item.value().toString();
|
_conf.address = item.value().toString();
|
||||||
@ -88,7 +93,8 @@ namespace Qv2ray
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Qv2ray version 2, RC 4
|
// Qv2ray version 2, RC 4
|
||||||
case 6: {
|
case 6:
|
||||||
|
{
|
||||||
// Moved API Stats port from connectionConfig to apiConfig
|
// Moved API Stats port from connectionConfig to apiConfig
|
||||||
QJsonObject apiConfig;
|
QJsonObject apiConfig;
|
||||||
apiConfig["enableAPI"] = true;
|
apiConfig["enableAPI"] = true;
|
||||||
@ -97,7 +103,8 @@ namespace Qv2ray
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 7: {
|
case 7:
|
||||||
|
{
|
||||||
auto lang = root["uiConfig"].toObject()["language"].toString().replace("-", "_");
|
auto lang = root["uiConfig"].toObject()["language"].toString().replace("-", "_");
|
||||||
auto uiConfig = root["uiConfig"].toObject();
|
auto uiConfig = root["uiConfig"].toObject();
|
||||||
uiConfig["language"] = lang;
|
uiConfig["language"] = lang;
|
||||||
@ -106,23 +113,24 @@ namespace Qv2ray
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From version 8 to 9, we introduced a lot of new connection metainfo(s)
|
// From version 8 to 9, we introduced a lot of new connection
|
||||||
case 8: {
|
// metainfo(s)
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
// Generate a default group
|
// Generate a default group
|
||||||
QJsonObject defaultGroup;
|
QJsonObject defaultGroup;
|
||||||
QStringList defaultGroupConnectionId;
|
QStringList defaultGroupConnectionId;
|
||||||
defaultGroup["displayName"] = QObject::tr("Default Group");
|
defaultGroup["displayName"] = QObject::tr("Default Group");
|
||||||
QString defaultGroupId = "000000000000";
|
QString defaultGroupId = "000000000000";
|
||||||
|
|
||||||
if (!QDir(QV2RAY_CONNECTIONS_DIR + defaultGroupId).exists()) {
|
if (!QDir(QV2RAY_CONNECTIONS_DIR + defaultGroupId).exists()) { QDir().mkpath(QV2RAY_CONNECTIONS_DIR + defaultGroupId); }
|
||||||
QDir().mkpath(QV2RAY_CONNECTIONS_DIR + defaultGroupId);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString autoStartId;
|
QString autoStartId;
|
||||||
UPGRADELOG("Upgrading connections...")
|
UPGRADELOG("Upgrading connections...")
|
||||||
QJsonObject rootConnections;
|
QJsonObject rootConnections;
|
||||||
|
|
||||||
for (auto config : root["configs"].toArray()) {
|
for (auto config : root["configs"].toArray())
|
||||||
|
{
|
||||||
UPGRADELOG("Migrating: " + config.toString())
|
UPGRADELOG("Migrating: " + config.toString())
|
||||||
//
|
//
|
||||||
// MOVE FILES.
|
// MOVE FILES.
|
||||||
@ -133,17 +141,19 @@ namespace Qv2ray
|
|||||||
DEBUG(MODULE_SETTINGS, "Generated new UUID: " + newUuid);
|
DEBUG(MODULE_SETTINGS, "Generated new UUID: " + newUuid);
|
||||||
|
|
||||||
// Check Autostart Id
|
// Check Autostart Id
|
||||||
if (root["autoStartConfig"].toObject()["subscriptionName"].toString().isEmpty()) {
|
if (root["autoStartConfig"].toObject()["subscriptionName"].toString().isEmpty())
|
||||||
if (root["autoStartConfig"].toObject()["connectionName"].toString() == config.toString()) {
|
{
|
||||||
autoStartId = newUuid;
|
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;
|
auto newPath = QV2RAY_CONNECTIONS_DIR + defaultGroupId + "/" + newUuid + QV2RAY_CONFIG_FILE_EXTENSION;
|
||||||
configFile.rename(newPath);
|
configFile.rename(newPath);
|
||||||
UPGRADELOG("Moved: " + filePath + " to " + newPath);
|
UPGRADELOG("Moved: " + filePath + " to " + newPath);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
UPGRADELOG("WARNING! This file is not found, possible loss of data!")
|
UPGRADELOG("WARNING! This file is not found, possible loss of data!")
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -159,7 +169,8 @@ namespace Qv2ray
|
|||||||
QJsonObject rootSubscriptions = root.take("subscriptions").toObject();
|
QJsonObject rootSubscriptions = root.take("subscriptions").toObject();
|
||||||
QJsonObject newSubscriptions;
|
QJsonObject newSubscriptions;
|
||||||
|
|
||||||
for (auto i = 0; i < rootSubscriptions.count(); i++) {
|
for (auto i = 0; i < rootSubscriptions.count(); i++)
|
||||||
|
{
|
||||||
auto key = rootSubscriptions.keys()[i];
|
auto key = rootSubscriptions.keys()[i];
|
||||||
auto value = rootSubscriptions.value(key);
|
auto value = rootSubscriptions.value(key);
|
||||||
//
|
//
|
||||||
@ -176,15 +187,14 @@ namespace Qv2ray
|
|||||||
auto newDirPath = QV2RAY_SUBSCRIPTION_DIR + subsUuid;
|
auto newDirPath = QV2RAY_SUBSCRIPTION_DIR + subsUuid;
|
||||||
QDir newDir(newDirPath);
|
QDir newDir(newDirPath);
|
||||||
|
|
||||||
if (!newDir.exists()) {
|
if (!newDir.exists()) { newDir.mkpath(newDirPath); }
|
||||||
newDir.mkpath(newDirPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// With extensions
|
// With extensions
|
||||||
auto fileList = GetFileList(baseDirPath);
|
auto fileList = GetFileList(baseDirPath);
|
||||||
|
|
||||||
// Copy every file within a subscription.
|
// Copy every file within a subscription.
|
||||||
for (auto fileName : fileList) {
|
for (auto fileName : fileList)
|
||||||
|
{
|
||||||
auto subsConnectionId = GenerateUuid();
|
auto subsConnectionId = GenerateUuid();
|
||||||
auto baseFilePath = baseDirPath + "/" + fileName;
|
auto baseFilePath = baseDirPath + "/" + fileName;
|
||||||
auto newFilePath = newDirPath + "/" + subsConnectionId + QV2RAY_CONFIG_FILE_EXTENSION;
|
auto newFilePath = newDirPath + "/" + subsConnectionId + QV2RAY_CONFIG_FILE_EXTENSION;
|
||||||
@ -199,10 +209,10 @@ namespace Qv2ray
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Check Autostart Id
|
// Check Autostart Id
|
||||||
if (root["autoStartConfig"].toObject()["subscriptionName"].toString() == key) {
|
if (root["autoStartConfig"].toObject()["subscriptionName"].toString() == key)
|
||||||
if (root["autoStartConfig"].toObject()["connectionName"].toString() == subsConnection["displayName"].toString()) {
|
{
|
||||||
autoStartId = subsConnectionId;
|
if (root["autoStartConfig"].toObject()["connectionName"].toString() == subsConnection["displayName"].toString())
|
||||||
}
|
{ autoStartId = subsConnectionId; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,12 +232,15 @@ namespace Qv2ray
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
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
|
// 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"),
|
QvMessageBoxWarn(nullptr, QObject::tr("Configuration Upgrade Failed"),
|
||||||
QObject::tr("Unsupported config version number: ") + QSTRN(fromVersion) + NEWLINE + NEWLINE +
|
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"
|
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.");
|
" 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))
|
LOG(MODULE_SETTINGS, "Migrating config from version " + QSTRN(fromVersion) + " to " + QSTRN(toVersion))
|
||||||
|
|
||||||
for (int i = fromVersion; i < toVersion; i++) {
|
for (int i = fromVersion; i < toVersion; i++) { root = UpgradeConfig_Inc(i, root); }
|
||||||
root = UpgradeConfig_Inc(i, root);
|
|
||||||
}
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "ConnectionIO.hpp"
|
#include "ConnectionIO.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::connection
|
namespace Qv2ray::core::connection
|
||||||
@ -8,16 +9,19 @@ namespace Qv2ray::core::connection
|
|||||||
////
|
////
|
||||||
//// Save Connection to a place, with checking if there's existing file.
|
//// Save Connection to a place, with checking if there's existing file.
|
||||||
//// If so, append "_N" to the name.
|
//// 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 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 there's already a file AND we CANNOT override existing file.
|
||||||
// if (QFile::exists(fullPath) && !canOverrideExisting) {
|
// if (QFile::exists(fullPath) && !canOverrideExisting) {
|
||||||
// // Alias is a pointer to a QString.
|
// // Alias is a pointer to a QString.
|
||||||
// DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias, QV2RAY_CONFIG_FILE_EXTENSION);
|
// DeducePossibleFileName(QV2RAY_CONFIG_DIR, alias,
|
||||||
// fullPath = QV2RAY_CONFIG_DIR + *alias + QV2RAY_CONFIG_FILE_EXTENSION;
|
// QV2RAY_CONFIG_FILE_EXTENSION); fullPath = QV2RAY_CONFIG_DIR +
|
||||||
|
// *alias + QV2RAY_CONFIG_FILE_EXTENSION;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// LOG(MODULE_SETTINGS, "Saving a config named: " + *alias)
|
// LOG(MODULE_SETTINGS, "Saving a config named: " + *alias)
|
||||||
@ -25,7 +29,8 @@ namespace Qv2ray::core::connection
|
|||||||
// return StringToFile(&str, &config);
|
// 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 str = JsonToString(obj);
|
||||||
// auto fName = *name;
|
// auto fName = *name;
|
||||||
@ -34,27 +39,31 @@ namespace Qv2ray::core::connection
|
|||||||
// fName = RemoveInvalidFileName(fName);
|
// 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 there's already a file. THIS IS EXTREMELY RARE
|
||||||
// if (config.exists()) {
|
// 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)
|
// LOG(MODULE_SETTINGS, "Saving a subscription named: " + fName)
|
||||||
// bool result = StringToFile(&str, &config);
|
// bool result = StringToFile(&str, &config);
|
||||||
//
|
//
|
||||||
// if (!result) {
|
// 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;
|
// *name = fName;
|
||||||
// return result;
|
// 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()) {
|
// if (!config.exists()) {
|
||||||
// LOG(MODULE_FILEIO, "Trying to remove a non-existing file?")
|
// 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()) {
|
// if (!config.exists()) {
|
||||||
// LOG(MODULE_FILEIO, "Trying to remove a non-existing file?")
|
// 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)
|
// LOG(MODULE_CONNECTION, "[RENAME] --> ORIGINAL: " + originalName +
|
||||||
// return QFile::rename(QV2RAY_CONFIG_DIR + originalName + QV2RAY_CONFIG_FILE_EXTENSION, QV2RAY_CONFIG_DIR + newName + QV2RAY_CONFIG_FILE_EXTENSION);
|
// ", 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)
|
// LOG(MODULE_SUBSCRIPTION, "[RENAME] --> ORIGINAL: " + originalName
|
||||||
// return QDir().rename(QV2RAY_SUBSCRIPTION_DIR + originalName, QV2RAY_SUBSCRIPTION_DIR + newName);
|
// + ", 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);
|
// QFile source(sourceFilePath);
|
||||||
//
|
//
|
||||||
// if (!source.exists()) {
|
// if (!source.exists()) {
|
||||||
// LOG(MODULE_FILEIO, "Trying to import from an non-existing file.")
|
// LOG(MODULE_FILEIO, "Trying to import from an non-existing
|
||||||
// return CONFIGROOT();
|
// file.") return CONFIGROOT();
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
|
// auto root = CONFIGROOT(JsonFromString(StringFromFile(&source)));
|
||||||
@ -111,4 +129,4 @@ namespace Qv2ray::core::connection
|
|||||||
// return root;
|
// return root;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::core::connection
|
||||||
|
@ -7,8 +7,8 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
// File Protocol
|
// File Protocol
|
||||||
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex);
|
CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex);
|
||||||
}
|
} // namespace ConnectionIO
|
||||||
}
|
} // namespace Qv2ray::core::connection
|
||||||
|
|
||||||
using namespace Qv2ray::core::connection;
|
using namespace Qv2ray::core::connection;
|
||||||
using namespace Qv2ray::core::connection::ConnectionIO;
|
using namespace Qv2ray::core::connection::ConnectionIO;
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#include "Generation.hpp"
|
#include "Generation.hpp"
|
||||||
#include "core/CoreUtils.hpp"
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
#include "core/CoreUtils.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::connection
|
namespace Qv2ray::core::connection
|
||||||
{
|
{
|
||||||
namespace Generation
|
namespace Generation
|
||||||
{
|
{
|
||||||
// -------------------------- BEGIN CONFIG GENERATIONS ----------------------------------------------------------------------------
|
// -------------------------- BEGIN CONFIG GENERATIONS
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
ROUTING GenerateRoutes(bool enableProxy, bool proxyCN)
|
ROUTING GenerateRoutes(bool enableProxy, bool proxyCN)
|
||||||
{
|
{
|
||||||
ROUTING root;
|
ROUTING root;
|
||||||
@ -15,8 +17,10 @@ namespace Qv2ray::core::connection
|
|||||||
// For Rules list
|
// For Rules list
|
||||||
ROUTERULELIST rulesList;
|
ROUTERULELIST rulesList;
|
||||||
|
|
||||||
if (!enableProxy) {
|
if (!enableProxy)
|
||||||
// This is added to disable all proxies, as a alternative influence of #64
|
{
|
||||||
|
// This is added to disable all proxies, as a alternative
|
||||||
|
// influence of #64
|
||||||
rulesList.append(GenerateSingleRouteRule(QStringList() << "regexp:.*", true, OUTBOUND_TAG_DIRECT));
|
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));
|
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.
|
// 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);
|
root.insert("rules", rulesList);
|
||||||
RROOT
|
RROOT
|
||||||
}
|
}
|
||||||
@ -56,20 +61,24 @@ namespace Qv2ray::core::connection
|
|||||||
RROOT
|
RROOT
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers)
|
OUTBOUNDSETTING
|
||||||
|
GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers)
|
||||||
{
|
{
|
||||||
OUTBOUNDSETTING root;
|
OUTBOUNDSETTING root;
|
||||||
QJsonArray x;
|
QJsonArray x;
|
||||||
|
|
||||||
foreach (auto server, servers) {
|
foreach (auto server, servers)
|
||||||
x.append(GenerateShadowSocksServerOUT(server.email, server.address, server.port, server.method, server.password, server.ota, server.level));
|
{
|
||||||
|
x.append(GenerateShadowSocksServerOUT(server.email, server.address, server.port, server.method, server.password, server.ota,
|
||||||
|
server.level));
|
||||||
}
|
}
|
||||||
|
|
||||||
root.insert("servers", x);
|
root.insert("servers", x);
|
||||||
RROOT
|
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;
|
OUTBOUNDSETTING root;
|
||||||
JADD(email, address, port, method, password, level, ota)
|
JADD(email, address, port, method, password, level, ota)
|
||||||
@ -81,7 +90,8 @@ namespace Qv2ray::core::connection
|
|||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
QJsonArray servers(QJsonArray::fromStringList(dnsServers));
|
QJsonArray servers(QJsonArray::fromStringList(dnsServers));
|
||||||
|
|
||||||
if (withLocalhost) {
|
if (withLocalhost)
|
||||||
|
{
|
||||||
// https://github.com/lhy0403/Qv2ray/issues/64
|
// https://github.com/lhy0403/Qv2ray/issues/64
|
||||||
// The fix patch didn't touch this line below.
|
// The fix patch didn't touch this line below.
|
||||||
//
|
//
|
||||||
@ -93,7 +103,7 @@ namespace Qv2ray::core::connection
|
|||||||
RROOT
|
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;
|
INBOUNDSETTING root;
|
||||||
JADD(address, port, network, timeout, followRedirect, userLevel)
|
JADD(address, port, network, timeout, followRedirect, userLevel)
|
||||||
@ -105,17 +115,14 @@ namespace Qv2ray::core::connection
|
|||||||
INBOUNDSETTING root;
|
INBOUNDSETTING root;
|
||||||
QJsonArray accounts;
|
QJsonArray accounts;
|
||||||
|
|
||||||
foreach (auto account, _accounts) {
|
foreach (auto account, _accounts)
|
||||||
if (account.user.isEmpty() && account.pass.isEmpty()) {
|
{
|
||||||
continue;
|
if (account.user.isEmpty() && account.pass.isEmpty()) { continue; }
|
||||||
}
|
|
||||||
|
|
||||||
accounts.append(GetRootObject(account));
|
accounts.append(GetRootObject(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accounts.isEmpty()) {
|
if (!accounts.isEmpty()) { JADD(accounts) }
|
||||||
JADD(accounts)
|
|
||||||
}
|
|
||||||
|
|
||||||
JADD(timeout, allowTransparent, userLevel)
|
JADD(timeout, allowTransparent, userLevel)
|
||||||
RROOT
|
RROOT
|
||||||
@ -130,7 +137,8 @@ namespace Qv2ray::core::connection
|
|||||||
oneServer["address"] = address;
|
oneServer["address"] = address;
|
||||||
oneServer["port"] = port;
|
oneServer["port"] = port;
|
||||||
|
|
||||||
if (useAuth) {
|
if (useAuth)
|
||||||
|
{
|
||||||
QJsonArray users;
|
QJsonArray users;
|
||||||
QJsonObject oneUser;
|
QJsonObject oneUser;
|
||||||
oneUser["user"] = username;
|
oneUser["user"] = username;
|
||||||
@ -150,35 +158,34 @@ namespace Qv2ray::core::connection
|
|||||||
INBOUNDSETTING root;
|
INBOUNDSETTING root;
|
||||||
QJsonArray accounts;
|
QJsonArray accounts;
|
||||||
|
|
||||||
foreach (auto acc, _accounts) {
|
foreach (auto acc, _accounts)
|
||||||
if (acc.user.isEmpty() && acc.pass.isEmpty()) {
|
{
|
||||||
continue;
|
if (acc.user.isEmpty() && acc.pass.isEmpty()) { continue; }
|
||||||
}
|
|
||||||
|
|
||||||
accounts.append(GetRootObject(acc));
|
accounts.append(GetRootObject(acc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accounts.isEmpty()) {
|
if (!accounts.isEmpty()) { JADD(accounts) }
|
||||||
JADD(accounts)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (udp) {
|
if (udp) { JADD(auth, udp, ip, userLevel) }
|
||||||
JADD(auth, udp, ip, userLevel)
|
else
|
||||||
} else {
|
{
|
||||||
JADD(auth, userLevel)
|
JADD(auth, userLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
RROOT
|
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;
|
OUTBOUND root;
|
||||||
JADD(sendThrough, protocol, settings, tag, streamSettings, mux)
|
JADD(sendThrough, protocol, settings, tag, streamSettings, mux)
|
||||||
RROOT
|
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;
|
INBOUND root;
|
||||||
LOG(MODULE_CONNECTION, "allocation is not used here.")
|
LOG(MODULE_CONNECTION, "allocation is not used here.")
|
||||||
@ -192,20 +199,18 @@ namespace Qv2ray::core::connection
|
|||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
QJsonArray services;
|
QJsonArray services;
|
||||||
|
|
||||||
if (withHandler)
|
if (withHandler) services << "HandlerService";
|
||||||
services << "HandlerService";
|
|
||||||
|
|
||||||
if (withLogger)
|
if (withLogger) services << "LoggerService";
|
||||||
services << "LoggerService";
|
|
||||||
|
|
||||||
if (withStats)
|
if (withStats) services << "StatsService";
|
||||||
services << "StatsService";
|
|
||||||
|
|
||||||
JADD(services, tag)
|
JADD(services, tag)
|
||||||
RROOT
|
RROOT
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------- END CONFIG GENERATIONS ------------------------------------------------------------------------------
|
// -------------------------- END CONFIG GENERATIONS
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
// BEGIN RUNTIME CONFIG GENERATION
|
// BEGIN RUNTIME CONFIG GENERATION
|
||||||
|
|
||||||
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root)
|
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root)
|
||||||
@ -213,8 +218,10 @@ namespace Qv2ray::core::connection
|
|||||||
bool isComplex = IsComplexConfig(root);
|
bool isComplex = IsComplexConfig(root);
|
||||||
QJsonObject logObject;
|
QJsonObject logObject;
|
||||||
//
|
//
|
||||||
//logObject.insert("access", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ACCESS_LOG_FILENAME);
|
// logObject.insert("access", QV2RAY_CONFIG_PATH +
|
||||||
//logObject.insert("error", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME);
|
// 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]);
|
logObject.insert("loglevel", vLogLevels[GlobalConfig.logLevel]);
|
||||||
root.insert("log", logObject);
|
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 inbounds list is empty we append our global configured
|
||||||
if (!root.contains("inbounds") || root["inbounds"].toArray().empty()) {
|
// inbounds to the config.
|
||||||
|
if (!root.contains("inbounds") || root["inbounds"].toArray().empty())
|
||||||
|
{
|
||||||
INBOUNDS inboundsList;
|
INBOUNDS inboundsList;
|
||||||
|
|
||||||
// HTTP Inbound
|
// HTTP Inbound
|
||||||
if (GlobalConfig.inboundConfig.useHTTP) {
|
if (GlobalConfig.inboundConfig.useHTTP)
|
||||||
|
{
|
||||||
INBOUND httpInBoundObject;
|
INBOUND httpInBoundObject;
|
||||||
httpInBoundObject.insert("listen", GlobalConfig.inboundConfig.listenip);
|
httpInBoundObject.insert("listen", GlobalConfig.inboundConfig.listenip);
|
||||||
httpInBoundObject.insert("port", GlobalConfig.inboundConfig.http_port);
|
httpInBoundObject.insert("port", GlobalConfig.inboundConfig.http_port);
|
||||||
httpInBoundObject.insert("protocol", "http");
|
httpInBoundObject.insert("protocol", "http");
|
||||||
httpInBoundObject.insert("tag", "http_IN");
|
httpInBoundObject.insert("tag", "http_IN");
|
||||||
|
|
||||||
if (GlobalConfig.inboundConfig.http_useAuth) {
|
if (GlobalConfig.inboundConfig.http_useAuth)
|
||||||
auto httpInSettings = GenerateHTTPIN(QList<AccountObject>() << GlobalConfig.inboundConfig.httpAccount);
|
{
|
||||||
|
auto httpInSettings = GenerateHTTPIN(QList<AccountObject>() << GlobalConfig.inboundConfig.httpAccount);
|
||||||
httpInBoundObject.insert("settings", httpInSettings);
|
httpInBoundObject.insert("settings", httpInSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +257,8 @@ namespace Qv2ray::core::connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SOCKS Inbound
|
// SOCKS Inbound
|
||||||
if (GlobalConfig.inboundConfig.useSocks) {
|
if (GlobalConfig.inboundConfig.useSocks)
|
||||||
|
{
|
||||||
INBOUND socksInBoundObject;
|
INBOUND socksInBoundObject;
|
||||||
socksInBoundObject.insert("listen", GlobalConfig.inboundConfig.listenip);
|
socksInBoundObject.insert("listen", GlobalConfig.inboundConfig.listenip);
|
||||||
socksInBoundObject.insert("port", GlobalConfig.inboundConfig.socks_port);
|
socksInBoundObject.insert("port", GlobalConfig.inboundConfig.socks_port);
|
||||||
@ -254,8 +266,7 @@ namespace Qv2ray::core::connection
|
|||||||
socksInBoundObject.insert("tag", "socks_IN");
|
socksInBoundObject.insert("tag", "socks_IN");
|
||||||
auto socksInSettings = GenerateSocksIN(GlobalConfig.inboundConfig.socks_useAuth ? "password" : "noauth",
|
auto socksInSettings = GenerateSocksIN(GlobalConfig.inboundConfig.socks_useAuth ? "password" : "noauth",
|
||||||
QList<AccountObject>() << GlobalConfig.inboundConfig.socksAccount,
|
QList<AccountObject>() << GlobalConfig.inboundConfig.socksAccount,
|
||||||
GlobalConfig.inboundConfig.socksUDP,
|
GlobalConfig.inboundConfig.socksUDP, GlobalConfig.inboundConfig.socksLocalIP);
|
||||||
GlobalConfig.inboundConfig.socksLocalIP);
|
|
||||||
socksInBoundObject.insert("settings", socksInSettings);
|
socksInBoundObject.insert("settings", socksInSettings);
|
||||||
inboundsList.append(socksInBoundObject);
|
inboundsList.append(socksInBoundObject);
|
||||||
}
|
}
|
||||||
@ -264,14 +275,16 @@ namespace Qv2ray::core::connection
|
|||||||
DEBUG(MODULE_CONNECTION, "Added global config inbounds to the config")
|
DEBUG(MODULE_CONNECTION, "Added global config inbounds to the config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process every inbounds to make sure a tag is configured, fixed API 0 speed
|
// Process every inbounds to make sure a tag is configured, fixed
|
||||||
// issue when no tag is configured.
|
// API 0 speed issue when no tag is configured.
|
||||||
INBOUNDS newTaggedInbounds = INBOUNDS(root["inbounds"].toArray());
|
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();
|
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.")
|
LOG(MODULE_SETTINGS, "Adding a tag to an inbound.")
|
||||||
_inboundItem["tag"] = GenerateRandomString(8);
|
_inboundItem["tag"] = GenerateRandomString(8);
|
||||||
newTaggedInbounds[i] = _inboundItem;
|
newTaggedInbounds[i] = _inboundItem;
|
||||||
@ -281,52 +294,66 @@ namespace Qv2ray::core::connection
|
|||||||
root["inbounds"] = newTaggedInbounds;
|
root["inbounds"] = newTaggedInbounds;
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Note: The part below always makes the whole functionality in trouble......
|
// Note: The part below always makes the whole functionality in
|
||||||
// BE EXTREME CAREFUL when changing these code below...
|
// trouble...... BE EXTREME CAREFUL when changing these code
|
||||||
// See: https://github.com/lhy0403/Qv2ray/issues/129
|
// below... See: https://github.com/lhy0403/Qv2ray/issues/129
|
||||||
// routeCountLabel in Mainwindow makes here failed to ENOUGH-ly check the routing tables
|
// 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.
|
// For some config files that has routing entries already.
|
||||||
// We DO NOT add extra routings.
|
// We DO NOT add extra routings.
|
||||||
//
|
//
|
||||||
// HOWEVER, we need to verify the QV2RAY_RULE_ENABLED entry.
|
// 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());
|
ROUTING routing = ROUTING(root["routing"].toObject());
|
||||||
ROUTERULELIST rules;
|
ROUTERULELIST rules;
|
||||||
LOG(MODULE_CONNECTION, "Processing an existing routing table.")
|
LOG(MODULE_CONNECTION, "Processing an existing routing table.")
|
||||||
|
|
||||||
for (auto _rule : routing["rules"].toArray()) {
|
for (auto _rule : routing["rules"].toArray())
|
||||||
|
{
|
||||||
auto _b = _rule.toObject();
|
auto _b = _rule.toObject();
|
||||||
|
|
||||||
if (_b.contains("QV2RAY_RULE_USE_BALANCER")) {
|
if (_b.contains("QV2RAY_RULE_USE_BALANCER"))
|
||||||
if (_b["QV2RAY_RULE_USE_BALANCER"].toBool()) {
|
{
|
||||||
|
if (_b["QV2RAY_RULE_USE_BALANCER"].toBool())
|
||||||
|
{
|
||||||
// We use balancer
|
// We use balancer
|
||||||
_b.remove("outboundTag");
|
_b.remove("outboundTag");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// We only use the normal outbound
|
// We only use the normal outbound
|
||||||
_b.remove("balancerTag");
|
_b.remove("balancerTag");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_SETTINGS, "We found a rule without QV2RAY_RULE_USE_BALANCER, so don't process it.")
|
LOG(MODULE_SETTINGS, "We found a rule without QV2RAY_RULE_USE_BALANCER, so don't process it.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this entry has been disabled.
|
// If this entry has been disabled.
|
||||||
if (_b.contains("QV2RAY_RULE_ENABLED") && _b["QV2RAY_RULE_ENABLED"].toBool() == true) {
|
if (_b.contains("QV2RAY_RULE_ENABLED") && _b["QV2RAY_RULE_ENABLED"].toBool() == true) { rules.append(_b); }
|
||||||
rules.append(_b);
|
else
|
||||||
} else {
|
{
|
||||||
LOG(MODULE_SETTINGS, "Discarded a rule as it's been set DISABLED")
|
LOG(MODULE_SETTINGS, "Discarded a rule as it's been set DISABLED")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routing["rules"] = rules;
|
routing["rules"] = rules;
|
||||||
root["routing"] = routing;
|
root["routing"] = routing;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//
|
//
|
||||||
LOG(MODULE_CONNECTION, "Inserting default values to simple config")
|
LOG(MODULE_CONNECTION, "Inserting default values to simple config")
|
||||||
|
|
||||||
if (root["outbounds"].toArray().count() != 1) {
|
if (root["outbounds"].toArray().count() != 1)
|
||||||
// There are no ROUTING but 2 or more outbounds.... This is rare, but possible.
|
{
|
||||||
|
// 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: 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.")
|
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
|
// Process forward proxy
|
||||||
#define fpConf GlobalConfig.connectionConfig.forwardProxyConfig
|
#define fpConf GlobalConfig.connectionConfig.forwardProxyConfig
|
||||||
|
|
||||||
if (fpConf.enableForwardProxy) {
|
if (fpConf.enableForwardProxy)
|
||||||
|
{
|
||||||
auto outboundArray = root["outbounds"].toArray();
|
auto outboundArray = root["outbounds"].toArray();
|
||||||
auto firstOutbound = outboundArray.first().toObject();
|
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.")
|
LOG(MODULE_CONNECTION, "Applying forward proxy to current connection.")
|
||||||
auto proxy = PROXYSETTING();
|
auto proxy = PROXYSETTING();
|
||||||
proxy["tag"] = OUTBOUND_TAG_FORWARD_PROXY;
|
proxy["tag"] = OUTBOUND_TAG_FORWARD_PROXY;
|
||||||
@ -349,13 +378,20 @@ namespace Qv2ray::core::connection
|
|||||||
// FP Outbound.
|
// FP Outbound.
|
||||||
OUTBOUNDSETTING fpOutbound;
|
OUTBOUNDSETTING fpOutbound;
|
||||||
|
|
||||||
if (fpConf.type.toLower() == "http" || fpConf.type.toLower() == "socks") {
|
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));
|
fpOutbound =
|
||||||
} else {
|
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)
|
LOG(MODULE_CONNECTION, "WARNING: Unsupported outbound type: " + fpConf.type)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Remove proxySettings from firstOutbound
|
// Remove proxySettings from firstOutbound
|
||||||
firstOutbound.remove("proxySettings");
|
firstOutbound.remove("proxySettings");
|
||||||
}
|
}
|
||||||
@ -366,7 +402,8 @@ namespace Qv2ray::core::connection
|
|||||||
|
|
||||||
#undef fpConf
|
#undef fpConf
|
||||||
OUTBOUNDS outbounds = OUTBOUNDS(root["outbounds"].toArray());
|
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;
|
root["outbounds"] = outbounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +444,8 @@ namespace Qv2ray::core::connection
|
|||||||
INBOUNDS inbounds = INBOUNDS(root["inbounds"].toArray());
|
INBOUNDS inbounds = INBOUNDS(root["inbounds"].toArray());
|
||||||
INBOUNDSETTING fakeDocodemoDoor;
|
INBOUNDSETTING fakeDocodemoDoor;
|
||||||
fakeDocodemoDoor["address"] = "127.0.0.1";
|
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);
|
inbounds.push_front(apiInboundsRoot);
|
||||||
root["inbounds"] = inbounds;
|
root["inbounds"] = inbounds;
|
||||||
//
|
//
|
||||||
@ -417,5 +455,5 @@ namespace Qv2ray::core::connection
|
|||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Generation
|
||||||
}
|
} // namespace Qv2ray::core::connection
|
||||||
|
@ -5,7 +5,7 @@ namespace Qv2ray::core::connection
|
|||||||
namespace Generation
|
namespace Generation
|
||||||
{
|
{
|
||||||
// Important config generation algorithms.
|
// 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);
|
ROUTING GenerateRoutes(bool enableProxy, bool cnProxy);
|
||||||
ROUTERULE GenerateSingleRouteRule(QStringList list, bool isDomain, QString outboundTag, QString type = "field");
|
ROUTERULE GenerateSingleRouteRule(QStringList list, bool isDomain, QString outboundTag, QString type = "field");
|
||||||
QJsonObject GenerateDNS(bool withLocalhost, QStringList dnsServers);
|
QJsonObject GenerateDNS(bool withLocalhost, QStringList dnsServers);
|
||||||
@ -15,20 +15,24 @@ namespace Qv2ray::core::connection
|
|||||||
OUTBOUNDSETTING GenerateFreedomOUT(QString domainStrategy, QString redirect, int userLevel);
|
OUTBOUNDSETTING GenerateFreedomOUT(QString domainStrategy, QString redirect, int userLevel);
|
||||||
OUTBOUNDSETTING GenerateBlackHoleOUT(bool useHTTP);
|
OUTBOUNDSETTING GenerateBlackHoleOUT(bool useHTTP);
|
||||||
OUTBOUNDSETTING GenerateShadowSocksOUT(QList<ShadowSocksServerObject> servers);
|
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);
|
OUTBOUNDSETTING GenerateHTTPSOCKSOut(QString address, int port, bool useAuth, QString username, QString password);
|
||||||
//
|
//
|
||||||
// Inbounds Protocols
|
// 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 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
|
// Generate FINAL Configs
|
||||||
CONFIGROOT GenerateRuntimeConfig(CONFIGROOT root);
|
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);
|
OUTBOUND GenerateOutboundEntry(QString protocol, OUTBOUNDSETTING settings, QJsonObject streamSettings, QJsonObject mux = QJsonObject(),
|
||||||
INBOUND GenerateInboundEntry(QString listen, int port, QString protocol, INBOUNDSETTING settings, QString tag, QJsonObject sniffing = QJsonObject(), QJsonObject allocate = 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;
|
||||||
using namespace Qv2ray::core::connection;
|
using namespace Qv2ray::core::connection;
|
||||||
|
@ -33,57 +33,68 @@ namespace Qv2ray::core::handlers
|
|||||||
* - log list
|
* - log list
|
||||||
* in case of error, no objects will be returned.
|
* in case of error, no objects will be returned.
|
||||||
*/
|
*/
|
||||||
std::pair <std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList>
|
std::pair<std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList> decodeSSD(
|
||||||
decodeSSD(const QString &uri, const QString &pattern = DEFAULT_NAME_PATTERN);
|
const QString &uri, const QString &pattern = DEFAULT_NAME_PATTERN);
|
||||||
}
|
} // namespace ssd
|
||||||
}
|
} // namespace Qv2ray::core::handlers
|
||||||
|
|
||||||
#define MUST_EXIST(fieldName) \
|
#define MUST_EXIST(fieldName) \
|
||||||
if (obj[(fieldName)].isUndefined()) {\
|
if (obj[(fieldName)].isUndefined()) \
|
||||||
logList << QObject::tr("invalid ssd link: json: field %1 must exist").arg(fieldName);\
|
{ \
|
||||||
return std::make_pair(std::nullopt, logList);\
|
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);\
|
#define MUST_PORT(fieldName) \
|
||||||
if (int value = obj[(fieldName)].toInt(-1); value < 0 || value > 65535) { \
|
MUST_EXIST(fieldName); \
|
||||||
logList << QObject::tr("invalid ssd link: json: field %1 must be valid port number");\
|
if (int value = obj[(fieldName)].toInt(-1); value < 0 || value > 65535) \
|
||||||
return std::make_pair(std::nullopt, logList);\
|
{ \
|
||||||
|
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);\
|
#define MUST_STRING(fieldName) \
|
||||||
if (!obj[(fieldName)].isString()) {\
|
MUST_EXIST(fieldName); \
|
||||||
logList << QObject::tr("invalid ssd link: json: field %1 must be of type 'string'").arg(fieldName);\
|
if (!obj[(fieldName)].isString()) \
|
||||||
return std::make_pair(std::nullopt, logList);\
|
{ \
|
||||||
|
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);\
|
#define MUST_ARRAY(fieldName) \
|
||||||
if (!obj[(fieldName)].isArray()) {\
|
MUST_EXIST(fieldName); \
|
||||||
logList << QObject::tr("invalid ssd link: json: field %1 must be an array").arg(fieldName);\
|
if (!obj[(fieldName)].isArray()) \
|
||||||
return std::make_pair(std::nullopt, logList);\
|
{ \
|
||||||
|
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) \
|
#define SERVER_SHOULD_BE_OBJECT(server) \
|
||||||
if (!server.isObject()) {\
|
if (!server.isObject()) \
|
||||||
logList << QObject::tr("skipping invalid ssd server: server must be an object");\
|
{ \
|
||||||
continue;\
|
logList << QObject::tr("skipping invalid ssd server: server must be an object"); \
|
||||||
|
continue; \
|
||||||
}
|
}
|
||||||
#define SHOULD_EXIST(fieldName) \
|
#define SHOULD_EXIST(fieldName) \
|
||||||
if (serverObject[(fieldName)].isUndefined()) { \
|
if (serverObject[(fieldName)].isUndefined()) \
|
||||||
logList << QObject::tr("skipping invalid ssd server: missing required field %1").arg(fieldName);\
|
{ \
|
||||||
continue;\
|
logList << QObject::tr("skipping invalid ssd server: missing required field %1").arg(fieldName); \
|
||||||
|
continue; \
|
||||||
}
|
}
|
||||||
#define SHOULD_STRING(fieldName) SHOULD_EXIST(fieldName); \
|
#define SHOULD_STRING(fieldName) \
|
||||||
if (!serverObject[(fieldName)].isString()) { \
|
SHOULD_EXIST(fieldName); \
|
||||||
logList << QObject::tr("skipping invalid ssd server: field %1 should be of type 'string'").arg(fieldName);\
|
if (!serverObject[(fieldName)].isString()) \
|
||||||
continue; \
|
{ \
|
||||||
|
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::
|
||||||
std::pair <std::optional<std::pair<QString, QList<std::pair<QString, ShadowSocksServerObject>>>>, QStringList>
|
decodeSSD(const QString &uri, const QString &pattern)
|
||||||
Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &pattern)
|
|
||||||
{
|
{
|
||||||
// The list for the parsing log.
|
// The list for the parsing log.
|
||||||
QStringList logList;
|
QStringList logList;
|
||||||
|
|
||||||
// ssd links should begin with "ssd://"
|
// ssd links should begin with "ssd://"
|
||||||
if (!uri.startsWith("ssd://")) {
|
if (!uri.startsWith("ssd://"))
|
||||||
|
{
|
||||||
logList << QObject::tr("invalid ssd link: should begin with ssd://");
|
logList << QObject::tr("invalid ssd link: should begin with ssd://");
|
||||||
return std::make_pair(std::nullopt, logList);
|
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 ssdURIBody = QStringRef(&uri, 5, uri.length() - 6);
|
||||||
const auto decodedJSON = QByteArray::fromBase64(ssdURIBody.toUtf8());
|
const auto decodedJSON = QByteArray::fromBase64(ssdURIBody.toUtf8());
|
||||||
|
|
||||||
if (decodedJSON.length() == 0) {
|
if (decodedJSON.length() == 0)
|
||||||
|
{
|
||||||
logList << QObject::tr("invalid ssd link: base64 parse failed");
|
logList << QObject::tr("invalid ssd link: base64 parse failed");
|
||||||
return std::make_pair(std::nullopt, logList);
|
return std::make_pair(std::nullopt, logList);
|
||||||
}
|
}
|
||||||
@ -101,13 +113,15 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
|
|||||||
QJsonParseError err;
|
QJsonParseError err;
|
||||||
QJsonDocument document = QJsonDocument::fromJson(decodedJSON, &err);
|
QJsonDocument document = QJsonDocument::fromJson(decodedJSON, &err);
|
||||||
|
|
||||||
if (document.isNull()) {
|
if (document.isNull())
|
||||||
|
{
|
||||||
logList << QObject::tr("invalid ssd link: json parse failed: ") % err.errorString();
|
logList << QObject::tr("invalid ssd link: json parse failed: ") % err.errorString();
|
||||||
return std::make_pair(std::nullopt, logList);
|
return std::make_pair(std::nullopt, logList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// json should be an object
|
// json should be an object
|
||||||
if (!document.isObject()) {
|
if (!document.isObject())
|
||||||
|
{
|
||||||
logList << QObject::tr("invalid ssd link: found non-object json, aborting");
|
logList << QObject::tr("invalid ssd link: found non-object json, aborting");
|
||||||
return std::make_pair(std::nullopt, logList);
|
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
|
// check: rc4-md5 is not supported by v2ray-core
|
||||||
// TODO: more checks, including all algorithms
|
// 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");
|
logList << QObject::tr("invalid ssd link: rc4-md5 encryption is not supported by v2ray-core");
|
||||||
return std::make_pair(std::nullopt, logList);
|
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
|
// iterate through the servers
|
||||||
for (QJsonValueRef server : obj["servers"].toArray()) {
|
for (QJsonValueRef server : obj["servers"].toArray())
|
||||||
|
{
|
||||||
SERVER_SHOULD_BE_OBJECT(server);
|
SERVER_SHOULD_BE_OBJECT(server);
|
||||||
QJsonObject serverObject = server.toObject();
|
QJsonObject serverObject = server.toObject();
|
||||||
ShadowSocksServerObject ssObject;
|
ShadowSocksServerObject ssObject;
|
||||||
@ -158,11 +174,13 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
|
|||||||
// port selection:
|
// port selection:
|
||||||
// normal: use global settings
|
// normal: use global settings
|
||||||
// overriding: use current config
|
// overriding: use current config
|
||||||
if (serverObject["port"].isUndefined()) {
|
if (serverObject["port"].isUndefined()) { ssObject.port = port; }
|
||||||
ssObject.port = port;
|
else if (auto currPort = serverObject["port"].toInt(-1); port >= 0 && port <= 65535)
|
||||||
} else if (auto currPort = serverObject["port"].toInt(-1); port >= 0 && port <= 65535) {
|
{
|
||||||
ssObject.port = currPort;
|
ssObject.port = currPort;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
logList << QObject::tr("warning: invalid port encountered. using fallback value.");
|
logList << QObject::tr("warning: invalid port encountered. using fallback value.");
|
||||||
ssObject.port = port;
|
ssObject.port = port;
|
||||||
}
|
}
|
||||||
@ -172,11 +190,13 @@ Qv2ray::core::handlers::ssd::decodeSSD(const QString &uri, const QString &patter
|
|||||||
// entitled: using given name
|
// entitled: using given name
|
||||||
QString nodeName;
|
QString nodeName;
|
||||||
|
|
||||||
if (serverObject["remarks"].isUndefined()) {
|
if (serverObject["remarks"].isUndefined()) { nodeName = QString("%1:%2").arg(ssObject.address).arg(ssObject.port); }
|
||||||
nodeName = QString("%1:%2").arg(ssObject.address).arg(ssObject.port);
|
else if (serverObject["remarks"].isString())
|
||||||
} else if (serverObject["remarks"].isString()) {
|
{
|
||||||
nodeName = serverObject["remarks"].toString();
|
nodeName = serverObject["remarks"].toString();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
logList << QObject::tr("warning: invalid name encountered. using fallback value.");
|
logList << QObject::tr("warning: invalid name encountered. using fallback value.");
|
||||||
nodeName = QString("%1:%2").arg(ssObject.address).arg(ssObject.port);
|
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
|
// specified: use given value
|
||||||
double ratio = 1.0;
|
double ratio = 1.0;
|
||||||
|
|
||||||
if (auto currRatio = serverObject["ratio"].toDouble(-1.0); currRatio != -1.0) {
|
if (auto currRatio = serverObject["ratio"].toDouble(-1.0); currRatio != -1.0) { ratio = currRatio; }
|
||||||
ratio = currRatio;
|
else if (!serverObject["ratio"].isUndefined())
|
||||||
} else if (!serverObject["ratio"].isUndefined()) {
|
{
|
||||||
logList << QObject::tr("warning: invalid ratio encountered. using fallback value.");
|
logList << QObject::tr("warning: invalid ratio encountered. using fallback value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Serialization.hpp"
|
#include "Serialization.hpp"
|
||||||
|
|
||||||
#include "Generation.hpp"
|
#include "Generation.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#include "core/CoreUtils.hpp"
|
#include "core/CoreUtils.hpp"
|
||||||
@ -12,11 +13,13 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
CONFIGROOT config;
|
CONFIGROOT config;
|
||||||
|
|
||||||
if (link.startsWith("vmess://")) {
|
if (link.startsWith("vmess://")) { config = ConvertConfigFromVMessString(link, alias, errMessage); }
|
||||||
config = ConvertConfigFromVMessString(link, alias, errMessage);
|
else if (link.startsWith("ss://"))
|
||||||
} else if (link.startsWith("ss://")) {
|
{
|
||||||
config = ConvertConfigFromSSString(link, alias, errMessage);
|
config = ConvertConfigFromSSString(link, alias, errMessage);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*errMessage = QObject::tr("Unsupported share link format.");
|
*errMessage = QObject::tr("Unsupported share link format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,21 +34,29 @@ namespace Qv2ray::core::connection
|
|||||||
auto type = outbound["protocol"].toString();
|
auto type = outbound["protocol"].toString();
|
||||||
QString sharelink = "";
|
QString sharelink = "";
|
||||||
|
|
||||||
if (type == "vmess") {
|
if (type == "vmess")
|
||||||
auto vmessServer = StructFromJsonString<VMessServerObject>(JsonToString(outbound["settings"].toObject()["vnext"].toArray().first().toObject()));
|
{
|
||||||
|
auto vmessServer =
|
||||||
|
StructFromJsonString<VMessServerObject>(JsonToString(outbound["settings"].toObject()["vnext"].toArray().first().toObject()));
|
||||||
auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outbound["streamSettings"].toObject()));
|
auto transport = StructFromJsonString<StreamSettingsObject>(JsonToString(outbound["streamSettings"].toObject()));
|
||||||
sharelink = ConvertConfigToVMessString(transport, vmessServer, alias);
|
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);
|
sharelink = ConvertConfigToSSString(ssServer, alias, isSip002);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_CONNECTION, "Unsupported outbound type: " + type)
|
LOG(MODULE_CONNECTION, "Unsupported outbound type: " + type)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sharelink;
|
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)
|
QString ConvertConfigToVMessString(const StreamSettingsObject &transfer, const VMessServerObject &serverConfig, const QString &alias)
|
||||||
{
|
{
|
||||||
QJsonObject vmessUriRoot;
|
QJsonObject vmessUriRoot;
|
||||||
@ -59,15 +70,19 @@ namespace Qv2ray::core::connection
|
|||||||
vmessUriRoot["net"] = transfer.network;
|
vmessUriRoot["net"] = transfer.network;
|
||||||
vmessUriRoot["tls"] = transfer.security;
|
vmessUriRoot["tls"] = transfer.security;
|
||||||
|
|
||||||
if (transfer.network == "tcp") {
|
if (transfer.network == "tcp") { vmessUriRoot["type"] = transfer.tcpSettings.header.type; }
|
||||||
vmessUriRoot["type"] = transfer.tcpSettings.header.type;
|
else if (transfer.network == "kcp")
|
||||||
} else if (transfer.network == "kcp") {
|
{
|
||||||
vmessUriRoot["type"] = transfer.kcpSettings.header.type;
|
vmessUriRoot["type"] = transfer.kcpSettings.header.type;
|
||||||
} else if (transfer.network == "quic") {
|
}
|
||||||
|
else if (transfer.network == "quic")
|
||||||
|
{
|
||||||
vmessUriRoot["type"] = transfer.quicSettings.header.type;
|
vmessUriRoot["type"] = transfer.quicSettings.header.type;
|
||||||
vmessUriRoot["host"] = transfer.quicSettings.security;
|
vmessUriRoot["host"] = transfer.quicSettings.security;
|
||||||
vmessUriRoot["path"] = transfer.quicSettings.key;
|
vmessUriRoot["path"] = transfer.quicSettings.key;
|
||||||
} else if (transfer.network == "ws") {
|
}
|
||||||
|
else if (transfer.network == "ws")
|
||||||
|
{
|
||||||
auto x = transfer.wsSettings.headers;
|
auto x = transfer.wsSettings.headers;
|
||||||
auto host = x.contains("host");
|
auto host = x.contains("host");
|
||||||
auto CapHost = x.contains("Host");
|
auto CapHost = x.contains("Host");
|
||||||
@ -75,7 +90,9 @@ namespace Qv2ray::core::connection
|
|||||||
//
|
//
|
||||||
vmessUriRoot["host"] = realHost;
|
vmessUriRoot["host"] = realHost;
|
||||||
vmessUriRoot["path"] = transfer.wsSettings.path;
|
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["host"] = transfer.httpSettings.host.join(",");
|
||||||
vmessUriRoot["path"] = transfer.httpSettings.path;
|
vmessUriRoot["path"] = transfer.httpSettings.path;
|
||||||
}
|
}
|
||||||
@ -89,8 +106,8 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
// String may start with: vmess:// and ss://
|
// String may start with: vmess:// and ss://
|
||||||
// We only process vmess:// here
|
// We only process vmess:// here
|
||||||
// Some subscription providers may use plain vmess:// saperated by lines
|
// Some subscription providers may use plain vmess:// saperated by
|
||||||
// But others may use base64 of above.
|
// lines But others may use base64 of above.
|
||||||
auto result = QString::fromUtf8(arr).trimmed();
|
auto result = QString::fromUtf8(arr).trimmed();
|
||||||
return result.startsWith("vmess://") ? result : Base64Decode(result);
|
return result.startsWith("vmess://") ? result : Base64Decode(result);
|
||||||
}
|
}
|
||||||
@ -100,8 +117,9 @@ namespace Qv2ray::core::connection
|
|||||||
ShadowSocksServerObject server;
|
ShadowSocksServerObject server;
|
||||||
QString d_name;
|
QString d_name;
|
||||||
|
|
||||||
//auto ssUri = _ssUri.toStdString();
|
// auto ssUri = _ssUri.toStdString();
|
||||||
if (ssUri.length() < 5) {
|
if (ssUri.length() < 5)
|
||||||
|
{
|
||||||
LOG(MODULE_CONNECTION, "ss:// string too short")
|
LOG(MODULE_CONNECTION, "ss:// string too short")
|
||||||
*errMessage = QObject::tr("SS URI is too short");
|
*errMessage = QObject::tr("SS URI is too short");
|
||||||
}
|
}
|
||||||
@ -110,53 +128,51 @@ namespace Qv2ray::core::connection
|
|||||||
auto hashPos = uri.lastIndexOf("#");
|
auto hashPos = uri.lastIndexOf("#");
|
||||||
DEBUG(MODULE_CONNECTION, "Hash sign position: " + QSTRN(hashPos))
|
DEBUG(MODULE_CONNECTION, "Hash sign position: " + QSTRN(hashPos))
|
||||||
|
|
||||||
if (hashPos >= 0) {
|
if (hashPos >= 0)
|
||||||
|
{
|
||||||
// Get the name/remark
|
// Get the name/remark
|
||||||
d_name = uri.mid(uri.lastIndexOf("#") + 1);
|
d_name = uri.mid(uri.lastIndexOf("#") + 1);
|
||||||
uri.truncate(hashPos);
|
uri.truncate(hashPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No plugins for Qv2ray so disable those lnes.i
|
// 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
|
// // TODO: support plugins. For now, just ignore them
|
||||||
// uri.erase(pluginPos);
|
// uri.erase(pluginPos);
|
||||||
//}
|
//}
|
||||||
auto atPos = uri.indexOf('@');
|
auto atPos = uri.indexOf('@');
|
||||||
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
|
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
|
||||||
|
|
||||||
if (atPos < 0) {
|
if (atPos < 0)
|
||||||
|
{
|
||||||
// Old URI scheme
|
// Old URI scheme
|
||||||
QString decoded = QByteArray::fromBase64(uri.toUtf8(), QByteArray::Base64Option::OmitTrailingEquals);
|
QString decoded = QByteArray::fromBase64(uri.toUtf8(), QByteArray::Base64Option::OmitTrailingEquals);
|
||||||
auto colonPos = decoded.indexOf(':');
|
auto colonPos = decoded.indexOf(':');
|
||||||
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
|
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
|
||||||
|
|
||||||
if (colonPos < 0) {
|
if (colonPos < 0) { *errMessage = QObject::tr("Can't find the colon separator between method and password"); }
|
||||||
*errMessage = QObject::tr("Can't find the colon separator between method and password");
|
|
||||||
}
|
|
||||||
|
|
||||||
server.method = decoded.left(colonPos);
|
server.method = decoded.left(colonPos);
|
||||||
decoded.remove(0, colonPos + 1);
|
decoded.remove(0, colonPos + 1);
|
||||||
atPos = decoded.lastIndexOf('@');
|
atPos = decoded.lastIndexOf('@');
|
||||||
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
|
DEBUG(MODULE_CONNECTION, "At sign position: " + QSTRN(atPos))
|
||||||
|
|
||||||
if (atPos < 0) {
|
if (atPos < 0) { *errMessage = QObject::tr("Can't find the at separator between password and hostname"); }
|
||||||
*errMessage = QObject::tr("Can't find the at separator between password and hostname");
|
|
||||||
}
|
|
||||||
|
|
||||||
server.password = decoded.mid(0, atPos);
|
server.password = decoded.mid(0, atPos);
|
||||||
decoded.remove(0, atPos + 1);
|
decoded.remove(0, atPos + 1);
|
||||||
colonPos = decoded.lastIndexOf(':');
|
colonPos = decoded.lastIndexOf(':');
|
||||||
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
|
DEBUG(MODULE_CONNECTION, "Colon position: " + QSTRN(colonPos))
|
||||||
|
|
||||||
if (colonPos < 0) {
|
if (colonPos < 0) { *errMessage = QObject::tr("Can't find the colon separator between hostname and port"); }
|
||||||
*errMessage = QObject::tr("Can't find the colon separator between hostname and port");
|
|
||||||
}
|
|
||||||
|
|
||||||
server.address = decoded.mid(0, colonPos);
|
server.address = decoded.mid(0, colonPos);
|
||||||
server.port = decoded.mid(colonPos + 1).toInt();
|
server.port = decoded.mid(colonPos + 1).toInt();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// SIP002 URI scheme
|
// SIP002 URI scheme
|
||||||
auto x = QUrl::fromUserInput(uri);
|
auto x = QUrl::fromUserInput(uri);
|
||||||
server.address = x.host();
|
server.address = x.host();
|
||||||
@ -166,9 +182,7 @@ namespace Qv2ray::core::connection
|
|||||||
//
|
//
|
||||||
DEBUG(MODULE_CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
|
DEBUG(MODULE_CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
|
||||||
|
|
||||||
if (userInfoSp < 0) {
|
if (userInfoSp < 0) { *errMessage = QObject::tr("Can't find the colon separator between method and password"); }
|
||||||
*errMessage = QObject::tr("Can't find the colon separator between method and password");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString method = userInfo.mid(0, userInfoSp);
|
QString method = userInfo.mid(0, userInfoSp);
|
||||||
server.method = method;
|
server.method = method;
|
||||||
@ -178,7 +192,8 @@ namespace Qv2ray::core::connection
|
|||||||
d_name = QUrl::fromPercentEncoding(d_name.toUtf8());
|
d_name = QUrl::fromPercentEncoding(d_name.toUtf8());
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
OUTBOUNDS outbounds;
|
OUTBOUNDS outbounds;
|
||||||
outbounds.append(GenerateOutboundEntry("shadowsocks", GenerateShadowSocksOUT(QList<ShadowSocksServerObject>() << server), QJsonObject()));
|
outbounds.append(
|
||||||
|
GenerateOutboundEntry("shadowsocks", GenerateShadowSocksOUT(QList<ShadowSocksServerObject>() << server), QJsonObject()));
|
||||||
JADD(outbounds)
|
JADD(outbounds)
|
||||||
*alias = alias->isEmpty() ? d_name : *alias + "_" + d_name;
|
*alias = alias->isEmpty() ? d_name : *alias + "_" + d_name;
|
||||||
LOG(MODULE_CONNECTION, "Deduced alias: " + *alias)
|
LOG(MODULE_CONNECTION, "Deduced alias: " + *alias)
|
||||||
@ -189,12 +204,15 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
auto myAlias = QUrl::toPercentEncoding(alias);
|
auto myAlias = QUrl::toPercentEncoding(alias);
|
||||||
|
|
||||||
if (isSip002) {
|
if (isSip002)
|
||||||
|
{
|
||||||
LOG(MODULE_CONNECTION, "Converting an ss-server config to Sip002 ss:// format")
|
LOG(MODULE_CONNECTION, "Converting an ss-server config to Sip002 ss:// format")
|
||||||
QString plainUserInfo = server.method + ":" + server.password;
|
QString plainUserInfo = server.method + ":" + server.password;
|
||||||
QString userinfo(plainUserInfo.toUtf8().toBase64(QByteArray::Base64Option::Base64UrlEncoding).data());
|
QString userinfo(plainUserInfo.toUtf8().toBase64(QByteArray::Base64Option::Base64UrlEncoding).data());
|
||||||
return "ss://" + userinfo + "@" + server.address + ":" + QSTRN(server.port) + "#" + myAlias;
|
return "ss://" + userinfo + "@" + server.address + ":" + QSTRN(server.port) + "#" + myAlias;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_CONNECTION, "Converting an ss-server config to old ss:// string format")
|
LOG(MODULE_CONNECTION, "Converting an ss-server config to old ss:// string format")
|
||||||
QString ssUri = server.method + ":" + server.password + "@" + server.address + ":" + QSTRN(server.port);
|
QString ssUri = server.method + ":" + server.password + "@" + server.address + ":" + QSTRN(server.port);
|
||||||
return "ss://" + ssUri.toUtf8().toBase64(QByteArray::Base64Option::OmitTrailingEquals) + "#" + myAlias;
|
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.")
|
LOG(MODULE_SETTINGS, "Trying to convert from a vmess string.")
|
||||||
QString vmess = vmessStr;
|
QString vmess = vmessStr;
|
||||||
|
|
||||||
if (vmess.trimmed() != vmess) {
|
if (vmess.trimmed() != vmess)
|
||||||
|
{
|
||||||
LOG(MODULE_SETTINGS, "VMess string has some prefix/postfix spaces, trimming.")
|
LOG(MODULE_SETTINGS, "VMess string has some prefix/postfix spaces, trimming.")
|
||||||
vmess = vmessStr.trimmed();
|
vmess = vmessStr.trimmed();
|
||||||
}
|
}
|
||||||
@ -217,16 +236,19 @@ namespace Qv2ray::core::connection
|
|||||||
// Reset errMessage
|
// Reset errMessage
|
||||||
*errMessage = "";
|
*errMessage = "";
|
||||||
|
|
||||||
if (!vmess.toLower().startsWith("vmess://")) {
|
if (!vmess.toLower().startsWith("vmess://"))
|
||||||
|
{
|
||||||
*errMessage = QObject::tr("VMess string should start with 'vmess://'");
|
*errMessage = QObject::tr("VMess string should start with 'vmess://'");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8);
|
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8);
|
||||||
auto b64Str = vmessJsonB64.toString();
|
auto b64Str = vmessJsonB64.toString();
|
||||||
|
|
||||||
if (b64Str.isEmpty()) {
|
if (b64Str.isEmpty())
|
||||||
|
{
|
||||||
*errMessage = QObject::tr("VMess string should be a valid base64 string");
|
*errMessage = QObject::tr("VMess string should be a valid base64 string");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
@ -234,14 +256,16 @@ namespace Qv2ray::core::connection
|
|||||||
auto vmessString = Base64Decode(b64Str);
|
auto vmessString = Base64Decode(b64Str);
|
||||||
auto jsonErr = VerifyJsonString(vmessString);
|
auto jsonErr = VerifyJsonString(vmessString);
|
||||||
|
|
||||||
if (!jsonErr.isEmpty()) {
|
if (!jsonErr.isEmpty())
|
||||||
|
{
|
||||||
*errMessage = jsonErr;
|
*errMessage = jsonErr;
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vmessConf = JsonFromString(vmessString);
|
auto vmessConf = JsonFromString(vmessString);
|
||||||
|
|
||||||
if (vmessConf.isEmpty()) {
|
if (vmessConf.isEmpty())
|
||||||
|
{
|
||||||
*errMessage = QObject::tr("JSON should not be empty");
|
*errMessage = QObject::tr("JSON should not be empty");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
@ -249,21 +273,23 @@ namespace Qv2ray::core::connection
|
|||||||
bool flag = true;
|
bool flag = true;
|
||||||
// C is a quick hack...
|
// C is a quick hack...
|
||||||
#define C(k) vmessConf.contains(k)
|
#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");
|
flag = flag && C("id") && C("aid") && C("port") && C("add");
|
||||||
// Stream Settings
|
// Stream Settings
|
||||||
auto net = C("net") ? vmessConf["net"].toString() : "tcp";
|
auto net = C("net") ? vmessConf["net"].toString() : "tcp";
|
||||||
|
|
||||||
if (net == "http" || net == "ws")
|
if (net == "http" || net == "ws") flag = flag && C("host") && C("path");
|
||||||
flag = flag && C("host") && C("path");
|
|
||||||
else if (net == "domainsocket")
|
else if (net == "domainsocket")
|
||||||
flag = flag && C("path");
|
flag = flag && C("path");
|
||||||
else if (net == "quic")
|
else if (net == "quic")
|
||||||
flag = flag && C("host") && C("type") && C("path");
|
flag = flag && C("host") && C("type") && C("path");
|
||||||
|
|
||||||
#undef C
|
#undef C
|
||||||
//return flag ? 0 : 1;
|
// return flag ? 0 : 1;
|
||||||
} catch (exception *e) {
|
}
|
||||||
|
catch (exception *e)
|
||||||
|
{
|
||||||
*errMessage = e->what();
|
*errMessage = e->what();
|
||||||
LOG(MODULE_IMPORT, "Failed to decode vmess string: " + *errMessage)
|
LOG(MODULE_IMPORT, "Failed to decode vmess string: " + *errMessage)
|
||||||
delete e;
|
delete e;
|
||||||
@ -279,44 +305,62 @@ namespace Qv2ray::core::connection
|
|||||||
int port, aid;
|
int port, aid;
|
||||||
//
|
//
|
||||||
// key = key in JSON and the variable name.
|
// key = key in JSON and the variable name.
|
||||||
// values = Candidate variable list, if not match, the first one is used as default.
|
// values = Candidate variable list, if not match, the first one is
|
||||||
// [[val.size() <= 1]] is used when only the default value exists.
|
// used as default.
|
||||||
// - It can be empty, if so, if the key is not in the JSON, or the value is empty, it'll report an error.
|
// [[val.size() <= 1]] is used when only the default value
|
||||||
// - Else if it contains one thing. if the key is not in the JSON, or the value is empty, it'll use that one.
|
// exists.
|
||||||
// - 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
|
// - 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.
|
// - Else, it'll use the value found from the JSON object.
|
||||||
//
|
//
|
||||||
#define empty_arg
|
#define empty_arg
|
||||||
#define __vmess_checker__func(key, values) \
|
#define __vmess_checker__func(key, values) \
|
||||||
{\
|
{ \
|
||||||
auto val = QStringList() values;\
|
auto val = QStringList() values; \
|
||||||
if (vmessConf.contains(#key) && !vmessConf[#key].toVariant().toString().trimmed().isEmpty() \
|
if (vmessConf.contains(#key) && !vmessConf[#key].toVariant().toString().trimmed().isEmpty() && \
|
||||||
&& (val.size() <= 1 || val.contains(vmessConf[#key].toVariant().toString()))) {\
|
(val.size() <= 1 || val.contains(vmessConf[#key].toVariant().toString()))) \
|
||||||
key = vmessConf[#key].toVariant().toString();\
|
{ \
|
||||||
DEBUG(MODULE_IMPORT, "Found key \"" #key "\" within the vmess object.")\
|
key = vmessConf[#key].toVariant().toString(); \
|
||||||
} else if (!val.isEmpty()) {\
|
DEBUG(MODULE_IMPORT, "Found key \"" #key "\" within the vmess object.") \
|
||||||
key = val.first(); \
|
} \
|
||||||
DEBUG(MODULE_IMPORT, "Using key \"" #key "\" from the first candidate list: " + key)\
|
else if (!val.isEmpty()) \
|
||||||
} else{\
|
{ \
|
||||||
*errMessage = QObject::tr(#key " does not exist."); \
|
key = val.first(); \
|
||||||
LOG(MODULE_IMPORT, "Cannot process \"" #key "\" since it's not included in the json object." ) \
|
DEBUG(MODULE_IMPORT, "Using key \"" #key "\" from the first candidate list: " + key) \
|
||||||
LOG(MODULE_IMPORT, " --> values: " + val.join(";")) \
|
} \
|
||||||
LOG(MODULE_IMPORT, " --> PS: " + ps) \
|
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.
|
// Get Alias (AKA ps) from address and port.
|
||||||
__vmess_checker__func(ps, << vmessConf["add"].toVariant().toString() + ":" + vmessConf["port"].toVariant().toString());
|
__vmess_checker__func(ps, << vmessConf["add"].toVariant().toString() + ":" + vmessConf["port"].toVariant().toString());
|
||||||
__vmess_checker__func(add, empty_arg)
|
__vmess_checker__func(add, empty_arg) __vmess_checker__func(id, empty_arg) __vmess_checker__func(net, << "tcp"
|
||||||
__vmess_checker__func(id, empty_arg)
|
<< "http"
|
||||||
__vmess_checker__func(net, << "tcp" << "http" << "h2" << "ws" << "kcp" << "domainsocket" << "quic")
|
<< "h2"
|
||||||
__vmess_checker__func(type, << "none" << "http" << "srtp" << "utp" << "wechat-video")
|
<< "ws"
|
||||||
__vmess_checker__func(path, << "")
|
<< "kcp"
|
||||||
__vmess_checker__func(host, << "")
|
<< "domainsocket"
|
||||||
__vmess_checker__func(tls, << "")
|
<< "quic")
|
||||||
//
|
__vmess_checker__func(type, << "none"
|
||||||
port = vmessConf["port"].toVariant().toInt();
|
<< "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();
|
aid = vmessConf["aid"].toVariant().toInt();
|
||||||
// Apply the settings.
|
// Apply the settings.
|
||||||
//
|
//
|
||||||
@ -340,23 +384,29 @@ namespace Qv2ray::core::connection
|
|||||||
// Stream Settings
|
// Stream Settings
|
||||||
StreamSettingsObject streaming;
|
StreamSettingsObject streaming;
|
||||||
|
|
||||||
if (net == "tcp") {
|
if (net == "tcp") { streaming.tcpSettings.header.type = type; }
|
||||||
streaming.tcpSettings.header.type = type;
|
else if (net == "http" || net == "h2")
|
||||||
} else if (net == "http" || net == "h2") {
|
{
|
||||||
// Fill hosts for HTTP
|
// Fill hosts for HTTP
|
||||||
for (auto _host : host.split(',')) {
|
for (auto _host : host.split(',')) { streaming.httpSettings.host.push_back(_host.trimmed()); }
|
||||||
streaming.httpSettings.host.push_back(_host.trimmed());
|
|
||||||
}
|
|
||||||
|
|
||||||
streaming.httpSettings.path = path;
|
streaming.httpSettings.path = path;
|
||||||
} else if (net == "ws") {
|
}
|
||||||
|
else if (net == "ws")
|
||||||
|
{
|
||||||
streaming.wsSettings.headers["Host"] = host;
|
streaming.wsSettings.headers["Host"] = host;
|
||||||
streaming.wsSettings.path = path;
|
streaming.wsSettings.path = path;
|
||||||
} else if (net == "kcp") {
|
}
|
||||||
|
else if (net == "kcp")
|
||||||
|
{
|
||||||
streaming.kcpSettings.header.type = type;
|
streaming.kcpSettings.header.type = type;
|
||||||
} else if (net == "domainsocket") {
|
}
|
||||||
|
else if (net == "domainsocket")
|
||||||
|
{
|
||||||
streaming.dsSettings.path = path;
|
streaming.dsSettings.path = path;
|
||||||
} else if (net == "quic") {
|
}
|
||||||
|
else if (net == "quic")
|
||||||
|
{
|
||||||
streaming.quicSettings.security = host;
|
streaming.quicSettings.security = host;
|
||||||
streaming.quicSettings.header.type = type;
|
streaming.quicSettings.header.type = type;
|
||||||
streaming.quicSettings.key = path;
|
streaming.quicSettings.key = path;
|
||||||
@ -364,7 +414,8 @@ namespace Qv2ray::core::connection
|
|||||||
|
|
||||||
// FIXME: makeshift patch for #290.
|
// FIXME: makeshift patch for #290.
|
||||||
// to be rewritten after refactoring.
|
// 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.serverName = host;
|
||||||
streaming.tlsSettings.allowInsecure = false;
|
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);
|
auto outbound = GenerateOutboundEntry("vmess", vConf, GetRootObject(streaming), QJsonObject(), "0.0.0.0", OUTBOUND_TAG_PROXY);
|
||||||
//
|
//
|
||||||
root["outbounds"] = QJsonArray() << outbound;
|
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;
|
*alias = alias->trimmed().isEmpty() ? ps : *alias + "_" + ps;
|
||||||
#undef default
|
#undef default
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Serialization
|
||||||
}
|
} // namespace Qv2ray::core::connection
|
||||||
|
@ -5,7 +5,7 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
namespace Serialization
|
namespace Serialization
|
||||||
{
|
{
|
||||||
//int VerifyVMessProtocolString(QString vmess);
|
// int VerifyVMessProtocolString(QString vmess);
|
||||||
QString DecodeSubscriptionString(QByteArray arr);
|
QString DecodeSubscriptionString(QByteArray arr);
|
||||||
|
|
||||||
// General
|
// General
|
||||||
@ -19,8 +19,8 @@ namespace Qv2ray::core::connection
|
|||||||
// SS URI Protocol
|
// SS URI Protocol
|
||||||
CONFIGROOT ConvertConfigFromSSString(const QString &ss, QString *alias, QString *errMessage);
|
CONFIGROOT ConvertConfigFromSSString(const QString &ss, QString *alias, QString *errMessage);
|
||||||
QString ConvertConfigToSSString(const ShadowSocksServerObject &server, const QString &alias, bool isSip002);
|
QString ConvertConfigToSSString(const ShadowSocksServerObject &server, const QString &alias, bool isSip002);
|
||||||
}
|
} // namespace Serialization
|
||||||
}
|
} // namespace Qv2ray::core::connection
|
||||||
|
|
||||||
using namespace Qv2ray::core;
|
using namespace Qv2ray::core;
|
||||||
using namespace Qv2ray::core::connection;
|
using namespace Qv2ray::core::connection;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "ConnectionHandler.hpp"
|
#include "ConnectionHandler.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#include "core/config/ConfigBackend.hpp"
|
#include "core/config/ConfigBackend.hpp"
|
||||||
|
#include "core/connection/Serialization.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::handlers
|
namespace Qv2ray::core::handlers
|
||||||
{
|
{
|
||||||
@ -10,26 +12,23 @@ namespace Qv2ray::core::handlers
|
|||||||
DEBUG(MODULE_CORE_HANDLER, "ConnectionHandler Constructor.")
|
DEBUG(MODULE_CORE_HANDLER, "ConnectionHandler Constructor.")
|
||||||
|
|
||||||
// Do we need to check how many of them are loaded?
|
// Do we need to check how many of them are loaded?
|
||||||
for (auto i = 0; i < GlobalConfig.connections.count(); i++) {
|
for (auto i = 0; i < GlobalConfig.connections.count(); i++)
|
||||||
connections[ConnectionId(GlobalConfig.connections.keys()[i])] = GlobalConfig.connections.values()[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];
|
auto val = GlobalConfig.subscriptions[key];
|
||||||
groups[GroupId(key)] = val;
|
groups[GroupId(key)] = val;
|
||||||
|
|
||||||
for (auto conn : val.connections) {
|
for (auto conn : val.connections) { connections[ConnectionId(conn)].groupId = GroupId(key); }
|
||||||
connections[ConnectionId(conn)].groupId = GroupId(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto key : GlobalConfig.groups.keys()) {
|
for (auto key : GlobalConfig.groups.keys())
|
||||||
|
{
|
||||||
auto val = GlobalConfig.groups[key];
|
auto val = GlobalConfig.groups[key];
|
||||||
groups[GroupId(key)] = val;
|
groups[GroupId(key)] = val;
|
||||||
|
|
||||||
for (auto conn : val.connections) {
|
for (auto conn : val.connections) { connections[ConnectionId(conn)].groupId = GroupId(key); }
|
||||||
connections[ConnectionId(conn)].groupId = GroupId(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vCoreInstance = new V2rayKernelInstance();
|
vCoreInstance = new V2rayKernelInstance();
|
||||||
@ -47,7 +46,7 @@ namespace Qv2ray::core::handlers
|
|||||||
pingConnectionTimerId = startTimer(60 * 1000);
|
pingConnectionTimerId = startTimer(60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvConnectionHandler::CHSaveConnectionData_p()
|
void QvConnectionHandler::CHSaveConfigData_p()
|
||||||
{
|
{
|
||||||
// Copy
|
// Copy
|
||||||
auto newGlobalConfig = GlobalConfig;
|
auto newGlobalConfig = GlobalConfig;
|
||||||
@ -55,18 +54,21 @@ namespace Qv2ray::core::handlers
|
|||||||
newGlobalConfig.groups.clear();
|
newGlobalConfig.groups.clear();
|
||||||
newGlobalConfig.subscriptions.clear();
|
newGlobalConfig.subscriptions.clear();
|
||||||
|
|
||||||
for (auto i = 0; i < connections.count(); i++) {
|
for (auto i = 0; i < connections.count(); i++)
|
||||||
newGlobalConfig.connections[connections.keys()[i].toString()] = connections.values()[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);
|
QStringList connections = IdListToStrings(groups.values()[i].connections);
|
||||||
|
|
||||||
if (groups.values()[i].isSubscription) {
|
if (groups.values()[i].isSubscription)
|
||||||
|
{
|
||||||
SubscriptionObject_Config o = groups.values()[i];
|
SubscriptionObject_Config o = groups.values()[i];
|
||||||
o.connections = connections;
|
o.connections = connections;
|
||||||
newGlobalConfig.subscriptions[groups.keys()[i].toString()] = o;
|
newGlobalConfig.subscriptions[groups.keys()[i].toString()] = o;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
GroupObject_Config o = groups.values()[i];
|
GroupObject_Config o = groups.values()[i];
|
||||||
o.connections = connections;
|
o.connections = connections;
|
||||||
newGlobalConfig.groups[groups.keys()[i].toString()] = o;
|
newGlobalConfig.groups[groups.keys()[i].toString()] = o;
|
||||||
@ -78,29 +80,25 @@ namespace Qv2ray::core::handlers
|
|||||||
|
|
||||||
void QvConnectionHandler::timerEvent(QTimerEvent *event)
|
void QvConnectionHandler::timerEvent(QTimerEvent *event)
|
||||||
{
|
{
|
||||||
if (event->timerId() == saveTimerId) {
|
if (event->timerId() == saveTimerId) { CHSaveConfigData_p(); }
|
||||||
CHSaveConnectionData_p();
|
else if (event->timerId() == pingAllTimerId)
|
||||||
} else if (event->timerId() == pingAllTimerId) {
|
{
|
||||||
StartLatencyTest();
|
StartLatencyTest();
|
||||||
} else if (event->timerId() == pingConnectionTimerId) {
|
}
|
||||||
if (currentConnectionId != NullConnectionId) {
|
else if (event->timerId() == pingConnectionTimerId)
|
||||||
StartLatencyTest(currentConnectionId);
|
{
|
||||||
}
|
if (currentConnectionId != NullConnectionId) { StartLatencyTest(currentConnectionId); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvConnectionHandler::StartLatencyTest()
|
void QvConnectionHandler::StartLatencyTest()
|
||||||
{
|
{
|
||||||
for (auto connection : connections.keys()) {
|
for (auto connection : connections.keys()) { StartLatencyTest(connection); }
|
||||||
StartLatencyTest(connection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvConnectionHandler::StartLatencyTest(const GroupId &id)
|
void QvConnectionHandler::StartLatencyTest(const GroupId &id)
|
||||||
{
|
{
|
||||||
for (auto connection : groups[id].connections) {
|
for (auto connection : groups[id].connections) { StartLatencyTest(connection); }
|
||||||
StartLatencyTest(connection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvConnectionHandler::StartLatencyTest(const ConnectionId &id)
|
void QvConnectionHandler::StartLatencyTest(const ConnectionId &id)
|
||||||
@ -123,10 +121,9 @@ namespace Qv2ray::core::handlers
|
|||||||
{
|
{
|
||||||
QList<GroupId> subsList;
|
QList<GroupId> subsList;
|
||||||
|
|
||||||
for (auto group : groups.keys()) {
|
for (auto group : groups.keys())
|
||||||
if (groups[group].isSubscription) {
|
{
|
||||||
subsList.push_back(group);
|
if (groups[group].isSubscription) { subsList.push_back(group); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return subsList;
|
return subsList;
|
||||||
@ -149,10 +146,9 @@ namespace Qv2ray::core::handlers
|
|||||||
|
|
||||||
const ConnectionId QvConnectionHandler::GetConnectionIdByDisplayName(const QString &displayName) const
|
const ConnectionId QvConnectionHandler::GetConnectionIdByDisplayName(const QString &displayName) const
|
||||||
{
|
{
|
||||||
for (auto conn : connections.keys()) {
|
for (auto conn : connections.keys())
|
||||||
if (connections[conn].displayName == displayName) {
|
{
|
||||||
return conn;
|
if (connections[conn].displayName == displayName) { return conn; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NullConnectionId;
|
return NullConnectionId;
|
||||||
@ -160,10 +156,9 @@ namespace Qv2ray::core::handlers
|
|||||||
|
|
||||||
const GroupId QvConnectionHandler::GetGroupIdByDisplayName(const QString &displayName) const
|
const GroupId QvConnectionHandler::GetGroupIdByDisplayName(const QString &displayName) const
|
||||||
{
|
{
|
||||||
for (auto group : groups.keys()) {
|
for (auto group : groups.keys())
|
||||||
if (groups[group].displayName == displayName) {
|
{
|
||||||
return group;
|
if (groups[group].displayName == displayName) { return group; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NullGroupId;
|
return NullGroupId;
|
||||||
@ -171,48 +166,57 @@ namespace Qv2ray::core::handlers
|
|||||||
|
|
||||||
const GroupId QvConnectionHandler::GetConnectionGroupId(const ConnectionId &id) const
|
const GroupId QvConnectionHandler::GetConnectionGroupId(const ConnectionId &id) const
|
||||||
{
|
{
|
||||||
if (!connections.contains(id)) {
|
if (!connections.contains(id)) { LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString()); }
|
||||||
LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return connections[id].groupId;
|
return connections[id].groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
double QvConnectionHandler::GetConnectionLatency(const ConnectionId &id) const
|
double QvConnectionHandler::GetConnectionLatency(const ConnectionId &id) const
|
||||||
{
|
{
|
||||||
if (!connections.contains(id)) {
|
if (!connections.contains(id)) { LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString()); }
|
||||||
LOG(MODULE_CORE_HANDLER, "Cannot find id: " + id.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return connections[id].latency;
|
return connections[id].latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
const optional<QString> QvConnectionHandler::DeleteConnection(const ConnectionId &id)
|
const optional<QString> QvConnectionHandler::DeleteConnection(const ConnectionId &id)
|
||||||
{
|
{
|
||||||
// TODO
|
//
|
||||||
Q_UNUSED(id)
|
auto groupId = connections[id].groupId;
|
||||||
return "";
|
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)
|
const optional<QString> QvConnectionHandler::StartConnection(const ConnectionId &identifier)
|
||||||
{
|
{
|
||||||
if (!connections.contains(identifier)) {
|
if (!connections.contains(identifier)) { return tr("No connection selected!") + NEWLINE + tr("Please select a config from the list."); }
|
||||||
return tr("No connection selected!") + NEWLINE + tr("Please select a config from the list.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentConnectionId != NullConnectionId) {
|
if (currentConnectionId != NullConnectionId) { StopConnection(); }
|
||||||
StopConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIGROOT root = GetConnectionRoot(connections[identifier].groupId, identifier);
|
CONFIGROOT root = GetConnectionRoot(connections[identifier].groupId, identifier);
|
||||||
return CHStartConnection_p(identifier, root);
|
return CHStartConnection_p(identifier, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvConnectionHandler::StopConnection() //const ConnectionId &id
|
void QvConnectionHandler::StopConnection() // const ConnectionId &id
|
||||||
{
|
{
|
||||||
// Currently just simply stop it.
|
// Currently just simply stop it.
|
||||||
//_UNUSED(id)
|
//_UNUSED(id)
|
||||||
//if (currentConnectionId == id) {
|
// if (currentConnectionId == id) {
|
||||||
//}
|
//}
|
||||||
CHStopConnection_p();
|
CHStopConnection_p();
|
||||||
}
|
}
|
||||||
@ -226,9 +230,7 @@ namespace Qv2ray::core::handlers
|
|||||||
{
|
{
|
||||||
QString result;
|
QString result;
|
||||||
|
|
||||||
if (!connections.contains(id)) {
|
if (!connections.contains(id)) { result = tr("N/A"); }
|
||||||
result = tr("N/A");
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIGROOT root = GetConnectionRoot(connections[id].groupId, id);
|
CONFIGROOT root = GetConnectionRoot(connections[id].groupId, id);
|
||||||
QStringList protocols;
|
QStringList protocols;
|
||||||
@ -236,12 +238,12 @@ namespace Qv2ray::core::handlers
|
|||||||
auto outbound = root["outbounds"].toArray().first().toObject();
|
auto outbound = root["outbounds"].toArray().first().toObject();
|
||||||
result.append(outbound["protocol"].toString());
|
result.append(outbound["protocol"].toString());
|
||||||
|
|
||||||
if (outbound.contains("streamSettings")) {
|
if (outbound.contains("streamSettings"))
|
||||||
result.append(" + " + outbound["streamSettings"].toObject()["network"].toString());
|
{
|
||||||
|
result.append(" / " + outbound["streamSettings"].toObject()["network"].toString());
|
||||||
|
|
||||||
if (outbound["streamSettings"].toObject().contains("tls")) {
|
if (outbound["streamSettings"].toObject().contains("tls"))
|
||||||
result.append(outbound["streamSettings"].toObject()["tls"].toBool() ? " + tls" : "");
|
{ result.append(outbound["streamSettings"].toObject()["tls"].toBool() ? " / tls" : ""); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -249,23 +251,23 @@ namespace Qv2ray::core::handlers
|
|||||||
|
|
||||||
const tuple<quint64, quint64> QvConnectionHandler::GetConnectionUsageAmount(const ConnectionId &id) const
|
const tuple<quint64, quint64> QvConnectionHandler::GetConnectionUsageAmount(const ConnectionId &id) const
|
||||||
{
|
{
|
||||||
if (!connections.contains(id)) {
|
if (!connections.contains(id)) { return make_tuple(0, 0); }
|
||||||
return make_tuple(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_tuple(connections[id].upLinkData, connections[id].downLinkData);
|
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];
|
// return groups[id];
|
||||||
//}
|
//}
|
||||||
|
|
||||||
QvConnectionHandler::~QvConnectionHandler()
|
QvConnectionHandler::~QvConnectionHandler()
|
||||||
{
|
{
|
||||||
CHSaveConnectionData_p();
|
CHSaveConfigData_p();
|
||||||
|
|
||||||
if (vCoreInstance->KernelStarted) {
|
if (vCoreInstance->KernelStarted)
|
||||||
|
{
|
||||||
vCoreInstance->StopConnection();
|
vCoreInstance->StopConnection();
|
||||||
LOG(MODULE_CORE_HANDLER, "Stopped connection from destructor.")
|
LOG(MODULE_CORE_HANDLER, "Stopped connection from destructor.")
|
||||||
}
|
}
|
||||||
@ -285,36 +287,49 @@ namespace Qv2ray::core::handlers
|
|||||||
return CONFIGROOT(JsonFromString(StringFromFile(path)));
|
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);
|
auto root = GetConnectionRoot(id);
|
||||||
bool validOutboundFound = false;
|
|
||||||
QString host;
|
|
||||||
int port;
|
|
||||||
|
|
||||||
for (auto item : root["outbounds"].toArray()) {
|
bool isSucceed = false;
|
||||||
OUTBOUND outBoundRoot = OUTBOUND(item.toObject());
|
auto result = CHGetOutboundData_p(root, &isSucceed);
|
||||||
QString outboundType = "";
|
return result;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
void QvConnectionHandler::OnLatencyDataArrived(const QvTCPingResultObject &result)
|
||||||
{
|
{
|
||||||
if (connections.contains(result.connectionId)) {
|
if (connections.contains(result.connectionId))
|
||||||
|
{
|
||||||
connections[result.connectionId].latency = result.avg;
|
connections[result.connectionId].latency = result.avg;
|
||||||
emit OnLatencyTestFinished(result.connectionId, result.avg);
|
emit OnLatencyTestFinished(result.connectionId, result.avg);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_CORE_HANDLER, "Received a latecy result with non-exist connection id.")
|
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)
|
bool QvConnectionHandler::UpdateConnection(const ConnectionId &id, const CONFIGROOT &root)
|
||||||
{
|
{
|
||||||
auto groupId = connections[id].groupId;
|
auto groupId = connections[id].groupId;
|
||||||
auto path = (groups[groupId].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR)
|
auto path = (groups[groupId].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR) + groupId.toString() + "/" +
|
||||||
+ groupId.toString() + "/" + id.toString() + QV2RAY_CONFIG_FILE_EXTENSION;
|
id.toString() + QV2RAY_CONFIG_FILE_EXTENSION;
|
||||||
auto content = JsonToString(root);
|
auto content = JsonToString(root);
|
||||||
emit OnConnectionChanged(id);
|
emit OnConnectionChanged(id);
|
||||||
return StringToFile(content, path);
|
return StringToFile(content, path);
|
||||||
@ -333,10 +348,101 @@ namespace Qv2ray::core::handlers
|
|||||||
{
|
{
|
||||||
tuple<QString, int64_t, float> result;
|
tuple<QString, int64_t, float> result;
|
||||||
|
|
||||||
if (!groups[id].isSubscription) {
|
if (!groups[id].isSubscription) { return result; }
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_tuple(groups[id].address, groups[id].lastUpdated, groups[id].updateInterval);
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#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/kernel/KernelInteractions.hpp"
|
||||||
#include "core/tcping/QvTCPing.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
|
namespace Qv2ray::core::handlers
|
||||||
{
|
{
|
||||||
class QvConnectionHandler : public QObject
|
class QvConnectionHandler : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QvConnectionHandler();
|
explicit QvConnectionHandler();
|
||||||
~QvConnectionHandler();
|
~QvConnectionHandler();
|
||||||
//
|
//
|
||||||
const QList<ConnectionId> Connections() const;
|
const QList<ConnectionId> Connections() const;
|
||||||
//
|
//
|
||||||
const QList<GroupId> AllGroups() const;
|
const QList<GroupId> AllGroups() const;
|
||||||
const QList<GroupId> Subscriptions() const;
|
const QList<GroupId> Subscriptions() const;
|
||||||
const QList<ConnectionId> Connections(const GroupId &groupId) const;
|
const QList<ConnectionId> Connections(const GroupId &groupId) const;
|
||||||
//
|
//
|
||||||
// Generic Get Options
|
// Generic Get Options
|
||||||
const QString GetDisplayName(const GroupId &id, int limit = -1) const;
|
const QString GetDisplayName(const GroupId &id, int limit = -1) const;
|
||||||
const QString GetDisplayName(const ConnectionId &id, int limit = -1) const;
|
const QString GetDisplayName(const ConnectionId &id, int limit = -1) const;
|
||||||
const GroupId GetGroupIdByDisplayName(const QString &displayName) const;
|
const GroupId GetGroupIdByDisplayName(const QString &displayName) const;
|
||||||
const ConnectionId GetConnectionIdByDisplayName(const QString &displayName) const;
|
const ConnectionId GetConnectionIdByDisplayName(const QString &displayName) const;
|
||||||
//
|
//
|
||||||
// Connectivity Operationss
|
// Connectivity Operationss
|
||||||
bool IsConnected(const ConnectionId &id) const;
|
bool IsConnected(const ConnectionId &id) const;
|
||||||
const optional<QString> StartConnection(const ConnectionId &identifier);
|
const optional<QString> StartConnection(const ConnectionId &identifier);
|
||||||
void StopConnection(); //const ConnectionId &id
|
void StopConnection(); // const ConnectionId &id
|
||||||
//
|
//
|
||||||
// Connection Operations.
|
// Connection Operations.
|
||||||
const GroupId GetConnectionGroupId(const ConnectionId &id) const;
|
const GroupId GetConnectionGroupId(const ConnectionId &id) const;
|
||||||
double GetConnectionLatency(const ConnectionId &id) const;
|
double GetConnectionLatency(const ConnectionId &id) const;
|
||||||
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
|
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
|
||||||
const optional<QString> DeleteConnection(const ConnectionId &id);
|
const optional<QString> DeleteConnection(const ConnectionId &id);
|
||||||
bool UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
|
bool UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
|
||||||
const optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
|
const optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
|
||||||
const ConnectionId DuplicateConnection(const ConnectionId &id);
|
const ConnectionId DuplicateConnection(const ConnectionId &id);
|
||||||
const optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
|
const optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
|
||||||
//
|
//
|
||||||
const CONFIGROOT GetConnectionRoot(const ConnectionId &id) const;
|
const CONFIGROOT GetConnectionRoot(const ConnectionId &id) const;
|
||||||
const CONFIGROOT GetConnectionRoot(const GroupId &group, const ConnectionId &id) const;
|
const CONFIGROOT GetConnectionRoot(const GroupId &group, const ConnectionId &id) const;
|
||||||
//
|
//
|
||||||
// Get Conncetion Property
|
// Get Conncetion Property
|
||||||
const QString GetConnectionProtocolString(const ConnectionId &id) const;
|
const QString GetConnectionProtocolString(const ConnectionId &id) const;
|
||||||
const tuple<QString, int> GetConnectionInfo(const ConnectionId &connectionId) const;
|
const tuple<QString, QString, int> GetConnectionData(const ConnectionId &connectionId) const;
|
||||||
const tuple<quint64, quint64> GetConnectionUsageAmount(const ConnectionId &id) const;
|
const tuple<quint64, quint64> GetConnectionUsageAmount(const ConnectionId &id) const;
|
||||||
//
|
//
|
||||||
// Misc Connection Operations
|
// Misc Connection Operations
|
||||||
void StartLatencyTest();
|
void StartLatencyTest();
|
||||||
void StartLatencyTest(const GroupId &id);
|
void StartLatencyTest(const GroupId &id);
|
||||||
void StartLatencyTest(const ConnectionId &id);
|
void StartLatencyTest(const ConnectionId &id);
|
||||||
//
|
//
|
||||||
// Group Operations
|
// Group Operations
|
||||||
const optional<QString> DeleteGroup(const GroupId &id);
|
const optional<QString> DeleteGroup(const GroupId &id);
|
||||||
const optional<QString> DuplicateGroup(const GroupId &id);
|
const optional<QString> DuplicateGroup(const GroupId &id);
|
||||||
const GroupId &CreateGroup(const QString displayName, bool isSubscription);
|
const GroupId &CreateGroup(const QString displayName, bool isSubscription);
|
||||||
const optional<QString> RenameGroup(const GroupId &id, const QString &newName);
|
const optional<QString> RenameGroup(const GroupId &id, const QString &newName);
|
||||||
//
|
//
|
||||||
// Subscriptions
|
// Subscriptions
|
||||||
const optional<QString> UpdateSubscription(const GroupId &id, bool useSystemProxy);
|
bool UpdateSubscription(const GroupId &id, bool useSystemProxy);
|
||||||
const optional<QString> UpdateSubscriptionASync(const GroupId &id, bool useSystemProxy);
|
bool UpdateSubscriptionASync(const GroupId &id, bool useSystemProxy);
|
||||||
const tuple<QString, int64_t, float> GetSubscriptionData(const GroupId &id);
|
const tuple<QString, int64_t, float> GetSubscriptionData(const GroupId &id);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void OnCrashed();
|
void OnCrashed();
|
||||||
void OnConnected(const ConnectionId &id);
|
void OnConnected(const ConnectionId &id);
|
||||||
void OnDisConnected(const ConnectionId &id);
|
void OnDisConnected(const ConnectionId &id);
|
||||||
void OnVCoreLogAvailable(const ConnectionId &id, const QString &log);
|
void OnVCoreLogAvailable(const ConnectionId &id, const QString &log);
|
||||||
void OnStatsAvailable(const ConnectionId &id,
|
void OnStatsAvailable(const ConnectionId &id, const quint64 uploadSpeed, const quint64 downloadSpeed, const quint64 totalUpload,
|
||||||
const quint64 uploadSpeed, const quint64 downloadSpeed,
|
const quint64 totalDownload);
|
||||||
const quint64 totalUpload, const quint64 totalDownload);
|
//
|
||||||
//
|
void OnConnectionCreated(const ConnectionId &id, const QString &displayName);
|
||||||
void OnConnectionCreated(const ConnectionId &id, const QString &displayName);
|
void OnConnectionRenamed(const ConnectionId &id, const QString &originalName, const QString &newName);
|
||||||
void OnConnectionRenamed(const ConnectionId &id, const QString &originalName, const QString &newName);
|
void OnConnectionChanged(const ConnectionId &id);
|
||||||
void OnConnectionChanged(const ConnectionId &id);
|
void OnConnectionGroupChanged(const ConnectionId &id, const QString &originalGroup, const QString &newGroup);
|
||||||
void OnConnectionGroupChanged(const ConnectionId &id, const QString &originalGroup, const QString &newGroup);
|
//
|
||||||
//
|
void OnLatencyTestStarted(const ConnectionId &id);
|
||||||
void OnLatencyTestStarted(const ConnectionId &id);
|
void OnLatencyTestFinished(const ConnectionId &id, const uint average);
|
||||||
void OnLatencyTestFinished(const ConnectionId &id, const uint average);
|
//
|
||||||
//
|
void OnGroupCreated(const GroupId &id, const QString &displayName);
|
||||||
void OnGroupCreated(const GroupId &id, const QString &displayName);
|
void OnGroupRenamed(const GroupId &id, const QString &oldName, const QString &newName);
|
||||||
void OnGroupRenamed(const GroupId &id, const QString &oldName, const QString &newName);
|
void OnGroupDeleted(const GroupId &id, const QString &displayName);
|
||||||
void OnGroupDeleted(const GroupId &id, const QString &displayName);
|
//
|
||||||
//
|
// void OnSubscriptionCreated(const GroupId &id, const QString &displayName, const QString &address);
|
||||||
//void OnSubscriptionCreated(const GroupId &id, const QString &displayName, const QString &address);
|
// void OnSubscriptionDeleted(const GroupId &id, const QString &oldName, const QString &newName);
|
||||||
//void OnSubscriptionDeleted(const GroupId &id, const QString &oldName, const QString &newName);
|
void OnSubscriptionUpdateFinished(const GroupId &id);
|
||||||
void OnSubscriptionUpdateFinished(const GroupId &id);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void OnStatsDataArrived(const ConnectionId &id, const quint64 uploadSpeed, const quint64 downloadSpeed);
|
void OnStatsDataArrived(const ConnectionId &id, const quint64 uploadSpeed, const quint64 downloadSpeed);
|
||||||
void OnVCoreCrashed(const ConnectionId &id);
|
void OnVCoreCrashed(const ConnectionId &id);
|
||||||
void OnLatencyDataArrived(const QvTCPingResultObject &data);
|
void OnLatencyDataArrived(const QvTCPingResultObject &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CHSaveConnectionData_p();
|
void CHSaveConfigData_p();
|
||||||
//
|
//
|
||||||
optional<QString> CHStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
|
optional<QString> CHStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
|
||||||
void CHStopConnection_p();
|
void CHStopConnection_p();
|
||||||
bool CHSaveConnectionConfig_p(CONFIGROOT obj, const ConnectionId &id, bool override);
|
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:
|
private:
|
||||||
int saveTimerId;
|
int saveTimerId;
|
||||||
int pingAllTimerId;
|
int pingAllTimerId;
|
||||||
int pingConnectionTimerId;
|
int pingConnectionTimerId;
|
||||||
QHash<GroupId, GroupMetaObject> groups;
|
QHash<GroupId, GroupMetaObject> groups;
|
||||||
QHash<ConnectionId, ConnectionMetaObject> connections;
|
QHash<ConnectionId, ConnectionMetaObject> connections;
|
||||||
//QHash<ConnectionId, CONFIGROOT> connectionRootCache;
|
// QHash<ConnectionId, CONFIGROOT> connectionRootCache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QvHttpRequestHelper *httpHelper;
|
QvHttpRequestHelper *httpHelper;
|
||||||
QvTCPingHelper *tcpingHelper;
|
bool isHttpRequestInProgress = false;
|
||||||
// We only support one cuncurrent connection currently.
|
QvTCPingHelper *tcpingHelper;
|
||||||
|
// We only support one cuncurrent connection currently.
|
||||||
#ifdef QV2RAY_MULTIPlE_ONNECTION
|
#ifdef QV2RAY_MULTIPlE_ONNECTION
|
||||||
QHash<ConnectionId, *V2rayKernelInstance> kernelInstances;
|
QHash<ConnectionId, *V2rayKernelInstance> kernelInstances;
|
||||||
#else
|
#else
|
||||||
ConnectionId currentConnectionId = NullConnectionId;
|
ConnectionId currentConnectionId = NullConnectionId;
|
||||||
V2rayKernelInstance *vCoreInstance = nullptr;
|
V2rayKernelInstance *vCoreInstance = nullptr;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ::Qv2ray::core::handlers::QvConnectionHandler *ConnectionManager = nullptr;
|
inline ::Qv2ray::core::handlers::QvConnectionHandler *ConnectionManager = nullptr;
|
||||||
}
|
} // namespace Qv2ray::core::handlers
|
||||||
|
|
||||||
using 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 fullConfig = GenerateRuntimeConfig(root);
|
||||||
auto result = vCoreInstance->StartConnection(id, fullConfig);
|
auto result = vCoreInstance->StartConnection(id, fullConfig);
|
||||||
|
|
||||||
if (!result.has_value()) {
|
if (!result.has_value())
|
||||||
|
{
|
||||||
currentConnectionId = id;
|
currentConnectionId = id;
|
||||||
emit OnConnected(currentConnectionId);
|
emit OnConnected(currentConnectionId);
|
||||||
}
|
}
|
||||||
@ -18,13 +19,16 @@ optional<QString> QvConnectionHandler::CHStartConnection_p(const ConnectionId &i
|
|||||||
|
|
||||||
void QvConnectionHandler::CHStopConnection_p()
|
void QvConnectionHandler::CHStopConnection_p()
|
||||||
{
|
{
|
||||||
if (vCoreInstance->KernelStarted) {
|
if (vCoreInstance->KernelStarted)
|
||||||
|
{
|
||||||
vCoreInstance->StopConnection();
|
vCoreInstance->StopConnection();
|
||||||
// Copy
|
// Copy
|
||||||
ConnectionId id = currentConnectionId;
|
ConnectionId id = currentConnectionId;
|
||||||
currentConnectionId = NullConnectionId;
|
currentConnectionId = NullConnectionId;
|
||||||
emit OnDisConnected(id);
|
emit OnDisConnected(id);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_CORE_HANDLER, "VCore is not started, not disconnecting")
|
LOG(MODULE_CORE_HANDLER, "VCore is not started, not disconnecting")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ using grpc::Channel;
|
|||||||
using grpc::ClientContext;
|
using grpc::ClientContext;
|
||||||
using grpc::Status;
|
using grpc::Status;
|
||||||
#else
|
#else
|
||||||
#include "libs/libqvb/build/libqvb.h"
|
#include "libs/libqvb/build/libqvb.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Qv2ray::core::kernel
|
namespace Qv2ray::core::kernel
|
||||||
@ -22,9 +22,7 @@ namespace Qv2ray::core::kernel
|
|||||||
DEBUG(MODULE_VCORE, "API Worker initialised.")
|
DEBUG(MODULE_VCORE, "API Worker initialised.")
|
||||||
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
|
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
|
||||||
connect(thread, SIGNAL(started()), this, SLOT(process()));
|
connect(thread, SIGNAL(started()), this, SLOT(process()));
|
||||||
connect(thread, &QThread::finished, []() {
|
connect(thread, &QThread::finished, []() { LOG(MODULE_VCORE, "API thread stopped") });
|
||||||
LOG(MODULE_VCORE, "API thread stopped")
|
|
||||||
});
|
|
||||||
started = true;
|
started = true;
|
||||||
thread->start();
|
thread->start();
|
||||||
DEBUG(MODULE_VCORE, "API Worker started.")
|
DEBUG(MODULE_VCORE, "API Worker started.")
|
||||||
@ -52,21 +50,22 @@ namespace Qv2ray::core::kernel
|
|||||||
thread->wait();
|
thread->wait();
|
||||||
|
|
||||||
// Although thread shouldnot be null, we'll add this check to be safe.
|
// Although thread shouldnot be null, we'll add this check to be safe.
|
||||||
if (thread) {
|
if (thread) { delete thread; }
|
||||||
delete thread;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// API Core Operations
|
// API Core Operations
|
||||||
// Start processing data.
|
// Start processing data.
|
||||||
void APIWorker::process()
|
void APIWorker::process()
|
||||||
{
|
{
|
||||||
while (started) {
|
while (started)
|
||||||
|
{
|
||||||
QThread::msleep(1000);
|
QThread::msleep(1000);
|
||||||
bool dialed = false;
|
bool dialed = false;
|
||||||
|
|
||||||
while (running) {
|
while (running)
|
||||||
if (!dialed) {
|
{
|
||||||
|
if (!dialed)
|
||||||
|
{
|
||||||
auto channelAddress = "127.0.0.1:" + QString::number(GlobalConfig.apiConfig.statsPort);
|
auto channelAddress = "127.0.0.1:" + QString::number(GlobalConfig.apiConfig.statsPort);
|
||||||
#ifdef WITH_LIB_GRPCPP
|
#ifdef WITH_LIB_GRPCPP
|
||||||
Channel = grpc::CreateChannel(channelAddress.toStdString(), grpc::InsecureChannelCredentials());
|
Channel = grpc::CreateChannel(channelAddress.toStdString(), grpc::InsecureChannelCredentials());
|
||||||
@ -85,36 +84,44 @@ namespace Qv2ray::core::kernel
|
|||||||
qint64 value_up = 0;
|
qint64 value_up = 0;
|
||||||
qint64 value_down = 0;
|
qint64 value_down = 0;
|
||||||
|
|
||||||
for (auto tag : inboundTags) {
|
for (auto tag : inboundTags)
|
||||||
|
{
|
||||||
value_up += CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>uplink");
|
value_up += CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>uplink");
|
||||||
value_down += CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>downlink");
|
value_down += CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>downlink");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value_up < 0 || value_down < 0) {
|
if (value_up < 0 || value_down < 0)
|
||||||
|
{
|
||||||
dialed = false;
|
dialed = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running) {
|
if (running)
|
||||||
|
{
|
||||||
apiFailedCounter = 0;
|
apiFailedCounter = 0;
|
||||||
emit OnDataReady(value_up, value_down);
|
emit OnDataReady(value_up, value_down);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
for (auto tag : inboundTags) {
|
for (auto tag : inboundTags)
|
||||||
|
{
|
||||||
auto valup = CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>uplink");
|
auto valup = CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>uplink");
|
||||||
auto valdown = CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>downlink");
|
auto valdown = CallStatsAPIByName("inbound>>>" + tag + ">>>traffic>>>downlink");
|
||||||
|
|
||||||
if (valup < 0 || valdown < 0) {
|
if (valup < 0 || valdown < 0)
|
||||||
|
{
|
||||||
dialed = false;
|
dialed = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running) {
|
if (running)
|
||||||
|
{
|
||||||
apiFailedCounter = 0;
|
apiFailedCounter = 0;
|
||||||
emit OnDataReady(tag, valup, valdown);
|
emit OnDataReady(tag, valup, valdown);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// If the connection has stopped, just quit.
|
// If the connection has stopped, just quit.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -123,19 +130,22 @@ namespace Qv2ray::core::kernel
|
|||||||
#endif
|
#endif
|
||||||
QThread::msleep(1000);
|
QThread::msleep(1000);
|
||||||
} // end while running
|
} // end while running
|
||||||
} // end while started
|
} // end while started
|
||||||
|
|
||||||
thread->exit();
|
thread->exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 APIWorker::CallStatsAPIByName(const QString &name)
|
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.")
|
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");
|
emit error("Failed to get statistics data, please check if V2ray is running properly");
|
||||||
apiFailedCounter++;
|
apiFailedCounter++;
|
||||||
return 0;
|
return 0;
|
||||||
} else if (apiFailedCounter > QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD) {
|
}
|
||||||
|
else if (apiFailedCounter > QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +157,8 @@ namespace Qv2ray::core::kernel
|
|||||||
ClientContext context;
|
ClientContext context;
|
||||||
Status status = Stub->GetStats(&context, request, &response);
|
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()) + ")")
|
LOG(MODULE_VCORE, "API call returns: " + QSTRN(status.error_code()) + " (" + QString::fromStdString(status.error_message()) + ")")
|
||||||
apiFailedCounter++;
|
apiFailedCounter++;
|
||||||
}
|
}
|
||||||
@ -157,7 +168,8 @@ namespace Qv2ray::core::kernel
|
|||||||
qint64 data = GetStats(const_cast<char *>(name.toStdString().c_str()), 1000);
|
qint64 data = GetStats(const_cast<char *>(name.toStdString().c_str()), 1000);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (data < 0) {
|
if (data < 0)
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, "API call returns: " + QSTRN(data))
|
LOG(MODULE_VCORE, "API call returns: " + QSTRN(data))
|
||||||
apiFailedCounter++;
|
apiFailedCounter++;
|
||||||
return 0;
|
return 0;
|
||||||
@ -165,4 +177,4 @@ namespace Qv2ray::core::kernel
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::core::kernel
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#ifdef WITH_LIB_GRPCPP
|
#ifdef WITH_LIB_GRPCPP
|
||||||
#include <grpc++/grpc++.h>
|
#include "libs/gen/v2ray_api.grpc.pb.h"
|
||||||
#include "libs/gen/v2ray_api.pb.h"
|
#include "libs/gen/v2ray_api.pb.h"
|
||||||
#include "libs/gen/v2ray_api.grpc.pb.h"
|
|
||||||
|
#include <grpc++/grpc++.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Check 10 times before telling user that API has failed.
|
// Check 10 times before telling user that API has failed.
|
||||||
@ -13,34 +14,34 @@ namespace Qv2ray::core::kernel
|
|||||||
{
|
{
|
||||||
class APIWorker : public QObject
|
class APIWorker : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
APIWorker();
|
APIWorker();
|
||||||
~APIWorker();
|
~APIWorker();
|
||||||
void StartAPI(const QStringList &tags);
|
void StartAPI(const QStringList &tags);
|
||||||
void StopAPI();
|
void StopAPI();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void OnDataReady(const quint64 _totalUp, const quint64 _totalDown);
|
void OnDataReady(const quint64 _totalUp, const quint64 _totalDown);
|
||||||
void error(const QString &err);
|
void error(const QString &err);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qint64 CallStatsAPIByName(const QString &name);
|
qint64 CallStatsAPIByName(const QString &name);
|
||||||
QStringList inboundTags;
|
QStringList inboundTags;
|
||||||
QThread *thread;
|
QThread *thread;
|
||||||
//
|
//
|
||||||
bool started = false;
|
bool started = false;
|
||||||
bool running = false;
|
bool running = false;
|
||||||
uint apiFailedCounter = 0;
|
uint apiFailedCounter = 0;
|
||||||
#ifdef WITH_LIB_GRPCPP
|
#ifdef WITH_LIB_GRPCPP
|
||||||
std::shared_ptr<::grpc::Channel> Channel;
|
std::shared_ptr<::grpc::Channel> Channel;
|
||||||
std::unique_ptr<::v2ray::core::app::stats::command::StatsService::Stub> Stub;
|
std::unique_ptr<::v2ray::core::app::stats::command::StatsService::Stub> Stub;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::core::kernel
|
||||||
|
|
||||||
using 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 <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDesktopServices>
|
|
||||||
#include "common/QvHelpers.hpp"
|
|
||||||
#include "KernelInteractions.hpp"
|
|
||||||
#include "core/connection/ConnectionIO.hpp"
|
|
||||||
#include "APIBackend.hpp"
|
|
||||||
|
|
||||||
namespace Qv2ray::core::kernel
|
namespace Qv2ray::core::kernel
|
||||||
{
|
{
|
||||||
@ -12,14 +14,17 @@ namespace Qv2ray::core::kernel
|
|||||||
{
|
{
|
||||||
QFile coreFile(vCorePath);
|
QFile coreFile(vCorePath);
|
||||||
|
|
||||||
if (!coreFile.exists()) {
|
if (!coreFile.exists())
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "V2ray core file cannot be found.")
|
DEBUG(MODULE_VCORE, "V2ray core file cannot be found.")
|
||||||
*message = tr("V2ray core executable not found.");
|
*message = tr("V2ray core executable not found.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use open() here to prevent `executing` a folder, which may have the same name as the V2ray core.
|
// Use open() here to prevent `executing` a folder, which may have the
|
||||||
if (!coreFile.open(QFile::ReadOnly)) {
|
// same name as the V2ray core.
|
||||||
|
if (!coreFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "V2ray core file cannot be opened, possibly be a folder?")
|
DEBUG(MODULE_VCORE, "V2ray core file cannot be opened, possibly be a folder?")
|
||||||
*message = tr("V2ray core file cannot be opened, please ensure there's a file instead of a folder.");
|
*message = tr("V2ray core file cannot be opened, please ensure there's a file instead of a folder.");
|
||||||
return false;
|
return false;
|
||||||
@ -33,28 +38,32 @@ namespace Qv2ray::core::kernel
|
|||||||
bool hasGeoIP = FileExistsIn(QDir(vAssetsPath), "geoip.dat");
|
bool hasGeoIP = FileExistsIn(QDir(vAssetsPath), "geoip.dat");
|
||||||
bool hasGeoSite = FileExistsIn(QDir(vAssetsPath), "geosite.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.")
|
DEBUG(MODULE_VCORE, "V2ray assets path contains none of those two files.")
|
||||||
*message = tr("V2ray assets path is not valid.");
|
*message = tr("V2ray assets path is not valid.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasGeoIP) {
|
if (!hasGeoIP)
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "No geoip.dat in assets path, aborting.")
|
DEBUG(MODULE_VCORE, "No geoip.dat in assets path, aborting.")
|
||||||
*message = tr("No geoip.dat in assets path.");
|
*message = tr("No geoip.dat in assets path.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasGeoSite) {
|
if (!hasGeoSite)
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "No geosite.dat in assets path, aborting.")
|
DEBUG(MODULE_VCORE, "No geosite.dat in assets path, aborting.")
|
||||||
*message = tr("No geosite.dat in assets path.");
|
*message = tr("No geosite.dat in assets path.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if V2ray core returns a version number correctly.
|
// Check if V2ray core returns a version number correctly.
|
||||||
QProcess proc;
|
QProcess proc;
|
||||||
#ifdef Q_OS_WIN32
|
#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.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
proc.setProgram(vCorePath);
|
proc.setProgram(vCorePath);
|
||||||
proc.setNativeArguments("--version");
|
proc.setNativeArguments("--version");
|
||||||
@ -66,7 +75,8 @@ namespace Qv2ray::core::kernel
|
|||||||
proc.waitForFinished();
|
proc.waitForFinished();
|
||||||
auto exitCode = proc.exitCode();
|
auto exitCode = proc.exitCode();
|
||||||
|
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0)
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "VCore failed with an exit code: " + QSTRN(exitCode))
|
DEBUG(MODULE_VCORE, "VCore failed with an exit code: " + QSTRN(exitCode))
|
||||||
*message = tr("V2ray core failed with an exit code: ") + QSTRN(exitCode);
|
*message = tr("V2ray core failed with an exit code: ") + QSTRN(exitCode);
|
||||||
return false;
|
return false;
|
||||||
@ -75,7 +85,8 @@ namespace Qv2ray::core::kernel
|
|||||||
QString output = proc.readAllStandardOutput();
|
QString output = proc.readAllStandardOutput();
|
||||||
LOG(MODULE_VCORE, "V2ray output: " + SplitLines(output).join(";"))
|
LOG(MODULE_VCORE, "V2ray output: " + SplitLines(output).join(";"))
|
||||||
|
|
||||||
if (SplitLines(output).isEmpty()) {
|
if (SplitLines(output).isEmpty())
|
||||||
|
{
|
||||||
*message = tr("V2ray core returns empty string.");
|
*message = tr("V2ray core returns empty string.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -84,12 +95,12 @@ namespace Qv2ray::core::kernel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool V2rayKernelInstance::ValidateConfig(const QString &path)
|
bool V2rayKernelInstance::ValidateConfig(const QString &path)
|
||||||
{
|
{
|
||||||
QString v2rayCheckResult;
|
QString v2rayCheckResult;
|
||||||
|
|
||||||
if (ValidateKernel(GlobalConfig.v2CorePath, GlobalConfig.v2AssetsPath, &v2rayCheckResult)) {
|
if (ValidateKernel(GlobalConfig.v2CorePath, GlobalConfig.v2AssetsPath, &v2rayCheckResult))
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "V2ray version: " + v2rayCheckResult)
|
DEBUG(MODULE_VCORE, "V2ray version: " + v2rayCheckResult)
|
||||||
// Append assets location env.
|
// Append assets location env.
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
@ -98,21 +109,28 @@ namespace Qv2ray::core::kernel
|
|||||||
QProcess process;
|
QProcess process;
|
||||||
process.setProcessEnvironment(env);
|
process.setProcessEnvironment(env);
|
||||||
DEBUG(MODULE_VCORE, "Starting V2ray core with test options")
|
DEBUG(MODULE_VCORE, "Starting V2ray core with test options")
|
||||||
process.start(GlobalConfig.v2CorePath, QStringList() << "-test" << "-config" << path, QIODevice::ReadWrite | QIODevice::Text);
|
process.start(GlobalConfig.v2CorePath,
|
||||||
|
QStringList() << "-test"
|
||||||
|
<< "-config" << path,
|
||||||
|
QIODevice::ReadWrite | QIODevice::Text);
|
||||||
process.waitForFinished();
|
process.waitForFinished();
|
||||||
|
|
||||||
if (process.exitCode() != 0) {
|
if (process.exitCode() != 0)
|
||||||
|
{
|
||||||
QString output = QString(process.readAllStandardOutput());
|
QString output = QString(process.readAllStandardOutput());
|
||||||
QvMessageBoxWarn(nullptr, tr("Configuration Error"), output.mid(output.indexOf("anti-censorship.") + 17));
|
QvMessageBoxWarn(nullptr, tr("Configuration Error"), output.mid(output.indexOf("anti-censorship.") + 17));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
DEBUG(MODULE_VCORE, "Config file check passed.")
|
DEBUG(MODULE_VCORE, "Config file check passed.")
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
QvMessageBoxWarn(nullptr, tr("Cannot start V2ray"),
|
QvMessageBoxWarn(nullptr, tr("Cannot start V2ray"),
|
||||||
tr("V2ray core settings is incorrect.") + NEWLINE + NEWLINE +
|
tr("V2ray core settings is incorrect.") + NEWLINE + NEWLINE + tr("The error is: ") + NEWLINE + v2rayCheckResult);
|
||||||
tr("The error is: ") + NEWLINE + v2rayCheckResult);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,14 +138,14 @@ namespace Qv2ray::core::kernel
|
|||||||
V2rayKernelInstance::V2rayKernelInstance()
|
V2rayKernelInstance::V2rayKernelInstance()
|
||||||
{
|
{
|
||||||
vProcess = new QProcess();
|
vProcess = new QProcess();
|
||||||
connect(vProcess, &QProcess::readyReadStandardOutput, this, [&]() {
|
connect(vProcess, &QProcess::readyReadStandardOutput, this,
|
||||||
emit OnProcessOutputReadyRead(id, vProcess->readAllStandardOutput().trimmed());
|
[&]() { emit OnProcessOutputReadyRead(id, vProcess->readAllStandardOutput().trimmed()); });
|
||||||
});
|
|
||||||
connect(vProcess, &QProcess::stateChanged, [&](QProcess::ProcessState state) {
|
connect(vProcess, &QProcess::stateChanged, [&](QProcess::ProcessState state) {
|
||||||
DEBUG(MODULE_VCORE, "V2ray kernel process status changed: " + QVariant::fromValue(state).toString())
|
DEBUG(MODULE_VCORE, "V2ray kernel process status changed: " + QVariant::fromValue(state).toString())
|
||||||
|
|
||||||
// If V2ray crashed AFTER we start it.
|
// If V2ray crashed AFTER we start it.
|
||||||
if (KernelStarted && state == QProcess::NotRunning) {
|
if (KernelStarted && state == QProcess::NotRunning)
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, "V2ray kernel crashed.")
|
LOG(MODULE_VCORE, "V2ray kernel crashed.")
|
||||||
StopConnection();
|
StopConnection();
|
||||||
emit OnProcessErrored(id);
|
emit OnProcessErrored(id);
|
||||||
@ -140,7 +158,8 @@ namespace Qv2ray::core::kernel
|
|||||||
|
|
||||||
optional<QString> V2rayKernelInstance::StartConnection(const ConnectionId &id, const CONFIGROOT &root)
|
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")
|
LOG(MODULE_VCORE, "Status is invalid, expect STOPPED when calling StartConnection")
|
||||||
return tr("Invalid V2ray Instance Status.");
|
return tr("Invalid V2ray Instance Status.");
|
||||||
}
|
}
|
||||||
@ -151,7 +170,8 @@ namespace Qv2ray::core::kernel
|
|||||||
//
|
//
|
||||||
auto filePath = QV2RAY_GENERATED_FILE_PATH;
|
auto filePath = QV2RAY_GENERATED_FILE_PATH;
|
||||||
|
|
||||||
if (ValidateConfig(filePath)) {
|
if (ValidateConfig(filePath))
|
||||||
|
{
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
env.insert("V2RAY_LOCATION_ASSET", GlobalConfig.v2AssetsPath);
|
env.insert("V2RAY_LOCATION_ASSET", GlobalConfig.v2AssetsPath);
|
||||||
vProcess->setProcessEnvironment(env);
|
vProcess->setProcessEnvironment(env);
|
||||||
@ -163,10 +183,12 @@ namespace Qv2ray::core::kernel
|
|||||||
this->id = id;
|
this->id = id;
|
||||||
QStringList inboundTags;
|
QStringList inboundTags;
|
||||||
|
|
||||||
for (auto item : root["inbounds"].toArray()) {
|
for (auto item : root["inbounds"].toArray())
|
||||||
|
{
|
||||||
auto tag = item.toObject()["tag"].toString("");
|
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.
|
// Ignore API tag and empty tags.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -178,20 +200,26 @@ namespace Qv2ray::core::kernel
|
|||||||
apiEnabled = false;
|
apiEnabled = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
if (StartupOption.noAPI) {
|
if (StartupOption.noAPI) { LOG(MODULE_VCORE, "API has been disabled by the command line argument \"-noAPI\"") }
|
||||||
LOG(MODULE_VCORE, "API has been disabled by the command line argument \"-noAPI\"")
|
else if (!GlobalConfig.apiConfig.enableAPI)
|
||||||
} else if (!GlobalConfig.apiConfig.enableAPI) {
|
{
|
||||||
LOG(MODULE_VCORE, "API has been disabled by the global config option")
|
LOG(MODULE_VCORE, "API has been disabled by the global config option")
|
||||||
} else if (inboundTags.isEmpty()) {
|
}
|
||||||
|
else if (inboundTags.isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, "API is disabled since no inbound tags configured. This is probably caused by a bad complex config.")
|
LOG(MODULE_VCORE, "API is disabled since no inbound tags configured. This is probably caused by a bad complex config.")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
apiWorker->StartAPI(inboundTags);
|
apiWorker->StartAPI(inboundTags);
|
||||||
apiEnabled = true;
|
apiEnabled = true;
|
||||||
DEBUG(MODULE_VCORE, "Qv2ray API started")
|
DEBUG(MODULE_VCORE, "Qv2ray API started")
|
||||||
}
|
}
|
||||||
|
|
||||||
return { };
|
return {};
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
KernelStarted = false;
|
KernelStarted = false;
|
||||||
return tr("V2ray kernel failed to start.");
|
return tr("V2ray kernel failed to start.");
|
||||||
}
|
}
|
||||||
@ -199,12 +227,14 @@ namespace Qv2ray::core::kernel
|
|||||||
|
|
||||||
void V2rayKernelInstance::StopConnection()
|
void V2rayKernelInstance::StopConnection()
|
||||||
{
|
{
|
||||||
if (apiEnabled) {
|
if (apiEnabled)
|
||||||
|
{
|
||||||
apiWorker->StopAPI();
|
apiWorker->StopAPI();
|
||||||
apiEnabled = false;
|
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;
|
KernelStarted = false;
|
||||||
vProcess->close();
|
vProcess->close();
|
||||||
// Block until V2ray core exits
|
// Block until V2ray core exits
|
||||||
@ -214,9 +244,7 @@ namespace Qv2ray::core::kernel
|
|||||||
|
|
||||||
V2rayKernelInstance::~V2rayKernelInstance()
|
V2rayKernelInstance::~V2rayKernelInstance()
|
||||||
{
|
{
|
||||||
if (KernelStarted) {
|
if (KernelStarted) { StopConnection(); }
|
||||||
StopConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete apiWorker;
|
delete apiWorker;
|
||||||
delete vProcess;
|
delete vProcess;
|
||||||
@ -226,4 +254,4 @@ namespace Qv2ray::core::kernel
|
|||||||
{
|
{
|
||||||
emit OnNewStatsDataArrived(id, _totalUp, _totalDown);
|
emit OnNewStatsDataArrived(id, _totalUp, _totalDown);
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::core::kernel
|
||||||
|
@ -1,46 +1,47 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QProcess>
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "core/CoreSafeTypes.hpp"
|
#include "core/CoreSafeTypes.hpp"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
namespace Qv2ray::core::kernel
|
namespace Qv2ray::core::kernel
|
||||||
{
|
{
|
||||||
class APIWorker;
|
class APIWorker;
|
||||||
class V2rayKernelInstance : public QObject
|
class V2rayKernelInstance : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit V2rayKernelInstance();
|
explicit V2rayKernelInstance();
|
||||||
~V2rayKernelInstance() override;
|
~V2rayKernelInstance() override;
|
||||||
//
|
//
|
||||||
// Speed
|
// Speed
|
||||||
qulonglong getTagSpeedUp(const QString &tag);
|
qulonglong getTagSpeedUp(const QString &tag);
|
||||||
qulonglong getTagSpeedDown(const QString &tag);
|
qulonglong getTagSpeedDown(const QString &tag);
|
||||||
qulonglong getAllSpeedUp();
|
qulonglong getAllSpeedUp();
|
||||||
qulonglong getAllSpeedDown();
|
qulonglong getAllSpeedDown();
|
||||||
//
|
//
|
||||||
optional<QString> StartConnection(const ConnectionId &id, const CONFIGROOT &root);
|
optional<QString> StartConnection(const ConnectionId &id, const CONFIGROOT &root);
|
||||||
void StopConnection();
|
void StopConnection();
|
||||||
bool KernelStarted = false;
|
bool KernelStarted = false;
|
||||||
//
|
//
|
||||||
static bool ValidateConfig(const QString &path);
|
static bool ValidateConfig(const QString &path);
|
||||||
static bool ValidateKernel(const QString &vCorePath, const QString &vAssetsPath, QString *message);
|
static bool ValidateKernel(const QString &vCorePath, const QString &vAssetsPath, QString *message);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void OnProcessErrored(const ConnectionId &id);
|
void OnProcessErrored(const ConnectionId &id);
|
||||||
void OnProcessOutputReadyRead(const ConnectionId &id, const QString &output);
|
void OnProcessOutputReadyRead(const ConnectionId &id, const QString &output);
|
||||||
void OnNewStatsDataArrived(const ConnectionId &id, const quint64 _totalUp, const quint64 _totalDown);
|
void OnNewStatsDataArrived(const ConnectionId &id, const quint64 _totalUp, const quint64 _totalDown);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onAPIDataReady(const quint64 _totalUp, const quint64 _totalDown);
|
void onAPIDataReady(const quint64 _totalUp, const quint64 _totalDown);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
APIWorker *apiWorker;
|
APIWorker *apiWorker;
|
||||||
QProcess *vProcess;
|
QProcess *vProcess;
|
||||||
bool apiEnabled;
|
bool apiEnabled;
|
||||||
//
|
//
|
||||||
ConnectionId id = NullConnectionId;
|
ConnectionId id = NullConnectionId;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::core::kernel
|
||||||
|
|
||||||
using namespace Qv2ray::core::kernel;
|
using namespace Qv2ray::core::kernel;
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <WinSock2.h>
|
#include <WS2tcpip.h>
|
||||||
#include <WS2tcpip.h>
|
#include <WinSock2.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/socket.h>
|
#include <netdb.h>
|
||||||
#include <netdb.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "QtConcurrent/QtConcurrent"
|
||||||
#include "QvTCPing.hpp"
|
#include "QvTCPing.hpp"
|
||||||
#include "core/handler/ConnectionHandler.hpp"
|
#include "core/handler/ConnectionHandler.hpp"
|
||||||
#include "QtConcurrent/QtConcurrent"
|
|
||||||
|
|
||||||
namespace Qv2ray::core::tcping
|
namespace Qv2ray::core::tcping
|
||||||
{
|
{
|
||||||
@ -23,7 +23,8 @@ namespace Qv2ray::core::tcping
|
|||||||
|
|
||||||
void QvTCPingHelper::StopAllLatenceTest()
|
void QvTCPingHelper::StopAllLatenceTest()
|
||||||
{
|
{
|
||||||
while (!pingWorkingThreads.isEmpty()) {
|
while (!pingWorkingThreads.isEmpty())
|
||||||
|
{
|
||||||
auto worker = pingWorkingThreads.dequeue();
|
auto worker = pingWorkingThreads.dequeue();
|
||||||
worker->future().cancel();
|
worker->future().cancel();
|
||||||
worker->cancel();
|
worker->cancel();
|
||||||
@ -35,13 +36,11 @@ namespace Qv2ray::core::tcping
|
|||||||
watcher->setFuture(QtConcurrent::run(&QvTCPingHelper::TestLatency_p, id, count));
|
watcher->setFuture(QtConcurrent::run(&QvTCPingHelper::TestLatency_p, id, count));
|
||||||
pingWorkingThreads.enqueue(watcher);
|
pingWorkingThreads.enqueue(watcher);
|
||||||
//
|
//
|
||||||
connect(watcher, &QFutureWatcher<QvTCPingResultObject>::finished, this, [ = ]() {
|
connect(watcher, &QFutureWatcher<QvTCPingResultObject>::finished, this, [=]() {
|
||||||
auto result = watcher->result();
|
auto result = watcher->result();
|
||||||
this->pingWorkingThreads.removeOne(watcher);
|
this->pingWorkingThreads.removeOne(watcher);
|
||||||
|
|
||||||
if (!result.errorMessage.isEmpty()) {
|
if (!result.errorMessage.isEmpty()) { LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage) }
|
||||||
LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
emit this->OnLatencyTestCompleted(result);
|
emit this->OnLatencyTestCompleted(result);
|
||||||
});
|
});
|
||||||
@ -54,12 +53,14 @@ namespace Qv2ray::core::tcping
|
|||||||
|
|
||||||
if (isExiting) return data;
|
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;
|
double successCount = 0, errorCount = 0;
|
||||||
addrinfo *resolved;
|
addrinfo *resolved;
|
||||||
int errcode;
|
int errcode;
|
||||||
|
|
||||||
if ((errcode = resolveHost(host.toStdString(), port, &resolved)) != 0) {
|
if ((errcode = resolveHost(host.toStdString(), port, &resolved)) != 0)
|
||||||
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
data.errorMessage = QString::fromStdWString(gai_strerror(errcode));
|
data.errorMessage = QString::fromStdWString(gai_strerror(errcode));
|
||||||
#else
|
#else
|
||||||
@ -71,26 +72,35 @@ namespace Qv2ray::core::tcping
|
|||||||
bool noAddress = false;
|
bool noAddress = false;
|
||||||
int currentCount = 0;
|
int currentCount = 0;
|
||||||
|
|
||||||
while (currentCount < count) {
|
while (currentCount < count)
|
||||||
|
{
|
||||||
if (isExiting) return QvTCPingResultObject();
|
if (isExiting) return QvTCPingResultObject();
|
||||||
|
|
||||||
system_clock::time_point start;
|
system_clock::time_point start;
|
||||||
system_clock::time_point end;
|
system_clock::time_point end;
|
||||||
|
|
||||||
if ((errcode = testLatency(resolved, &start, &end)) != 0) {
|
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 != -EADDRNOTAVAIL)
|
||||||
|
{
|
||||||
|
// LOG(MODULE_NETWORK, "Error connecting to host: " +
|
||||||
|
// data.hostName + ":" + QSTRN(data.port) + " " +
|
||||||
|
// strerror(-errcode))
|
||||||
errorCount++;
|
errorCount++;
|
||||||
} else {
|
}
|
||||||
if (noAddress) {
|
else
|
||||||
LOG(MODULE_NETWORK, ".")
|
{
|
||||||
} else {
|
if (noAddress) { LOG(MODULE_NETWORK, ".") }
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_NETWORK, "error connecting to host: " + QSTRN(-errcode) + " " + strerror(-errcode))
|
LOG(MODULE_NETWORK, "error connecting to host: " + QSTRN(-errcode) + " " + strerror(-errcode))
|
||||||
}
|
}
|
||||||
|
|
||||||
noAddress = true;
|
noAddress = true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
noAddress = false;
|
noAddress = false;
|
||||||
successCount++;
|
successCount++;
|
||||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
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.worst = min(data.worst, ms);
|
||||||
data.best = max(data.best, ms);
|
data.best = max(data.best, ms);
|
||||||
|
|
||||||
if (ms > 1000) {
|
if (ms > 1000)
|
||||||
|
{
|
||||||
LOG(MODULE_NETWORK, "Stop the test on the first long connect()")
|
LOG(MODULE_NETWORK, "Stop the test on the first long connect()")
|
||||||
break; /* 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;
|
int rv = 0;
|
||||||
|
|
||||||
/* try to connect for each of the entries: */
|
/* try to connect for each of the entries: */
|
||||||
while (addr != nullptr) {
|
while (addr != nullptr)
|
||||||
|
{
|
||||||
if (isExiting) return 0;
|
if (isExiting) return 0;
|
||||||
|
|
||||||
/* create socket */
|
/* create socket */
|
||||||
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||||
|
|
||||||
if (!fd) {
|
if (!fd) { goto next_addr0; }
|
||||||
goto next_addr0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
// Windows needs special conversion.
|
// 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
|
#else
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||||
#endif
|
#endif
|
||||||
@ -172,7 +182,8 @@ namespace Qv2ray::core::tcping
|
|||||||
/* connect to peer */
|
/* connect to peer */
|
||||||
// Qt has its own connect() function in QObject....
|
// Qt has its own connect() function in QObject....
|
||||||
// So we add "::" here
|
// 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();
|
*end = system_clock::now();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
@ -182,17 +193,17 @@ namespace Qv2ray::core::tcping
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_addr1:
|
next_addr1:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
#else
|
#else
|
||||||
close(fd);
|
close(fd);
|
||||||
#endif
|
#endif
|
||||||
next_addr0:
|
next_addr0:
|
||||||
addr = addr->ai_next;
|
addr = addr->ai_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = rv ? rv : -errno;
|
rv = rv ? rv : -errno;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::core::tcping
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
namespace Qv2ray::core::tcping
|
namespace Qv2ray::core::tcping
|
||||||
{
|
{
|
||||||
struct QvTCPingResultObject {
|
struct QvTCPingResultObject
|
||||||
|
{
|
||||||
ConnectionId connectionId = NullConnectionId;
|
ConnectionId connectionId = NullConnectionId;
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
int total, succeed, failed;
|
int total, succeed, failed;
|
||||||
@ -13,19 +14,20 @@ namespace Qv2ray::core::tcping
|
|||||||
|
|
||||||
class QvTCPingHelper : public QObject
|
class QvTCPingHelper : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit QvTCPingHelper(const int defaultCount = 5, QObject *parent = nullptr);
|
explicit QvTCPingHelper(const int defaultCount = 5, QObject *parent = nullptr);
|
||||||
void TestLatency(const ConnectionId &connectionId);
|
void TestLatency(const ConnectionId &connectionId);
|
||||||
void StopAllLatenceTest();
|
void StopAllLatenceTest();
|
||||||
signals:
|
signals:
|
||||||
void OnLatencyTestCompleted(const QvTCPingResultObject &data);
|
void OnLatencyTestCompleted(const QvTCPingResultObject &data);
|
||||||
private:
|
|
||||||
static QvTCPingResultObject TestLatency_p(const ConnectionId &id, const int count);
|
private:
|
||||||
int count;
|
static QvTCPingResultObject TestLatency_p(const ConnectionId &id, const int count);
|
||||||
QQueue<QFutureWatcher<QvTCPingResultObject>*> pingWorkingThreads;
|
int count;
|
||||||
|
QQueue<QFutureWatcher<QvTCPingResultObject> *> pingWorkingThreads;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::core::tcping
|
||||||
|
|
||||||
using namespace Qv2ray::core::tcping;
|
using namespace Qv2ray::core::tcping;
|
||||||
|
284
src/main.cpp
284
src/main.cpp
@ -1,37 +1,36 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStandardPaths>
|
#include "common/CommandArgs.hpp"
|
||||||
#include <QTranslator>
|
#include "common/QvHelpers.hpp"
|
||||||
#include <QStyle>
|
#include "common/QvTranslator.hpp"
|
||||||
#include <QLocale>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QStyleFactory>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <singleapplication.h>
|
|
||||||
#include <csignal>
|
|
||||||
#include "ui/w_MainWindow.hpp"
|
|
||||||
|
|
||||||
#include "core/config/ConfigBackend.hpp"
|
#include "core/config/ConfigBackend.hpp"
|
||||||
#include "core/handler/ConnectionHandler.hpp"
|
#include "core/handler/ConnectionHandler.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "ui/w_MainWindow.hpp"
|
||||||
#include "common/CommandArgs.hpp"
|
|
||||||
#include "common/QvTranslator.hpp"
|
#include <QApplication>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QTranslator>
|
||||||
|
#include <csignal>
|
||||||
|
#include <singleapplication.h>
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
// For unix root user check
|
// For unix root user check
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void signalHandler(int signum)
|
void signalHandler(int signum)
|
||||||
{
|
{
|
||||||
cout << "Interrupt signal (" << signum << ") received." << endl;
|
cout << "Interrupt signal (" << signum << ") received." << endl;
|
||||||
//if (MainWindow::mwInstance && MainWindow::mwInstance->vinstance) {
|
// if (MainWindow::mwInstance && MainWindow::mwInstance->vinstance) {
|
||||||
// cout << "Trying to stop connection..." << endl;
|
// cout << "Trying to stop connection..." << endl;
|
||||||
// MainWindow::mwInstance->vinstance->StopConnection();
|
// MainWindow::mwInstance->vinstance->StopConnection();
|
||||||
//}
|
//}
|
||||||
qApp->exit(-99);
|
qApp->exit(-99);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
|
bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
|
||||||
{
|
{
|
||||||
// Does not exist.
|
// 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()));
|
QFile testFile(path + ".qv2ray_file_write_test_file" + QSTRN(QTime::currentTime().msecsSinceStartOfDay()));
|
||||||
bool opened = testFile.open(QFile::OpenModeFlag::ReadWrite);
|
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_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.")
|
LOG(MODULE_INIT, "---> Cannot create a new file or openwrite a file.")
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
testFile.write("Qv2ray test file, feel free to remove.");
|
testFile.write("Qv2ray test file, feel free to remove.");
|
||||||
testFile.flush();
|
testFile.flush();
|
||||||
testFile.close();
|
testFile.close();
|
||||||
bool removed = testFile.remove();
|
bool removed = testFile.remove();
|
||||||
|
|
||||||
if (!removed) {
|
if (!removed)
|
||||||
|
{
|
||||||
// This is rare, as we can create a file but failed to remove it.
|
// 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_SETTINGS, "Directory at: " + path + " cannot be used as a valid config file path.")
|
||||||
LOG(MODULE_INIT, "---> Cannot remove a file.")
|
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.
|
// Check if an existing config is found.
|
||||||
QFile configFile(path + "Qv2ray.conf");
|
QFile configFile(path + "Qv2ray.conf");
|
||||||
|
|
||||||
@ -68,37 +72,52 @@ bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
|
|||||||
|
|
||||||
bool opened2 = configFile.open(QIODevice::ReadWrite);
|
bool opened2 = configFile.open(QIODevice::ReadWrite);
|
||||||
|
|
||||||
try {
|
try
|
||||||
if (opened2) {
|
{
|
||||||
|
if (opened2)
|
||||||
|
{
|
||||||
// Verify if the config can be loaded.
|
// Verify if the config can be loaded.
|
||||||
// Failed to parse if we changed the file structure...
|
// Failed to parse if we changed the file structure...
|
||||||
// Original:
|
// 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));
|
auto err = VerifyJsonString(StringFromFile(&configFile));
|
||||||
|
|
||||||
if (!err.isEmpty()) {
|
if (!err.isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_INIT, "Json parse returns: " + err)
|
LOG(MODULE_INIT, "Json parse returns: " + err)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// If the file format is valid.
|
// If the file format is valid.
|
||||||
auto conf = JsonFromString(StringFromFile(&configFile));
|
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();
|
configFile.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
LOG(MODULE_SETTINGS, "File: " + configFile.fileName() + " cannot be opened!")
|
else
|
||||||
|
{
|
||||||
|
LOG(MODULE_SETTINGS, "File: " + configFile.fileName() + " cannot be opened!")
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
LOG(MODULE_SETTINGS, "Exception raised when checking config: " + configFile.fileName())
|
LOG(MODULE_SETTINGS, "Exception raised when checking config: " + configFile.fileName())
|
||||||
//LOG(INIT, e->what())
|
// LOG(INIT, e->what())
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Warning"), QObject::tr("Qv2ray cannot load the config file from here:") + NEWLINE + configFile.fileName());
|
QvMessageBoxWarn(nullptr, QObject::tr("Warning"),
|
||||||
|
QObject::tr("Qv2ray cannot load the config file from here:") + NEWLINE + configFile.fileName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else return true;
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initialiseQv2ray()
|
bool initialiseQv2ray()
|
||||||
@ -109,12 +128,14 @@ bool initialiseQv2ray()
|
|||||||
const QString homeQv2ray = QDir::homePath() + "/.qv2ray" QV2RAY_CONFIG_DIR_SUFFIX;
|
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;
|
QStringList configFilePaths;
|
||||||
configFilePaths << currentPathConfig;
|
configFilePaths << currentPathConfig;
|
||||||
#ifdef WITH_FLATHUB_CONFIG_PATH
|
#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;
|
configFilePaths << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + QV2RAY_CONFIG_DIR_SUFFIX;
|
||||||
#endif
|
#endif
|
||||||
configFilePaths << configQv2ray;
|
configFilePaths << configQv2ray;
|
||||||
@ -123,31 +144,40 @@ bool initialiseQv2ray()
|
|||||||
QString configPath = "";
|
QString configPath = "";
|
||||||
bool hasExistingConfig = false;
|
bool hasExistingConfig = false;
|
||||||
|
|
||||||
for (auto path : configFilePaths) {
|
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 |
|
// 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);
|
bool isValidConfigPath = verifyConfigAvaliability(path, true);
|
||||||
|
|
||||||
// If we already found a valid config file. just simply load it...
|
// If we already found a valid config file. just simply load it...
|
||||||
if (hasExistingConfig) break;
|
if (hasExistingConfig) break;
|
||||||
|
|
||||||
if (isValidConfigPath) {
|
if (isValidConfigPath)
|
||||||
|
{
|
||||||
DEBUG(MODULE_INIT, "Path: " + path + " is valid.")
|
DEBUG(MODULE_INIT, "Path: " + path + " is valid.")
|
||||||
configPath = path;
|
configPath = path;
|
||||||
hasExistingConfig = true;
|
hasExistingConfig = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_INIT, "Path: " + path + " does not contain a valid config file.")
|
LOG(MODULE_INIT, "Path: " + path + " does not contain a valid config file.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no existing config.
|
// If there's no existing config.
|
||||||
if (hasExistingConfig) {
|
if (hasExistingConfig)
|
||||||
|
{
|
||||||
// Use the config path found by the checks above
|
// Use the config path found by the checks above
|
||||||
SetConfigDirPath(configPath);
|
SetConfigDirPath(configPath);
|
||||||
LOG(MODULE_INIT, "Using " + QV2RAY_CONFIG_DIR + " as the config path.")
|
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
|
#ifdef Q_OS_WIN
|
||||||
configPath = currentPathConfig;
|
configPath = currentPathConfig;
|
||||||
#else
|
#else
|
||||||
@ -156,23 +186,26 @@ bool initialiseQv2ray()
|
|||||||
bool mkpathResult = QDir().mkpath(configPath);
|
bool mkpathResult = QDir().mkpath(configPath);
|
||||||
|
|
||||||
// Check if the dirs are write-able
|
// Check if the dirs are write-able
|
||||||
if (mkpathResult && verifyConfigAvaliability(configPath, false)) {
|
if (mkpathResult && verifyConfigAvaliability(configPath, false))
|
||||||
// Found a valid config dir, with write permission, but assume no config is located in it.
|
{
|
||||||
|
// 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.")
|
LOG(MODULE_INIT, "Set " + configPath + " as the config path.")
|
||||||
SetConfigDirPath(configPath);
|
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.
|
// As we already tried to load config from every possible dir.
|
||||||
// This condition branch (!hasExistingConfig check) holds the fact that
|
// This condition branch (!hasExistingConfig check) holds the
|
||||||
// current config dir, should NOT contain any valid file (at least in the same name)
|
// fact that current config dir, should NOT contain any valid
|
||||||
// It usually means that QV2RAY_CONFIG_FILE here is corrupted, in JSON format.
|
// file (at least in the same name) It usually means that
|
||||||
// Otherwise Qv2ray would have loaded this config already instead of notifying to
|
// QV2RAY_CONFIG_FILE here is corrupted, in JSON format.
|
||||||
// create a new config in this folder.
|
// 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.")
|
LOG(MODULE_INIT, "This should not occur: Qv2ray config exists but failed to load.")
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Failed to initialise Qv2ray"),
|
QvMessageBoxWarn(nullptr, QObject::tr("Failed to initialise Qv2ray"),
|
||||||
QObject::tr("Failed to determine the location of config file.") + NEWLINE +
|
QObject::tr("Failed to determine the location of config file.") + NEWLINE +
|
||||||
QObject::tr("Qv2ray will now exit.") + NEWLINE +
|
QObject::tr("Qv2ray will now exit.") + NEWLINE + QObject::tr("Please report if you think it's a bug."));
|
||||||
QObject::tr("Please report if you think it's a bug."));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +217,9 @@ bool initialiseQv2ray()
|
|||||||
// Save initial config.
|
// Save initial config.
|
||||||
SaveGlobalConfig(conf);
|
SaveGlobalConfig(conf);
|
||||||
LOG(MODULE_INIT, "Created initial config file.")
|
LOG(MODULE_INIT, "Created initial config file.")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// None of the path above can be used as a dir for storing config.
|
// None of the path above can be used as a dir for storing config.
|
||||||
// Even the last folder failed to pass the check.
|
// Even the last folder failed to pass the check.
|
||||||
LOG(MODULE_INIT, "FATAL")
|
LOG(MODULE_INIT, "FATAL")
|
||||||
@ -192,14 +227,14 @@ bool initialiseQv2ray()
|
|||||||
QString searchPath = configFilePaths.join(NEWLINE);
|
QString searchPath = configFilePaths.join(NEWLINE);
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Cannot Start Qv2ray"),
|
QvMessageBoxWarn(nullptr, QObject::tr("Cannot Start Qv2ray"),
|
||||||
QObject::tr("Cannot find a place to store config files.") + NEWLINE +
|
QObject::tr("Cannot find a place to store config files.") + NEWLINE +
|
||||||
QObject::tr("Qv2ray has searched these paths below:") +
|
QObject::tr("Qv2ray has searched these paths below:") + NEWLINE + NEWLINE + searchPath + NEWLINE +
|
||||||
NEWLINE + NEWLINE + searchPath + NEWLINE +
|
QObject::tr("Qv2ray will now exit."));
|
||||||
QObject::tr("Qv2ray will now exit."));
|
|
||||||
return false;
|
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.
|
// The dir used to generate final config file, for V2ray interaction.
|
||||||
QDir().mkdir(QV2RAY_GENERATED_DIR);
|
QDir().mkdir(QV2RAY_GENERATED_DIR);
|
||||||
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
|
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
|
||||||
@ -208,7 +243,6 @@ bool initialiseQv2ray()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
@ -228,9 +262,9 @@ int main(int argc, char *argv[])
|
|||||||
QvCommandArgParser parser;
|
QvCommandArgParser parser;
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
|
|
||||||
switch (parser.ParseCommandLine(&errorMessage)) {
|
switch (parser.ParseCommandLine(&errorMessage))
|
||||||
case CommandLineOk:
|
{
|
||||||
break;
|
case CommandLineOk: break;
|
||||||
|
|
||||||
case CommandLineError:
|
case CommandLineError:
|
||||||
cout << errorMessage.toStdString() << endl;
|
cout << errorMessage.toStdString() << endl;
|
||||||
@ -243,16 +277,16 @@ int main(int argc, char *argv[])
|
|||||||
LOG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
|
LOG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case CommandLineHelpRequested:
|
case CommandLineHelpRequested: cout << parser.Parser()->helpText().toStdString() << endl; return 0;
|
||||||
cout << parser.Parser()->helpText().toStdString() << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
|
|
||||||
// Unix OS root user check.
|
// 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.
|
// Do not use getuid() here since it's installed as owned by the root,
|
||||||
if (!StartupOption.forceRunAsRootUser && geteuid() == 0) {
|
// 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("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!"))
|
LOG("ERROR", QObject::tr(" --> USE IT AT YOUR OWN RISK!"))
|
||||||
return 1;
|
return 1;
|
||||||
@ -263,9 +297,11 @@ int main(int argc, char *argv[])
|
|||||||
// finished: command line parsing
|
// finished: command line parsing
|
||||||
LOG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO)
|
LOG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO)
|
||||||
LOG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_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::setApplicationName("Qv2ray");
|
||||||
SingleApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
|
SingleApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
|
||||||
SingleApplication::setApplicationDisplayName("Qv2ray");
|
SingleApplication::setApplicationDisplayName("Qv2ray");
|
||||||
@ -275,7 +311,8 @@ int main(int argc, char *argv[])
|
|||||||
// ----------------------------> For debug build...
|
// ----------------------------> For debug build...
|
||||||
SingleApplication::setApplicationName("Qv2ray - DEBUG");
|
SingleApplication::setApplicationName("Qv2ray - DEBUG");
|
||||||
#endif
|
#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);
|
_qApp.setQuitOnLastWindowClosed(false);
|
||||||
// Early initialisation
|
// Early initialisation
|
||||||
//
|
//
|
||||||
@ -288,14 +325,11 @@ int main(int argc, char *argv[])
|
|||||||
bool _result_ = _qApp.installTranslator(Qv2rayTranslator.get());
|
bool _result_ = _qApp.installTranslator(Qv2rayTranslator.get());
|
||||||
LOG(MODULE_UI, "Installing a tranlator from OS: " + _lang + " -- " + (_result_ ? "OK" : "Failed"))
|
LOG(MODULE_UI, "Installing a tranlator from OS: " + _lang + " -- " + (_result_ ? "OK" : "Failed"))
|
||||||
//
|
//
|
||||||
LOG("LICENCE", NEWLINE "This program comes with ABSOLUTELY NO WARRANTY." NEWLINE
|
LOG("LICENCE", NEWLINE
|
||||||
"This is free software, and you are welcome to redistribute it" 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
|
"under certain conditions." NEWLINE NEWLINE "Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE 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
|
"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) 2020 dridk (@dridk): X2Struct (Apache)" NEWLINE "Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE
|
||||||
"Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE
|
|
||||||
"Copyright (c) 2020 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)" NEWLINE
|
"Copyright (c) 2020 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)" NEWLINE
|
||||||
"Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)" NEWLINE
|
"Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)" NEWLINE
|
||||||
"Copyright (c) 2016 Nikhil Marathe (@nikhilm): QHttpServer (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) 2019 TheWanderingCoel (@TheWanderingCoel): ShadowClash (launchatlogin) (GPLv3)" NEWLINE
|
||||||
"Copyright (c) 2020 Ram Pani (@DuckSoft): QvRPCBridge (WTFPL)" NEWLINE
|
"Copyright (c) 2020 Ram Pani (@DuckSoft): QvRPCBridge (WTFPL)" NEWLINE
|
||||||
"Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)" NEWLINE
|
"Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)" NEWLINE
|
||||||
"Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE
|
"Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE 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
|
#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
|
#endif
|
||||||
//
|
//
|
||||||
// Load the language translation list.
|
// Load the language translation list.
|
||||||
auto langs = GetFileList(QDir(":/translations"));
|
auto langs = GetFileList(QDir(":/translations"));
|
||||||
|
|
||||||
if (langs.empty()) {
|
if (langs.empty())
|
||||||
|
{
|
||||||
LOG(MODULE_INIT, "FAILED to find any translations. THIS IS A BUILD ERROR.")
|
LOG(MODULE_INIT, "FAILED to find any translations. THIS IS A BUILD ERROR.")
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Cannot load languages"), QObject::tr("Qv2ray will continue running, but you cannot change the UI language."));
|
QvMessageBoxWarn(nullptr, QObject::tr("Cannot load languages"),
|
||||||
} else {
|
QObject::tr("Qv2ray will continue running, but you cannot change the UI language."));
|
||||||
for (auto lang : langs) {
|
}
|
||||||
LOG(MODULE_INIT, "Found Translator: " + lang)
|
else
|
||||||
}
|
{
|
||||||
|
for (auto lang : langs) { LOG(MODULE_INIT, "Found Translator: " + lang) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Qv2ray Initialize, find possible config paths and verify them.
|
// Qv2ray Initialize, find possible config paths and verify them.
|
||||||
if (!initialiseQv2ray()) {
|
if (!initialiseQv2ray()) { return -1; }
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the config for upgrade, but do not parse it to the struct.
|
// Load the config for upgrade, but do not parse it to the struct.
|
||||||
auto conf = JsonFromString(StringFromFile(QV2RAY_CONFIG_FILE));
|
auto conf = JsonFromString(StringFromFile(QV2RAY_CONFIG_FILE));
|
||||||
auto confVersion = conf["config_version"].toVariant().toString().toInt();
|
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...
|
// Config version is larger than the current version...
|
||||||
// This is rare but it may happen....
|
// This is rare but it may happen....
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Qv2ray Cannot Continue"),
|
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("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("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("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE +
|
||||||
QObject::tr("Qv2ray will now exit."));
|
QObject::tr("Qv2ray will now exit."));
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confVersion < QV2RAY_CONFIG_VERSION) {
|
if (confVersion < QV2RAY_CONFIG_VERSION)
|
||||||
|
{
|
||||||
// That is, config file needs to be upgraded.
|
// That is, config file needs to be upgraded.
|
||||||
conf = Qv2ray::UpgradeConfig(confVersion, QV2RAY_CONFIG_VERSION, conf);
|
conf = Qv2ray::UpgradeConfig(confVersion, QV2RAY_CONFIG_VERSION, conf);
|
||||||
}
|
}
|
||||||
@ -356,7 +392,8 @@ int main(int argc, char *argv[])
|
|||||||
qApp->removeTranslator(Qv2rayTranslator.get());
|
qApp->removeTranslator(Qv2rayTranslator.get());
|
||||||
LOG(MODULE_INIT, "Removed system translations")
|
LOG(MODULE_INIT, "Removed system translations")
|
||||||
|
|
||||||
if (confObject.uiConfig.language.isEmpty()) {
|
if (confObject.uiConfig.language.isEmpty())
|
||||||
|
{
|
||||||
// Prevent empty.
|
// Prevent empty.
|
||||||
LOG(MODULE_UI, "Setting default UI language to en-US")
|
LOG(MODULE_UI, "Setting default UI language to en-US")
|
||||||
confObject.uiConfig.language = "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);
|
Qv2rayTranslator = std::move(QvTranslator(confObject.uiConfig.language).pTranslator);
|
||||||
|
|
||||||
if (qApp->installTranslator(Qv2rayTranslator.get())) {
|
if (qApp->installTranslator(Qv2rayTranslator.get()))
|
||||||
LOG(MODULE_INIT, "Successfully installed a translator for " + confObject.uiConfig.language)
|
{ LOG(MODULE_INIT, "Successfully installed a translator for " + confObject.uiConfig.language) }
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
// Do not translate these.....
|
// Do not translate these.....
|
||||||
// If a translator fails to load, pop up a message.
|
// If a translator fails to load, pop up a message.
|
||||||
QvMessageBoxWarn(
|
QvMessageBoxWarn(nullptr, "Translation Failed",
|
||||||
nullptr, "Translation Failed",
|
"Cannot load translation for " + confObject.uiConfig.language + ", English is now used." + NEWLINE + NEWLINE +
|
||||||
"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");
|
||||||
"Please go to Preferences Window to change language or open an Issue");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's save the config.
|
// Let's save the config.
|
||||||
@ -383,16 +420,16 @@ int main(int argc, char *argv[])
|
|||||||
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
|
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
|
||||||
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)
|
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)
|
||||||
|
|
||||||
if (!QSslSocket::supportsSsl()) {
|
if (!QSslSocket::supportsSsl())
|
||||||
|
{
|
||||||
LOG(MODULE_NETWORK, "Required OpenSSL version: " + osslReqVersion)
|
LOG(MODULE_NETWORK, "Required OpenSSL version: " + osslReqVersion)
|
||||||
LOG(MODULE_NETWORK, "OpenSSL library MISSING, Quitting.")
|
LOG(MODULE_NETWORK, "OpenSSL library MISSING, Quitting.")
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Dependency Missing"),
|
QvMessageBoxWarn(nullptr, QObject::tr("Dependency Missing"),
|
||||||
QObject::tr("Cannot find openssl libs") + NEWLINE +
|
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("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("If you are using an AppImage from Github Action, please report a bug.") + NEWLINE + NEWLINE +
|
||||||
QObject::tr("Technical Details") + NEWLINE +
|
QObject::tr("Technical Details") + NEWLINE + "OSsl.Rq.V=" + osslReqVersion + NEWLINE +
|
||||||
"OSsl.Rq.V=" + osslReqVersion + NEWLINE +
|
"OSsl.Cr.V=" + osslCurVersion);
|
||||||
"OSsl.Cr.V=" + osslCurVersion);
|
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +443,8 @@ int main(int argc, char *argv[])
|
|||||||
#ifdef QV2RAY_USE_BUILTIN_DARKTHEME
|
#ifdef QV2RAY_USE_BUILTIN_DARKTHEME
|
||||||
LOG(MODULE_UI, "Using built-in theme.")
|
LOG(MODULE_UI, "Using built-in theme.")
|
||||||
|
|
||||||
if (confObject.uiConfig.useDarkTheme) {
|
if (confObject.uiConfig.useDarkTheme)
|
||||||
|
{
|
||||||
LOG(MODULE_UI, " --> Using built-in dark theme.")
|
LOG(MODULE_UI, " --> Using built-in dark theme.")
|
||||||
// From https://forum.qt.io/topic/101391/windows-10-dark-theme/4
|
// From https://forum.qt.io/topic/101391/windows-10-dark-theme/4
|
||||||
_qApp.setStyle("Fusion");
|
_qApp.setStyle("Fusion");
|
||||||
@ -441,7 +479,8 @@ int main(int argc, char *argv[])
|
|||||||
QStringList themes = QStyleFactory::keys();
|
QStringList themes = QStyleFactory::keys();
|
||||||
//_qApp.setDesktopFileName("qv2ray.desktop");
|
//_qApp.setDesktopFileName("qv2ray.desktop");
|
||||||
|
|
||||||
if (themes.contains(confObject.uiConfig.theme)) {
|
if (themes.contains(confObject.uiConfig.theme))
|
||||||
|
{
|
||||||
_qApp.setStyle(confObject.uiConfig.theme);
|
_qApp.setStyle(confObject.uiConfig.theme);
|
||||||
LOG(MODULE_INIT + " " + MODULE_UI, "Setting Qv2ray UI themes: " + 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
|
#endif
|
||||||
#ifndef QT_DEBUG
|
#ifndef QT_DEBUG
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
//_qApp.setAttribute(Qt::AA_DontUseNativeMenuBar);
|
//_qApp.setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||||
// Initialise Connection Handler
|
// Initialise Connection Handler
|
||||||
@ -465,23 +505,19 @@ int main(int argc, char *argv[])
|
|||||||
// Handler for session logout, shutdown, etc.
|
// Handler for session logout, shutdown, etc.
|
||||||
// Will not block.
|
// Will not block.
|
||||||
QGuiApplication::setFallbackSessionManagementEnabled(false);
|
QGuiApplication::setFallbackSessionManagementEnabled(false);
|
||||||
QObject::connect(&_qApp, &QGuiApplication::commitDataRequest, []() {
|
QObject::connect(&_qApp, &QGuiApplication::commitDataRequest, []() { LOG(MODULE_INIT, "Quit triggered by session manager.") });
|
||||||
LOG(MODULE_INIT, "Quit triggered by session manager.")
|
|
||||||
});
|
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
signal(SIGUSR1, [](int) {
|
signal(SIGUSR1, [](int) { emit MainWindow::mwInstance->Connect(); });
|
||||||
emit MainWindow::mwInstance->Connect();
|
signal(SIGUSR2, [](int) { emit MainWindow::mwInstance->DisConnect(); });
|
||||||
});
|
|
||||||
signal(SIGUSR2, [](int) {
|
|
||||||
emit MainWindow::mwInstance->DisConnect();
|
|
||||||
});
|
|
||||||
#endif
|
#endif
|
||||||
auto rcode = _qApp.exec();
|
auto rcode = _qApp.exec();
|
||||||
delete ConnectionManager;
|
delete ConnectionManager;
|
||||||
LOG(MODULE_INIT, "Quitting normally")
|
LOG(MODULE_INIT, "Quitting normally")
|
||||||
return rcode;
|
return rcode;
|
||||||
#ifndef QT_DEBUG
|
#ifndef QT_DEBUG
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
QvMessageBoxWarn(nullptr, "ERROR", "There's something wrong happened and Qv2ray will quit now.");
|
QvMessageBoxWarn(nullptr, "ERROR", "There's something wrong happened and Qv2ray will quit now.");
|
||||||
LOG(MODULE_INIT, "EXCEPTION THROWN: " __FILE__)
|
LOG(MODULE_INIT, "EXCEPTION THROWN: " __FILE__)
|
||||||
return -99;
|
return -99;
|
||||||
|
@ -1,36 +1,45 @@
|
|||||||
#include "w_InboundEditor.hpp"
|
#include "w_InboundEditor.hpp"
|
||||||
#include "core/CoreUtils.hpp"
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
#include "core/CoreUtils.hpp"
|
||||||
#include "core/connection/ConnectionIO.hpp"
|
#include "core/connection/ConnectionIO.hpp"
|
||||||
|
|
||||||
static bool isLoading = false;
|
static bool isLoading = false;
|
||||||
#define CHECKLOADING if(isLoading) return;
|
#define CHECKLOADING \
|
||||||
|
if (isLoading) return;
|
||||||
|
|
||||||
InboundEditor::InboundEditor(INBOUND root, QWidget *parent) :
|
InboundEditor::InboundEditor(INBOUND root, QWidget *parent) : QDialog(parent), original(root)
|
||||||
QDialog(parent),
|
|
||||||
original(root)
|
|
||||||
{
|
{
|
||||||
QvMessageBusConnect(InboundEditor);
|
QvMessageBusConnect(InboundEditor);
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
this->root = root;
|
this->root = root;
|
||||||
auto inboundType = root["protocol"].toString();
|
auto inboundType = root["protocol"].toString();
|
||||||
allocate = root["allocate"].toObject();
|
allocate = root["allocate"].toObject();
|
||||||
sniffing = root["sniffing"].toObject();
|
sniffing = root["sniffing"].toObject();
|
||||||
|
|
||||||
if (inboundType == "http") {
|
if (inboundType == "http") { httpSettings = root["settings"].toObject(); }
|
||||||
httpSettings = root["settings"].toObject();
|
else if (inboundType == "socks")
|
||||||
} else if (inboundType == "socks") {
|
{
|
||||||
socksSettings = root["settings"].toObject();
|
socksSettings = root["settings"].toObject();
|
||||||
} else if (inboundType == "dokodemo-door") {
|
}
|
||||||
|
else if (inboundType == "dokodemo-door")
|
||||||
|
{
|
||||||
dokoSettings = root["settings"].toObject();
|
dokoSettings = root["settings"].toObject();
|
||||||
} else if (inboundType == "mtproto") {
|
}
|
||||||
|
else if (inboundType == "mtproto")
|
||||||
|
{
|
||||||
mtSettings = root["settings"].toObject();
|
mtSettings = root["settings"].toObject();
|
||||||
} else {
|
}
|
||||||
if (!root["protocol"].toString().isEmpty()) {
|
else
|
||||||
|
{
|
||||||
|
if (!root["protocol"].toString().isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Unsupported inbound type: " + inboundType)
|
LOG(MODULE_UI, "Unsupported inbound type: " + inboundType)
|
||||||
QvMessageBoxWarn(this, tr("Inbound type not supported"), tr("The inbound type is not supported by Qv2ray (yet). Please use JsonEditor to change the settings") + "\r\n" +
|
QvMessageBoxWarn(this, tr("Inbound type not supported"),
|
||||||
tr("Inbound: ") + inboundType);
|
tr("The inbound type is not supported by Qv2ray (yet). Please use JsonEditor to change the settings") + "\r\n" +
|
||||||
} else {
|
tr("Inbound: ") + inboundType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Creating new inbound config")
|
LOG(MODULE_UI, "Creating new inbound config")
|
||||||
root["protocol"] = inboundType = "http";
|
root["protocol"] = inboundType = "http";
|
||||||
}
|
}
|
||||||
@ -41,10 +50,9 @@ InboundEditor::InboundEditor(INBOUND root, QWidget *parent) :
|
|||||||
|
|
||||||
QvMessageBusSlotImpl(InboundEditor)
|
QvMessageBusSlotImpl(InboundEditor)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl\
|
{
|
||||||
MBHideDefaultImpl\
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl\
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,27 +67,28 @@ INBOUND InboundEditor::GenerateNewRoot()
|
|||||||
INBOUND _newRoot = root;
|
INBOUND _newRoot = root;
|
||||||
auto inboundType = root["protocol"].toString();
|
auto inboundType = root["protocol"].toString();
|
||||||
|
|
||||||
if (inboundType.isNull() || inboundType.isEmpty()) {
|
if (inboundType.isNull() || inboundType.isEmpty()) { inboundType = "http"; }
|
||||||
inboundType = "http";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inboundType == "http") {
|
if (inboundType == "http")
|
||||||
|
{
|
||||||
// Remove useless, misleading 'accounts' array.
|
// Remove useless, misleading 'accounts' array.
|
||||||
if (httpAccountListBox->count() == 0) {
|
if (httpAccountListBox->count() == 0) { httpSettings.remove("accounts"); }
|
||||||
httpSettings.remove("accounts");
|
|
||||||
}
|
|
||||||
|
|
||||||
_newRoot["settings"] = httpSettings;
|
_newRoot["settings"] = httpSettings;
|
||||||
} else if (inboundType == "socks") {
|
}
|
||||||
|
else if (inboundType == "socks")
|
||||||
|
{
|
||||||
// See above
|
// See above
|
||||||
if (socksAccountListBox->count() == 0) {
|
if (socksAccountListBox->count() == 0) { socksSettings.remove("accounts"); }
|
||||||
socksSettings.remove("accounts");
|
|
||||||
}
|
|
||||||
|
|
||||||
_newRoot["settings"] = socksSettings;
|
_newRoot["settings"] = socksSettings;
|
||||||
} else if (inboundType == "dokodemo-door") {
|
}
|
||||||
|
else if (inboundType == "dokodemo-door")
|
||||||
|
{
|
||||||
_newRoot["settings"] = dokoSettings;
|
_newRoot["settings"] = dokoSettings;
|
||||||
} else if (inboundType == "mtproto") {
|
}
|
||||||
|
else if (inboundType == "mtproto")
|
||||||
|
{
|
||||||
_newRoot["settings"] = mtSettings;
|
_newRoot["settings"] = mtSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +111,8 @@ void InboundEditor::LoadUIData()
|
|||||||
//
|
//
|
||||||
destOverrideList->setEnabled(sniffing["enabled"].toBool());
|
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() == "http") destOverrideList->item(0)->setCheckState(Qt::Checked);
|
||||||
|
|
||||||
if (item.toString().toLower() == "tls") destOverrideList->item(1)->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());
|
httpUserLevelSB->setValue(httpSettings["userLevel"].toInt());
|
||||||
httpAccountListBox->clear();
|
httpAccountListBox->clear();
|
||||||
|
|
||||||
for (auto user : httpSettings["accounts"].toArray()) {
|
for (auto user : httpSettings["accounts"].toArray())
|
||||||
httpAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString());
|
{ httpAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString()); }
|
||||||
}
|
|
||||||
|
|
||||||
// SOCKS
|
// SOCKS
|
||||||
socksAuthCombo->setCurrentText(socksSettings["auth"].toString());
|
socksAuthCombo->setCurrentText(socksSettings["auth"].toString());
|
||||||
@ -128,9 +137,8 @@ void InboundEditor::LoadUIData()
|
|||||||
socksUDPIPAddrTxt->setText(socksSettings["ip"].toString());
|
socksUDPIPAddrTxt->setText(socksSettings["ip"].toString());
|
||||||
socksUserLevelSB->setValue(socksSettings["userLevel"].toInt());
|
socksUserLevelSB->setValue(socksSettings["userLevel"].toInt());
|
||||||
|
|
||||||
for (auto user : socksSettings["accounts"].toArray()) {
|
for (auto user : socksSettings["accounts"].toArray())
|
||||||
socksAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString());
|
{ socksAccountListBox->addItem(user.toObject()["user"].toString() + ":" + user.toObject()["pass"].toString()); }
|
||||||
}
|
|
||||||
|
|
||||||
// Dokodemo-Door
|
// Dokodemo-Door
|
||||||
dokoFollowRedirectCB->setChecked(dokoSettings["followRedirect"].toBool());
|
dokoFollowRedirectCB->setChecked(dokoSettings["followRedirect"].toBool());
|
||||||
@ -190,15 +198,18 @@ void InboundEditor::on_httpRemoveUserBtn_clicked()
|
|||||||
{
|
{
|
||||||
CHECKLOADING
|
CHECKLOADING
|
||||||
|
|
||||||
if (httpAccountListBox->currentRow() != -1) {
|
if (httpAccountListBox->currentRow() != -1)
|
||||||
|
{
|
||||||
auto item = httpAccountListBox->currentItem();
|
auto item = httpAccountListBox->currentItem();
|
||||||
auto list = httpSettings["accounts"].toArray();
|
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 user = list[i].toObject();
|
||||||
auto entry = user["user"].toString() + ":" + user["pass"].toString();
|
auto entry = user["user"].toString() + ":" + user["pass"].toString();
|
||||||
|
|
||||||
if (entry == item->text().trimmed()) {
|
if (entry == item->text().trimmed())
|
||||||
|
{
|
||||||
list.removeAt(i);
|
list.removeAt(i);
|
||||||
httpSettings["accounts"] = list;
|
httpSettings["accounts"] = list;
|
||||||
LOG(MODULE_UI, "Removed http inbound user " + entry)
|
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?"));
|
// QvMessageBox(this, tr("Removing a user"), tr("No user has been
|
||||||
} else {
|
// removed. Why?"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Removing a user"), tr("You haven't selected a user yet."));
|
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();
|
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 _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."));
|
QvMessageBoxWarn(this, tr("Add a user"), tr("This user exists already."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -243,15 +259,18 @@ void InboundEditor::on_socksRemoveUserBtn_clicked()
|
|||||||
{
|
{
|
||||||
CHECKLOADING
|
CHECKLOADING
|
||||||
|
|
||||||
if (socksAccountListBox->currentRow() != -1) {
|
if (socksAccountListBox->currentRow() != -1)
|
||||||
|
{
|
||||||
auto item = socksAccountListBox->currentItem();
|
auto item = socksAccountListBox->currentItem();
|
||||||
auto list = socksSettings["accounts"].toArray();
|
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 user = list[i].toObject();
|
||||||
auto entry = user["user"].toString() + ":" + user["pass"].toString();
|
auto entry = user["user"].toString() + ":" + user["pass"].toString();
|
||||||
|
|
||||||
if (entry == item->text().trimmed()) {
|
if (entry == item->text().trimmed())
|
||||||
|
{
|
||||||
list.removeAt(i);
|
list.removeAt(i);
|
||||||
socksSettings["accounts"] = list;
|
socksSettings["accounts"] = list;
|
||||||
LOG(MODULE_UI, "Removed http inbound user " + entry)
|
LOG(MODULE_UI, "Removed http inbound user " + entry)
|
||||||
@ -259,7 +278,9 @@ void InboundEditor::on_socksRemoveUserBtn_clicked()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Removing a user"), tr("You haven't selected a user yet."));
|
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();
|
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 _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."));
|
QvMessageBoxWarn(this, tr("Add a user"), tr("This user exists already."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -322,12 +345,11 @@ void InboundEditor::on_destOverrideList_itemChanged(QListWidgetItem *item)
|
|||||||
Q_UNUSED(item)
|
Q_UNUSED(item)
|
||||||
QJsonArray list;
|
QJsonArray list;
|
||||||
|
|
||||||
for (int i = 0; i < destOverrideList->count(); i++) {
|
for (int i = 0; i < destOverrideList->count(); i++)
|
||||||
|
{
|
||||||
auto _item = destOverrideList->item(i);
|
auto _item = destOverrideList->item(i);
|
||||||
|
|
||||||
if (_item->checkState() == Qt::Checked) {
|
if (_item->checkState() == Qt::Checked) { list.append(_item->text().toLower()); }
|
||||||
list.append(_item->text().toLower());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sniffing["destOverride"] = list;
|
sniffing["destOverride"] = list;
|
||||||
@ -360,7 +382,7 @@ void InboundEditor::on_dokoIPAddrTxt_textEdited(const QString &arg1)
|
|||||||
void InboundEditor::on_dokoPortSB_valueChanged(int arg1)
|
void InboundEditor::on_dokoPortSB_valueChanged(int arg1)
|
||||||
{
|
{
|
||||||
CHECKLOADING
|
CHECKLOADING
|
||||||
dokoSettings["port"] = arg1;
|
dokoSettings["port"] = arg1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InboundEditor::on_dokoTCPCB_stateChanged(int 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)
|
void InboundEditor::on_socksAuthCombo_currentIndexChanged(const QString &arg1)
|
||||||
{
|
{
|
||||||
CHECKLOADING
|
CHECKLOADING
|
||||||
socksSettings["auth"] = arg1.toLower();
|
socksSettings["auth"] = arg1.toLower();
|
||||||
}
|
}
|
||||||
|
@ -1,97 +1,100 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
#include "ui/messaging/QvMessageBus.hpp"
|
||||||
|
#include "ui_w_InboundEditor.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QListWidgetItem>
|
#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:
|
public:
|
||||||
explicit InboundEditor(INBOUND root, QWidget *parent = nullptr);
|
explicit InboundEditor(INBOUND root, QWidget *parent = nullptr);
|
||||||
~InboundEditor();
|
~InboundEditor();
|
||||||
INBOUND OpenEditor();
|
INBOUND OpenEditor();
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_inboundProtocolCombo_currentIndexChanged(const QString &arg1);
|
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:
|
private:
|
||||||
INBOUND GenerateNewRoot();
|
INBOUND GenerateNewRoot();
|
||||||
void LoadUIData();
|
void LoadUIData();
|
||||||
INBOUND original;
|
INBOUND original;
|
||||||
INBOUND root;
|
INBOUND root;
|
||||||
//
|
//
|
||||||
QJsonObject httpSettings;
|
QJsonObject httpSettings;
|
||||||
QJsonObject socksSettings;
|
QJsonObject socksSettings;
|
||||||
QJsonObject mtSettings;
|
QJsonObject mtSettings;
|
||||||
QJsonObject dokoSettings;
|
QJsonObject dokoSettings;
|
||||||
//
|
//
|
||||||
QJsonObject sniffing;
|
QJsonObject sniffing;
|
||||||
QJsonObject allocate;
|
QJsonObject allocate;
|
||||||
};
|
};
|
||||||
|
@ -2,20 +2,22 @@
|
|||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
JsonEditor::JsonEditor(QJsonObject rootObject, QWidget *parent) :
|
JsonEditor::JsonEditor(QJsonObject rootObject, QWidget *parent) : QDialog(parent)
|
||||||
QDialog(parent)
|
|
||||||
{
|
{
|
||||||
QvMessageBusConnect(JsonEditor);
|
QvMessageBusConnect(JsonEditor);
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
original = rootObject;
|
original = rootObject;
|
||||||
final = 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")
|
LOG(MODULE_UI, "Begin loading Json Model")
|
||||||
jsonTree->setModel(&model);
|
jsonTree->setModel(&model);
|
||||||
model.loadJson(QJsonDocument(rootObject).toJson());
|
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."));
|
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)
|
QvMessageBusSlotImpl(JsonEditor)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +39,8 @@ QJsonObject JsonEditor::OpenEditor()
|
|||||||
int resultCode = this->exec();
|
int resultCode = this->exec();
|
||||||
auto string = jsonEditor->toPlainText();
|
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."));
|
QvMessageBoxWarn(this, tr("Json Contains Syntax Errors"), tr("You must correct these errors before continue."));
|
||||||
resultCode = this->exec();
|
resultCode = this->exec();
|
||||||
string = jsonEditor->toPlainText();
|
string = jsonEditor->toPlainText();
|
||||||
@ -57,13 +59,16 @@ void JsonEditor::on_jsonEditor_textChanged()
|
|||||||
auto VerifyResult = VerifyJsonString(string);
|
auto VerifyResult = VerifyJsonString(string);
|
||||||
jsonValidateStatus->setText(VerifyResult);
|
jsonValidateStatus->setText(VerifyResult);
|
||||||
|
|
||||||
if (VerifyResult.isEmpty()) {
|
if (VerifyResult.isEmpty())
|
||||||
|
{
|
||||||
BLACK(jsonEditor)
|
BLACK(jsonEditor)
|
||||||
final = JsonFromString(string);
|
final = JsonFromString(string);
|
||||||
model.loadJson(QJsonDocument(final).toJson());
|
model.loadJson(QJsonDocument(final).toJson());
|
||||||
jsonTree->expandAll();
|
jsonTree->expandAll();
|
||||||
jsonTree->resizeColumnToContents(0);
|
jsonTree->resizeColumnToContents(0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
RED(jsonEditor)
|
RED(jsonEditor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,10 +79,13 @@ void JsonEditor::on_formatJsonBtn_clicked()
|
|||||||
auto VerifyResult = VerifyJsonString(string);
|
auto VerifyResult = VerifyJsonString(string);
|
||||||
jsonValidateStatus->setText(VerifyResult);
|
jsonValidateStatus->setText(VerifyResult);
|
||||||
|
|
||||||
if (VerifyResult.isEmpty()) {
|
if (VerifyResult.isEmpty())
|
||||||
|
{
|
||||||
BLACK(jsonEditor)
|
BLACK(jsonEditor)
|
||||||
jsonEditor->setPlainText(JsonToString(JsonFromString(string)));
|
jsonEditor->setPlainText(JsonToString(JsonFromString(string)));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
RED(jsonEditor)
|
RED(jsonEditor)
|
||||||
QvMessageBoxWarn(this, tr("Syntax Errors"), tr("Please fix the JSON errors before continue"));
|
QvMessageBoxWarn(this, tr("Syntax Errors"), tr("Please fix the JSON errors before continue"));
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
#include "common/QJsonModel.hpp"
|
||||||
|
#include "ui/messaging/QvMessageBus.hpp"
|
||||||
|
#include "ui_w_JsonEditor.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QtCore>
|
#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:
|
public:
|
||||||
explicit JsonEditor(QJsonObject rootObject, QWidget *parent = nullptr);
|
explicit JsonEditor(QJsonObject rootObject, QWidget *parent = nullptr);
|
||||||
~JsonEditor();
|
~JsonEditor();
|
||||||
QJsonObject OpenEditor();
|
QJsonObject OpenEditor();
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_jsonEditor_textChanged();
|
void on_jsonEditor_textChanged();
|
||||||
|
|
||||||
void on_formatJsonBtn_clicked();
|
void on_formatJsonBtn_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QJsonModel model;
|
QJsonModel model;
|
||||||
QJsonObject original;
|
QJsonObject original;
|
||||||
QJsonObject final;
|
QJsonObject final;
|
||||||
};
|
};
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
#include <QDebug>
|
#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 <QFile>
|
||||||
#include <QIntValidator>
|
#include <QIntValidator>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "w_OutboundEditor.hpp"
|
OutboundEditor::OutboundEditor(QWidget *parent) : QDialog(parent), Tag(""), Mux(), vmess(), shadowsocks()
|
||||||
#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()
|
|
||||||
{
|
{
|
||||||
QvMessageBusConnect(OutboundEditor);
|
QvMessageBusConnect(OutboundEditor);
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
@ -40,10 +36,9 @@ OutboundEditor::OutboundEditor(QWidget *parent)
|
|||||||
|
|
||||||
QvMessageBusSlotImpl(OutboundEditor)
|
QvMessageBusSlotImpl(OutboundEditor)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,20 +52,28 @@ OutboundEditor::OutboundEditor(OUTBOUND outboundEntry, QWidget *parent) : Outbou
|
|||||||
useFProxy = outboundEntry[QV2RAY_USE_FPROXY_KEY].toBool(false);
|
useFProxy = outboundEntry[QV2RAY_USE_FPROXY_KEY].toBool(false);
|
||||||
ssWidget->SetStreamObject(StructFromJsonString<StreamSettingsObject>(JsonToString(outboundEntry["streamSettings"].toObject())));
|
ssWidget->SetStreamObject(StructFromJsonString<StreamSettingsObject>(JsonToString(outboundEntry["streamSettings"].toObject())));
|
||||||
|
|
||||||
if (OutboundType == "vmess") {
|
if (OutboundType == "vmess")
|
||||||
vmess = StructFromJsonString<VMessServerObject>(JsonToString(outboundEntry["settings"].toObject()["vnext"].toArray().first().toObject()));
|
{
|
||||||
|
vmess =
|
||||||
|
StructFromJsonString<VMessServerObject>(JsonToString(outboundEntry["settings"].toObject()["vnext"].toArray().first().toObject()));
|
||||||
shadowsocks.port = vmess.port;
|
shadowsocks.port = vmess.port;
|
||||||
shadowsocks.address = vmess.address;
|
shadowsocks.address = vmess.address;
|
||||||
socks.address = vmess.address;
|
socks.address = vmess.address;
|
||||||
socks.port = vmess.port;
|
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.address = shadowsocks.address;
|
||||||
vmess.port = shadowsocks.port;
|
vmess.port = shadowsocks.port;
|
||||||
socks.address = shadowsocks.address;
|
socks.address = shadowsocks.address;
|
||||||
socks.port = shadowsocks.port;
|
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.address = socks.address;
|
||||||
vmess.port = socks.port;
|
vmess.port = socks.port;
|
||||||
shadowsocks.address = socks.address;
|
shadowsocks.address = socks.address;
|
||||||
@ -81,7 +84,6 @@ OutboundEditor::OutboundEditor(OUTBOUND outboundEntry, QWidget *parent) : Outbou
|
|||||||
Result = GenerateConnectionJson();
|
Result = GenerateConnectionJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OutboundEditor::~OutboundEditor()
|
OutboundEditor::~OutboundEditor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -106,18 +108,23 @@ OUTBOUND OutboundEditor::GenerateConnectionJson()
|
|||||||
OUTBOUNDSETTING settings;
|
OUTBOUNDSETTING settings;
|
||||||
auto streaming = GetRootObject(ssWidget->GetStreamSettings());
|
auto streaming = GetRootObject(ssWidget->GetStreamSettings());
|
||||||
|
|
||||||
if (OutboundType == "vmess") {
|
if (OutboundType == "vmess")
|
||||||
|
{
|
||||||
// VMess is only a ServerObject, and we need an array { "vnext": [] }
|
// VMess is only a ServerObject, and we need an array { "vnext": [] }
|
||||||
QJsonArray vnext;
|
QJsonArray vnext;
|
||||||
vnext.append(GetRootObject(vmess));
|
vnext.append(GetRootObject(vmess));
|
||||||
settings.insert("vnext", vnext);
|
settings.insert("vnext", vnext);
|
||||||
} else if (OutboundType == "shadowsocks") {
|
}
|
||||||
|
else if (OutboundType == "shadowsocks")
|
||||||
|
{
|
||||||
streaming = QJsonObject();
|
streaming = QJsonObject();
|
||||||
LOG(MODULE_CONNECTION, "Shadowsocks outbound does not need StreamSettings.")
|
LOG(MODULE_CONNECTION, "Shadowsocks outbound does not need StreamSettings.")
|
||||||
QJsonArray servers;
|
QJsonArray servers;
|
||||||
servers.append(GetRootObject(shadowsocks));
|
servers.append(GetRootObject(shadowsocks));
|
||||||
settings["servers"] = servers;
|
settings["servers"] = servers;
|
||||||
} else if (OutboundType == "socks") {
|
}
|
||||||
|
else if (OutboundType == "socks")
|
||||||
|
{
|
||||||
streaming = QJsonObject();
|
streaming = QJsonObject();
|
||||||
LOG(MODULE_CONNECTION, "Socks outbound does not need StreamSettings.")
|
LOG(MODULE_CONNECTION, "Socks outbound does not need StreamSettings.")
|
||||||
QJsonArray servers;
|
QJsonArray servers;
|
||||||
@ -132,14 +139,17 @@ OUTBOUND OutboundEditor::GenerateConnectionJson()
|
|||||||
|
|
||||||
void OutboundEditor::ReloadGUI()
|
void OutboundEditor::ReloadGUI()
|
||||||
{
|
{
|
||||||
if (OutboundType == "vmess") {
|
if (OutboundType == "vmess")
|
||||||
|
{
|
||||||
outBoundTypeCombo->setCurrentIndex(0);
|
outBoundTypeCombo->setCurrentIndex(0);
|
||||||
ipLineEdit->setText(vmess.address);
|
ipLineEdit->setText(vmess.address);
|
||||||
portLineEdit->setText(QSTRN(vmess.port));
|
portLineEdit->setText(QSTRN(vmess.port));
|
||||||
idLineEdit->setText(vmess.users.front().id);
|
idLineEdit->setText(vmess.users.front().id);
|
||||||
alterLineEdit->setValue(vmess.users.front().alterId);
|
alterLineEdit->setValue(vmess.users.front().alterId);
|
||||||
securityCombo->setCurrentText(vmess.users.front().security);
|
securityCombo->setCurrentText(vmess.users.front().security);
|
||||||
} else if (OutboundType == "shadowsocks") {
|
}
|
||||||
|
else if (OutboundType == "shadowsocks")
|
||||||
|
{
|
||||||
outBoundTypeCombo->setCurrentIndex(1);
|
outBoundTypeCombo->setCurrentIndex(1);
|
||||||
// ShadowSocks Configs
|
// ShadowSocks Configs
|
||||||
ipLineEdit->setText(shadowsocks.address);
|
ipLineEdit->setText(shadowsocks.address);
|
||||||
@ -149,7 +159,9 @@ void OutboundEditor::ReloadGUI()
|
|||||||
ss_otaCheckBox->setChecked(shadowsocks.ota);
|
ss_otaCheckBox->setChecked(shadowsocks.ota);
|
||||||
ss_passwordTxt->setText(shadowsocks.password);
|
ss_passwordTxt->setText(shadowsocks.password);
|
||||||
ss_encryptionMethod->setCurrentText(shadowsocks.method);
|
ss_encryptionMethod->setCurrentText(shadowsocks.method);
|
||||||
} else if (OutboundType == "socks") {
|
}
|
||||||
|
else if (OutboundType == "socks")
|
||||||
|
{
|
||||||
outBoundTypeCombo->setCurrentIndex(2);
|
outBoundTypeCombo->setCurrentIndex(2);
|
||||||
ipLineEdit->setText(socks.address);
|
ipLineEdit->setText(socks.address);
|
||||||
portLineEdit->setText(QSTRN(socks.port));
|
portLineEdit->setText(QSTRN(socks.port));
|
||||||
@ -165,7 +177,6 @@ void OutboundEditor::ReloadGUI()
|
|||||||
muxConcurrencyTxt->setValue(Mux["concurrency"].toInt());
|
muxConcurrencyTxt->setValue(Mux["concurrency"].toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OutboundEditor::on_buttonBox_accepted()
|
void OutboundEditor::on_buttonBox_accepted()
|
||||||
{
|
{
|
||||||
Result = GenerateConnectionJson();
|
Result = GenerateConnectionJson();
|
||||||
@ -180,7 +191,8 @@ void OutboundEditor::on_ipLineEdit_textEdited(const QString &arg1)
|
|||||||
|
|
||||||
void OutboundEditor::on_portLineEdit_textEdited(const QString &arg1)
|
void OutboundEditor::on_portLineEdit_textEdited(const QString &arg1)
|
||||||
{
|
{
|
||||||
if (arg1 != "") {
|
if (arg1 != "")
|
||||||
|
{
|
||||||
vmess.port = arg1.toInt();
|
vmess.port = arg1.toInt();
|
||||||
shadowsocks.port = arg1.toInt();
|
shadowsocks.port = arg1.toInt();
|
||||||
socks.port = arg1.toInt();
|
socks.port = arg1.toInt();
|
||||||
|
@ -1,76 +1,79 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QtCore>
|
|
||||||
#include <QDialog>
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "ui_w_OutboundEditor.h"
|
|
||||||
#include "ui/widgets/StreamSettingsWidget.hpp"
|
|
||||||
#include "ui/messaging/QvMessageBus.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
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit OutboundEditor(QWidget *parent = nullptr);
|
explicit OutboundEditor(QWidget *parent = nullptr);
|
||||||
explicit OutboundEditor(OUTBOUND outboundEntry, QWidget *parent = nullptr);
|
explicit OutboundEditor(OUTBOUND outboundEntry, QWidget *parent = nullptr);
|
||||||
~OutboundEditor();
|
~OutboundEditor();
|
||||||
OUTBOUND OpenEditor();
|
OUTBOUND OpenEditor();
|
||||||
QString GetFriendlyName();
|
QString GetFriendlyName();
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
signals:
|
signals:
|
||||||
void s_reload_config(bool need_restart);
|
void s_reload_config(bool need_restart);
|
||||||
private slots:
|
private slots:
|
||||||
void on_buttonBox_accepted();
|
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:
|
private:
|
||||||
QString Tag;
|
QString Tag;
|
||||||
void ReloadGUI();
|
void ReloadGUI();
|
||||||
bool useFProxy;
|
bool useFProxy;
|
||||||
OUTBOUND GenerateConnectionJson();
|
OUTBOUND GenerateConnectionJson();
|
||||||
OUTBOUND Original;
|
OUTBOUND Original;
|
||||||
OUTBOUND Result;
|
OUTBOUND Result;
|
||||||
QJsonObject Mux;
|
QJsonObject Mux;
|
||||||
//
|
//
|
||||||
// Connection Configs
|
// Connection Configs
|
||||||
QString OutboundType;
|
QString OutboundType;
|
||||||
//
|
//
|
||||||
VMessServerObject vmess;
|
VMessServerObject vmess;
|
||||||
ShadowSocksServerObject shadowsocks;
|
ShadowSocksServerObject shadowsocks;
|
||||||
SocksServerObject socks;
|
SocksServerObject socks;
|
||||||
//
|
//
|
||||||
StreamSettingsWidget *ssWidget;
|
StreamSettingsWidget *ssWidget;
|
||||||
};
|
};
|
||||||
|
@ -1,36 +1,40 @@
|
|||||||
// WARNING
|
// WARNING
|
||||||
// Since it's required for *extra.cpp to know the content of those macros defined below.
|
// Since it's required for *extra.cpp to know the content of those macros
|
||||||
// We include this CPP file instead of the proper HPP file. Adding #pragma once to prevent duplicate function instances
|
// defined below. We include this CPP file instead of the proper HPP file.
|
||||||
|
// Adding #pragma once to prevent duplicate function instances
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "w_RoutesEditor.hpp"
|
#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 "FlowView.hpp"
|
||||||
#include "FlowViewStyle.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 QtNodes::FlowView;
|
||||||
using namespace Qv2ray::ui::nodemodels;
|
using namespace Qv2ray::ui::nodemodels;
|
||||||
|
|
||||||
static bool isLoading = false;
|
static bool isLoading = false;
|
||||||
#define CurrentRule this->rules[this->currentRuleTag]
|
#define CurrentRule this->rules[this->currentRuleTag]
|
||||||
#define LOADINGCHECK if(isLoading) return;
|
#define LOADINGCHECK \
|
||||||
#define GetFirstNodeData(node, nodeModel, dataModel) (static_cast<dataModel *>(static_cast<nodeModel *>((node).nodeDataModel())->outData(0).get()))
|
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()) { \
|
#define CHECKEMPTYRULES \
|
||||||
LOG(MODULE_UI, "No rules currently, we add one.") \
|
if (this->rules.isEmpty()) \
|
||||||
AddNewRule(); \
|
{ \
|
||||||
|
LOG(MODULE_UI, "No rules currently, we add one.") \
|
||||||
|
AddNewRule(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GRAPH_GLOBAL_OFFSET_X -80
|
#define GRAPH_GLOBAL_OFFSET_X -80
|
||||||
@ -41,18 +45,25 @@ static bool isLoading = false;
|
|||||||
|
|
||||||
void RouteEditor::SetupNodeWidget()
|
void RouteEditor::SetupNodeWidget()
|
||||||
{
|
{
|
||||||
if (GlobalConfig.uiConfig.useDarkTheme) {
|
if (GlobalConfig.uiConfig.useDarkTheme)
|
||||||
ConnectionStyle::setConnectionStyle(R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
|
{
|
||||||
|
ConnectionStyle::setConnectionStyle(
|
||||||
|
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
|
||||||
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,
|
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,
|
||||||
"ConstructionLineWidth": 2.0,"PointDiameter": 10.0,"UseDataDefinedColors": true}})");
|
"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",
|
"GradientColor0": "mintcream","GradientColor1": "mintcream","GradientColor2": "mintcream",
|
||||||
"GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10],
|
"GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10],
|
||||||
"FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5,
|
"FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5,
|
||||||
"ConnectionPointDiameter": 10.0,"Opacity": 1.0}})");
|
"ConnectionPointDiameter": 10.0,"Opacity": 1.0}})");
|
||||||
QtNodes::FlowViewStyle::setStyle(R"({"FlowViewStyle": {"BackgroundColor": [255, 255, 240],"FineGridColor": [245, 245, 230],"CoarseGridColor": [235, 235, 220]}})");
|
QtNodes::FlowViewStyle::setStyle(
|
||||||
ConnectionStyle::setConnectionStyle(R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
|
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,
|
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0,
|
||||||
"PointDiameter": 10.0,"UseDataDefinedColors": false}})");
|
"PointDiameter": 10.0,"UseDataDefinedColors": false}})");
|
||||||
}
|
}
|
||||||
@ -91,17 +102,20 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare
|
|||||||
domainStrategyCombo->setCurrentText(domainStrategy);
|
domainStrategyCombo->setCurrentText(domainStrategy);
|
||||||
|
|
||||||
// Show connections in the node graph
|
// Show connections in the node graph
|
||||||
for (auto in : root["inbounds"].toArray()) {
|
for (auto in : root["inbounds"].toArray())
|
||||||
|
{
|
||||||
INBOUND _in = INBOUND(in.toObject());
|
INBOUND _in = INBOUND(in.toObject());
|
||||||
AddInbound(_in);
|
AddInbound(_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto out : root["outbounds"].toArray()) {
|
for (auto out : root["outbounds"].toArray())
|
||||||
|
{
|
||||||
OUTBOUND _out = OUTBOUND(out.toObject());
|
OUTBOUND _out = OUTBOUND(out.toObject());
|
||||||
AddOutbound(_out);
|
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()));
|
auto _rule = StructFromJsonString<RuleObject>(JsonToString(item.toObject()));
|
||||||
AddRule(_rule);
|
AddRule(_rule);
|
||||||
}
|
}
|
||||||
@ -110,12 +124,12 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare
|
|||||||
defaultOutboundCombo->setCurrentText(root["outbounds"].toArray().first().toObject()["tag"].toString());
|
defaultOutboundCombo->setCurrentText(root["outbounds"].toArray().first().toObject()["tag"].toString());
|
||||||
|
|
||||||
// Find and add balancers.
|
// Find and add balancers.
|
||||||
for (auto _balancer : root["routing"].toObject()["balancers"].toArray()) {
|
for (auto _balancer : root["routing"].toObject()["balancers"].toArray())
|
||||||
|
{
|
||||||
auto _balancerObject = _balancer.toObject();
|
auto _balancerObject = _balancer.toObject();
|
||||||
|
|
||||||
if (!_balancerObject["tag"].toString().isEmpty()) {
|
if (!_balancerObject["tag"].toString().isEmpty())
|
||||||
balancers[_balancerObject["tag"].toString()] = _balancerObject["selector"].toVariant().toStringList();
|
{ balancers[_balancerObject["tag"].toString()] = _balancerObject["selector"].toVariant().toStringList(); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
@ -123,10 +137,9 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare
|
|||||||
|
|
||||||
QvMessageBusSlotImpl(RouteEditor)
|
QvMessageBusSlotImpl(RouteEditor)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,25 +153,31 @@ void RouteEditor::onNodeClicked(Node &n)
|
|||||||
auto isIn = inboundNodes.values().contains(&n);
|
auto isIn = inboundNodes.values().contains(&n);
|
||||||
auto isRule = ruleNodes.values().contains(&n);
|
auto isRule = ruleNodes.values().contains(&n);
|
||||||
|
|
||||||
if (isRule) {
|
if (isRule)
|
||||||
|
{
|
||||||
// It's a rule object
|
// It's a rule object
|
||||||
currentRuleTag = GetFirstNodeData(n, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
|
currentRuleTag = GetFirstNodeData(n, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
|
||||||
DEBUG(MODULE_GRAPH, "Selecting rule: " + currentRuleTag)
|
DEBUG(MODULE_GRAPH, "Selecting rule: " + currentRuleTag)
|
||||||
ShowCurrentRuleDetail();
|
ShowCurrentRuleDetail();
|
||||||
toolBox->setCurrentIndex(1);
|
toolBox->setCurrentIndex(1);
|
||||||
} else if (isOut || isIn) {
|
}
|
||||||
|
else if (isOut || isIn)
|
||||||
|
{
|
||||||
// It's an inbound or an outbound.
|
// It's an inbound or an outbound.
|
||||||
QString alias;
|
QString alias;
|
||||||
QString host;
|
QString host;
|
||||||
int port;
|
int port;
|
||||||
QString protocol;
|
QString protocol;
|
||||||
|
|
||||||
if (isOut) {
|
if (isOut)
|
||||||
|
{
|
||||||
alias = GetFirstNodeData(n, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
alias = GetFirstNodeData(n, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
||||||
QJsonObject _root = outbounds[alias].raw();
|
QJsonObject _root = outbounds[alias].raw();
|
||||||
throw new runtime_error("Not implemented");
|
throw new runtime_error("Not implemented");
|
||||||
GetOutboundData(OUTBOUND(_root), &host, &port, &protocol);
|
GetOutboundData(OUTBOUND(_root), &host, &port, &protocol);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
alias = GetFirstNodeData(n, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
alias = GetFirstNodeData(n, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
||||||
QJsonObject _root = inbounds[alias].raw();
|
QJsonObject _root = inbounds[alias].raw();
|
||||||
host = _root["listen"].toString();
|
host = _root["listen"].toString();
|
||||||
@ -170,7 +189,9 @@ void RouteEditor::onNodeClicked(Node &n)
|
|||||||
protocolLabel->setText(protocol);
|
protocolLabel->setText(protocol);
|
||||||
portLabel->setNum(port);
|
portLabel->setNum(port);
|
||||||
hostLabel->setText(host);
|
hostLabel->setText(host);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
|
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 sourceNode = c.getNode(PortType::Out);
|
||||||
auto const targetNode = c.getNode(PortType::In);
|
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
|
// It's a inbound-rule connection
|
||||||
onNodeClicked(*sourceNode);
|
onNodeClicked(*sourceNode);
|
||||||
onNodeClicked(*targetNode);
|
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 has an helper to let us remove duplicates, see below.
|
||||||
QStringList _inbounds;
|
QStringList _inbounds;
|
||||||
|
|
||||||
for (auto &&[_, conn] : nodeScene->connections()) {
|
for (auto &&[_, conn] : nodeScene->connections())
|
||||||
|
{
|
||||||
auto _connection = conn.get();
|
auto _connection = conn.get();
|
||||||
|
|
||||||
if (_connection->getNode(PortType::In) == targetNode && _connection->getNode(PortType::Out) == sourceNode && _connection->id() != c.id()) {
|
if (_connection->getNode(PortType::In) == targetNode && _connection->getNode(PortType::Out) == sourceNode &&
|
||||||
nodeScene->deleteConnection(*_connection);
|
_connection->id() != c.id())
|
||||||
}
|
{ nodeScene->deleteConnection(*_connection); }
|
||||||
// Append all inbounds
|
// 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());
|
_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
|
// caused by multi-in connection
|
||||||
_inbounds.removeDuplicates();
|
_inbounds.removeDuplicates();
|
||||||
CurrentRule.inboundTag = _inbounds;
|
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
|
// It's a rule-outbound connection
|
||||||
onNodeClicked(*sourceNode);
|
onNodeClicked(*sourceNode);
|
||||||
onNodeClicked(*targetNode);
|
onNodeClicked(*targetNode);
|
||||||
@ -219,7 +245,9 @@ void RouteEditor::onConnectionCreated(QtNodes::Connection const &c)
|
|||||||
// Update balancer settings.
|
// Update balancer settings.
|
||||||
ShowCurrentRuleDetail();
|
ShowCurrentRuleDetail();
|
||||||
LOG(MODULE_GRAPH, "Updated outbound: " + CurrentRule.outboundTag)
|
LOG(MODULE_GRAPH, "Updated outbound: " + CurrentRule.outboundTag)
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// It's an impossible connection
|
// It's an impossible connection
|
||||||
LOG(MODULE_GRAPH, "Unrecognized connection, RARE.")
|
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 source = c.getNode(PortType::Out);
|
||||||
auto const target = c.getNode(PortType::In);
|
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
|
// It's a inbound-rule connection
|
||||||
onNodeClicked(*source);
|
onNodeClicked(*source);
|
||||||
onNodeClicked(*target);
|
onNodeClicked(*target);
|
||||||
@ -243,19 +272,21 @@ void RouteEditor::onConnectionDeleted(QtNodes::Connection const &c)
|
|||||||
auto _inboundTag = GetFirstNodeData(*source, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
auto _inboundTag = GetFirstNodeData(*source, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
||||||
LOG(MODULE_UI, "Removing inbound: " + _inboundTag + " from rule: " + currentRuleTag)
|
LOG(MODULE_UI, "Removing inbound: " + _inboundTag + " from rule: " + currentRuleTag)
|
||||||
CurrentRule.inboundTag.removeAll(_inboundTag);
|
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
|
// It's a rule-outbound connection
|
||||||
onNodeClicked(*source);
|
onNodeClicked(*source);
|
||||||
onNodeClicked(*target);
|
onNodeClicked(*target);
|
||||||
currentRuleTag = GetFirstNodeData(*source, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
|
currentRuleTag = GetFirstNodeData(*source, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag();
|
||||||
auto _outboundTag = GetFirstNodeData(*target, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
auto _outboundTag = GetFirstNodeData(*target, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
||||||
|
|
||||||
if (!CurrentRule.QV2RAY_RULE_USE_BALANCER && CurrentRule.outboundTag == _outboundTag) {
|
if (!CurrentRule.QV2RAY_RULE_USE_BALANCER && CurrentRule.outboundTag == _outboundTag) { CurrentRule.outboundTag.clear(); }
|
||||||
CurrentRule.outboundTag.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(MODULE_GRAPH, "Removing an outbound: " + _outboundTag)
|
LOG(MODULE_GRAPH, "Removing an outbound: " + _outboundTag)
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// It's an impossible connection
|
// It's an impossible connection
|
||||||
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
|
LOG(MODULE_GRAPH, "Selected an unknown node, RARE.")
|
||||||
}
|
}
|
||||||
@ -265,30 +296,35 @@ CONFIGROOT RouteEditor::OpenEditor()
|
|||||||
{
|
{
|
||||||
auto result = this->exec();
|
auto result = this->exec();
|
||||||
|
|
||||||
if (rules.isEmpty()) {
|
if (rules.isEmpty())
|
||||||
// Prevent empty rule list causing mis-detection of config type to simple.
|
{
|
||||||
|
// Prevent empty rule list causing mis-detection of config type to
|
||||||
|
// simple.
|
||||||
on_addRouteBtn_clicked();
|
on_addRouteBtn_clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If clicking OK
|
// If clicking OK
|
||||||
if (result == QDialog::Accepted) {
|
if (result == QDialog::Accepted)
|
||||||
|
{
|
||||||
QJsonArray rulesArray;
|
QJsonArray rulesArray;
|
||||||
QJsonArray _balancers;
|
QJsonArray _balancers;
|
||||||
|
|
||||||
// Append rules by order
|
// 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 _rule = rules[ruleListWidget->item(i)->text()];
|
||||||
auto ruleJsonObject = GetRootObject(_rule);
|
auto ruleJsonObject = GetRootObject(_rule);
|
||||||
|
|
||||||
// Process balancer for a rule
|
// Process balancer for a rule
|
||||||
if (_rule.QV2RAY_RULE_USE_BALANCER) {
|
if (_rule.QV2RAY_RULE_USE_BALANCER)
|
||||||
|
{
|
||||||
// Do not use outbound tag.
|
// Do not use outbound tag.
|
||||||
ruleJsonObject.remove("outboundTag");
|
ruleJsonObject.remove("outboundTag");
|
||||||
|
|
||||||
// Find balancer list
|
// Find balancer list
|
||||||
if (!balancers.contains(_rule.balancerTag)) {
|
if (!balancers.contains(_rule.balancerTag)) { LOG(MODULE_UI, "Cannot find a balancer for tag: " + _rule.balancerTag) }
|
||||||
LOG(MODULE_UI, "Cannot find a balancer for tag: " + _rule.balancerTag)
|
else
|
||||||
} else {
|
{
|
||||||
auto _balancerList = balancers[_rule.balancerTag];
|
auto _balancerList = balancers[_rule.balancerTag];
|
||||||
QJsonObject balancerEntry;
|
QJsonObject balancerEntry;
|
||||||
balancerEntry["tag"] = _rule.balancerTag;
|
balancerEntry["tag"] = _rule.balancerTag;
|
||||||
@ -298,13 +334,9 @@ CONFIGROOT RouteEditor::OpenEditor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove some empty fields.
|
// Remove some empty fields.
|
||||||
if (_rule.port.isEmpty()) {
|
if (_rule.port.isEmpty()) { ruleJsonObject.remove("port"); }
|
||||||
ruleJsonObject.remove("port");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rule.network.isEmpty()) {
|
if (_rule.network.isEmpty()) { ruleJsonObject.remove("network"); }
|
||||||
ruleJsonObject.remove("network");
|
|
||||||
}
|
|
||||||
|
|
||||||
rulesArray.append(ruleJsonObject);
|
rulesArray.append(ruleJsonObject);
|
||||||
}
|
}
|
||||||
@ -318,22 +350,25 @@ CONFIGROOT RouteEditor::OpenEditor()
|
|||||||
QJsonArray _outbounds;
|
QJsonArray _outbounds;
|
||||||
|
|
||||||
// Convert our internal data format to QJsonArray
|
// Convert our internal data format to QJsonArray
|
||||||
for (auto x : inbounds) {
|
for (auto x : inbounds)
|
||||||
if (x.isEmpty())
|
{
|
||||||
continue;
|
if (x.isEmpty()) continue;
|
||||||
|
|
||||||
_inbounds.append(x.raw());
|
_inbounds.append(x.raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto x : outbounds) {
|
for (auto x : outbounds)
|
||||||
if (x.isEmpty())
|
{
|
||||||
continue;
|
if (x.isEmpty()) continue;
|
||||||
|
|
||||||
if (getTag(x) == defaultOutbound) {
|
if (getTag(x) == defaultOutbound)
|
||||||
|
{
|
||||||
LOG(MODULE_CONNECTION, "Pushing default outbound to the front.")
|
LOG(MODULE_CONNECTION, "Pushing default outbound to the front.")
|
||||||
// Put the default outbound to the first.
|
// Put the default outbound to the first.
|
||||||
_outbounds.push_front(x.raw());
|
_outbounds.push_front(x.raw());
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_outbounds.push_back(x.raw());
|
_outbounds.push_back(x.raw());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,7 +377,9 @@ CONFIGROOT RouteEditor::OpenEditor()
|
|||||||
root["outbounds"] = _outbounds;
|
root["outbounds"] = _outbounds;
|
||||||
root["routing"] = routing;
|
root["routing"] = routing;
|
||||||
return root;
|
return root;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,18 +392,22 @@ RouteEditor::~RouteEditor()
|
|||||||
disconnect(nodeScene, &FlowScene::connectionCreated, this, &RouteEditor::onConnectionCreated);
|
disconnect(nodeScene, &FlowScene::connectionCreated, this, &RouteEditor::onConnectionCreated);
|
||||||
disconnect(nodeScene, &FlowScene::nodeClicked, this, &RouteEditor::onNodeClicked);
|
disconnect(nodeScene, &FlowScene::nodeClicked, this, &RouteEditor::onNodeClicked);
|
||||||
}
|
}
|
||||||
void RouteEditor::on_buttonBox_accepted() {}
|
void RouteEditor::on_buttonBox_accepted()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void RouteEditor::ShowCurrentRuleDetail()
|
void RouteEditor::ShowCurrentRuleDetail()
|
||||||
{
|
{
|
||||||
LOADINGCHECK
|
LOADINGCHECK
|
||||||
|
|
||||||
if (currentRuleTag.isEmpty()) {
|
if (currentRuleTag.isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
|
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rules.contains(currentRuleTag)) {
|
if (!rules.contains(currentRuleTag))
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Show rule details"), tr("A rule cannot be found: ") + 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.")
|
LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.")
|
||||||
return;
|
return;
|
||||||
@ -384,16 +425,15 @@ void RouteEditor::ShowCurrentRuleDetail()
|
|||||||
balancerSelectionCombo->clear();
|
balancerSelectionCombo->clear();
|
||||||
|
|
||||||
// BUG added the wrong items, should be outbound list.
|
// BUG added the wrong items, should be outbound list.
|
||||||
for (auto out : outbounds) {
|
for (auto out : outbounds) { balancerSelectionCombo->addItem((out)["tag"].toString()); }
|
||||||
balancerSelectionCombo->addItem((out)["tag"].toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Balancers combo and balancer list.
|
// Balancers combo and balancer list.
|
||||||
enableBalancerCB->setChecked(CurrentRule.QV2RAY_RULE_USE_BALANCER);
|
enableBalancerCB->setChecked(CurrentRule.QV2RAY_RULE_USE_BALANCER);
|
||||||
balancersWidget->setEnabled(CurrentRule.QV2RAY_RULE_USE_BALANCER);
|
balancersWidget->setEnabled(CurrentRule.QV2RAY_RULE_USE_BALANCER);
|
||||||
|
|
||||||
if (!CurrentRule.balancerTag.isEmpty()) {
|
if (!CurrentRule.balancerTag.isEmpty())
|
||||||
|
{
|
||||||
balancerList->clear();
|
balancerList->clear();
|
||||||
balancerList->addItems(balancers[CurrentRule.balancerTag]);
|
balancerList->addItems(balancers[CurrentRule.balancerTag]);
|
||||||
}
|
}
|
||||||
@ -490,12 +530,15 @@ void RouteEditor::on_balancerAddBtn_clicked()
|
|||||||
LOADINGCHECK
|
LOADINGCHECK
|
||||||
auto balancerTx = balancerSelectionCombo->currentText();
|
auto balancerTx = balancerSelectionCombo->currentText();
|
||||||
|
|
||||||
if (!balancerTx.isEmpty()) {
|
if (!balancerTx.isEmpty())
|
||||||
|
{
|
||||||
this->balancers[CurrentRule.balancerTag].append(balancerSelectionCombo->currentText());
|
this->balancers[CurrentRule.balancerTag].append(balancerSelectionCombo->currentText());
|
||||||
balancerList->addItem(balancerTx);
|
balancerList->addItem(balancerTx);
|
||||||
balancerSelectionCombo->setEditText("");
|
balancerSelectionCombo->setEditText("");
|
||||||
statusLabel->setText(tr("OK"));
|
statusLabel->setText(tr("OK"));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
statusLabel->setText(tr("Balancer is empty, not processing."));
|
statusLabel->setText(tr("Balancer is empty, not processing."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,9 +546,7 @@ void RouteEditor::on_balancerDelBtn_clicked()
|
|||||||
{
|
{
|
||||||
LOADINGCHECK
|
LOADINGCHECK
|
||||||
|
|
||||||
if (balancerList->currentRow() < 0) {
|
if (balancerList->currentRow() < 0) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
balancers[CurrentRule.balancerTag].removeAt(balancerList->currentRow());
|
balancers[CurrentRule.balancerTag].removeAt(balancerList->currentRow());
|
||||||
balancerList->takeItem(balancerList->currentRow());
|
balancerList->takeItem(balancerList->currentRow());
|
||||||
@ -568,7 +609,8 @@ void RouteEditor::on_enableBalancerCB_stateChanged(int arg1)
|
|||||||
CurrentRule.QV2RAY_RULE_USE_BALANCER = useBalancer;
|
CurrentRule.QV2RAY_RULE_USE_BALANCER = useBalancer;
|
||||||
balancersWidget->setEnabled(useBalancer);
|
balancersWidget->setEnabled(useBalancer);
|
||||||
|
|
||||||
if (CurrentRule.balancerTag.isEmpty()) {
|
if (CurrentRule.balancerTag.isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Creating a new balancer tag.")
|
LOG(MODULE_UI, "Creating a new balancer tag.")
|
||||||
CurrentRule.balancerTag = GenerateRandomString(6);
|
CurrentRule.balancerTag = GenerateRandomString(6);
|
||||||
balancers[CurrentRule.balancerTag] = QStringList();
|
balancers[CurrentRule.balancerTag] = QStringList();
|
||||||
@ -576,16 +618,18 @@ void RouteEditor::on_enableBalancerCB_stateChanged(int arg1)
|
|||||||
|
|
||||||
DEBUG(MODULE_UI, "Balancer: " + CurrentRule.balancerTag)
|
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.")
|
LOG(MODULE_UI, "A rule has been set to use balancer, disconnect it to any outbound.")
|
||||||
auto ruleNode = ruleNodes[currentRuleTag];
|
auto ruleNode = ruleNodes[currentRuleTag];
|
||||||
|
|
||||||
for (auto &&[_, conn] : nodeScene->connections()) {
|
for (auto &&[_, conn] : nodeScene->connections())
|
||||||
if (conn.get()->getNode(PortType::Out) == ruleNode) {
|
{
|
||||||
nodeScene->deleteConnection(*conn);
|
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."));
|
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 _Inconfig = GlobalConfig.inboundConfig;
|
||||||
//
|
//
|
||||||
auto _in_httpConf = GenerateHTTPIN(QList<AccountObject>() << _Inconfig.httpAccount);
|
auto _in_httpConf = GenerateHTTPIN(QList<AccountObject>() << _Inconfig.httpAccount);
|
||||||
auto _in_socksConf = GenerateSocksIN((_Inconfig.socks_useAuth ? "password" : "noauth"),
|
auto _in_socksConf = GenerateSocksIN((_Inconfig.socks_useAuth ? "password" : "noauth"), QList<AccountObject>() << _Inconfig.socksAccount,
|
||||||
QList<AccountObject>() << _Inconfig.socksAccount,
|
|
||||||
_Inconfig.socksUDP, _Inconfig.socksLocalIP);
|
_Inconfig.socksUDP, _Inconfig.socksLocalIP);
|
||||||
//
|
//
|
||||||
auto _in_HTTP = GenerateInboundEntry(_Inconfig.listenip, _Inconfig.http_port, "http", _in_httpConf, "HTTP_gConf");
|
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);
|
InboundEditor w(INBOUND(), this);
|
||||||
auto _result = w.OpenEditor();
|
auto _result = w.OpenEditor();
|
||||||
|
|
||||||
if (w.result() == QDialog::Accepted) {
|
if (w.result() == QDialog::Accepted) { AddInbound(_result); }
|
||||||
AddInbound(_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECKEMPTYRULES
|
CHECKEMPTYRULES
|
||||||
}
|
}
|
||||||
@ -635,19 +676,17 @@ void RouteEditor::on_addOutboundBtn_clicked()
|
|||||||
// True here for not keep the inbounds.
|
// True here for not keep the inbounds.
|
||||||
auto configs = w.OpenImport(true);
|
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 conf = configs.values()[i];
|
||||||
auto name = configs.key(conf, "");
|
auto name = configs.key(conf, "");
|
||||||
|
|
||||||
if (name.isEmpty())
|
if (name.isEmpty()) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
// conf is rootObject, needs to unwrap it.
|
// conf is rootObject, needs to unwrap it.
|
||||||
auto confList = conf["outbounds"].toArray();
|
auto confList = conf["outbounds"].toArray();
|
||||||
|
|
||||||
for (int i = 0; i < confList.count(); i++) {
|
for (int i = 0; i < confList.count(); i++) { AddOutbound(OUTBOUND(confList[i].toObject())); }
|
||||||
AddOutbound(OUTBOUND(confList[i].toObject()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECKEMPTYRULES
|
CHECKEMPTYRULES
|
||||||
@ -661,7 +700,8 @@ void RouteEditor::on_ruleEnableCB_stateChanged(int arg1)
|
|||||||
}
|
}
|
||||||
void RouteEditor::on_delBtn_clicked()
|
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."));
|
QvMessageBoxWarn(this, tr("Remove Items"), tr("Please select a node from the graph to continue."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -671,40 +711,46 @@ void RouteEditor::on_delBtn_clicked()
|
|||||||
auto isOutbound = outboundNodes.values().contains(firstNode);
|
auto isOutbound = outboundNodes.values().contains(firstNode);
|
||||||
auto isRule = ruleNodes.values().contains(firstNode);
|
auto isRule = ruleNodes.values().contains(firstNode);
|
||||||
|
|
||||||
// Get the tag first, and call inbounds/outbounds/rules container variable remove()
|
// Get the tag first, and call inbounds/outbounds/rules container variable
|
||||||
// Remove the node last since some events may trigger.
|
// remove() Remove the node last since some events may trigger. Then remove
|
||||||
// Then remove the node container.
|
// the node container.
|
||||||
if (isInbound) {
|
if (isInbound)
|
||||||
|
{
|
||||||
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
||||||
nodeScene->removeNode(*inboundNodes[currentInboundOutboundTag]);
|
nodeScene->removeNode(*inboundNodes[currentInboundOutboundTag]);
|
||||||
inboundNodes.remove(currentInboundOutboundTag);
|
inboundNodes.remove(currentInboundOutboundTag);
|
||||||
|
|
||||||
// Remove corresponded inbound tags from the rules.
|
// Remove corresponded inbound tags from the rules.
|
||||||
for (auto k : rules.keys()) {
|
for (auto k : rules.keys())
|
||||||
|
{
|
||||||
auto v = rules[k];
|
auto v = rules[k];
|
||||||
v.inboundTag.removeAll(currentInboundOutboundTag);
|
v.inboundTag.removeAll(currentInboundOutboundTag);
|
||||||
rules[k] = v;
|
rules[k] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
inbounds.remove(currentInboundOutboundTag);
|
inbounds.remove(currentInboundOutboundTag);
|
||||||
} else if (isOutbound) {
|
}
|
||||||
|
else if (isOutbound)
|
||||||
|
{
|
||||||
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
||||||
outbounds.remove(currentInboundOutboundTag);
|
outbounds.remove(currentInboundOutboundTag);
|
||||||
ResolveDefaultOutboundTag(currentInboundOutboundTag, "");
|
ResolveDefaultOutboundTag(currentInboundOutboundTag, "");
|
||||||
|
|
||||||
// Remove corresponded outbound tags from the rules.
|
// Remove corresponded outbound tags from the rules.
|
||||||
for (auto k : rules.keys()) {
|
for (auto k : rules.keys())
|
||||||
|
{
|
||||||
auto v = rules[k];
|
auto v = rules[k];
|
||||||
|
|
||||||
if (v.outboundTag == currentInboundOutboundTag)
|
if (v.outboundTag == currentInboundOutboundTag) v.outboundTag.clear();
|
||||||
v.outboundTag.clear();
|
|
||||||
|
|
||||||
rules[k] = v;
|
rules[k] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeScene->removeNode(*outboundNodes[currentInboundOutboundTag]);
|
nodeScene->removeNode(*outboundNodes[currentInboundOutboundTag]);
|
||||||
outboundNodes.remove(currentInboundOutboundTag);
|
outboundNodes.remove(currentInboundOutboundTag);
|
||||||
} else if (isRule) {
|
}
|
||||||
|
else if (isRule)
|
||||||
|
{
|
||||||
ruleEnableCB->setEnabled(false);
|
ruleEnableCB->setEnabled(false);
|
||||||
ruleTagLineEdit->setEnabled(false);
|
ruleTagLineEdit->setEnabled(false);
|
||||||
ruleRenameBtn->setEnabled(false);
|
ruleRenameBtn->setEnabled(false);
|
||||||
@ -719,27 +765,30 @@ void RouteEditor::on_delBtn_clicked()
|
|||||||
// Remove item from the rule order list widget.
|
// Remove item from the rule order list widget.
|
||||||
ruleListWidget->takeItem(ruleListWidget->row(ruleListWidget->findItems(RuleTag, Qt::MatchExactly).first()));
|
ruleListWidget->takeItem(ruleListWidget->row(ruleListWidget->findItems(RuleTag, Qt::MatchExactly).first()));
|
||||||
CHECKEMPTYRULES
|
CHECKEMPTYRULES
|
||||||
//currentRuleTag = rules.firstKey();
|
// currentRuleTag = rules.firstKey();
|
||||||
//ShowCurrentRuleDetail();
|
// ShowCurrentRuleDetail();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Unknown node selected.")
|
LOG(MODULE_UI, "Unknown node selected.")
|
||||||
QvMessageBoxWarn(this, tr("Error"), tr("Qv2ray entered an unknown state."));
|
QvMessageBoxWarn(this, tr("Error"), tr("Qv2ray entered an unknown state."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void RouteEditor::on_editBtn_clicked()
|
void RouteEditor::on_editBtn_clicked()
|
||||||
{
|
{
|
||||||
if (nodeScene->selectedNodes().empty()) {
|
if (nodeScene->selectedNodes().empty())
|
||||||
QvMessageBoxWarn(this, tr("Edit Inbound/Outbound"), tr("Please select a node from the graph to continue."));
|
{ QvMessageBoxWarn(this, tr("Edit Inbound/Outbound"), tr("Please select a node from the graph to continue.")); }
|
||||||
}
|
|
||||||
|
|
||||||
auto firstNode = nodeScene->selectedNodes().at(0);
|
auto firstNode = nodeScene->selectedNodes().at(0);
|
||||||
auto isInbound = inboundNodes.values().contains(firstNode);
|
auto isInbound = inboundNodes.values().contains(firstNode);
|
||||||
auto isOutbound = outboundNodes.values().contains(firstNode);
|
auto isOutbound = outboundNodes.values().contains(firstNode);
|
||||||
|
|
||||||
if (isInbound) {
|
if (isInbound)
|
||||||
|
{
|
||||||
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
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);
|
QvMessageBoxWarn(this, tr("Edit Inbound"), tr("No inbound tag found: ") + currentInboundOutboundTag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -749,14 +798,18 @@ void RouteEditor::on_editBtn_clicked()
|
|||||||
auto protocol = _in["protocol"].toString();
|
auto protocol = _in["protocol"].toString();
|
||||||
int _code;
|
int _code;
|
||||||
|
|
||||||
if (protocol != "http" && protocol != "mtproto" && protocol != "socks" && protocol != "dokodemo-door") {
|
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."));
|
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"));
|
statusLabel->setText(tr("Opening JSON editor"));
|
||||||
JsonEditor w(_in, this);
|
JsonEditor w(_in, this);
|
||||||
_result = INBOUND(w.OpenEditor());
|
_result = INBOUND(w.OpenEditor());
|
||||||
_code = w.result();
|
_code = w.result();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
InboundEditor w(_in, this);
|
InboundEditor w(_in, this);
|
||||||
statusLabel->setText(tr("Opening default inbound editor"));
|
statusLabel->setText(tr("Opening default inbound editor"));
|
||||||
_result = w.OpenEditor();
|
_result = w.OpenEditor();
|
||||||
@ -765,22 +818,24 @@ void RouteEditor::on_editBtn_clicked()
|
|||||||
|
|
||||||
statusLabel->setText(tr("OK"));
|
statusLabel->setText(tr("OK"));
|
||||||
|
|
||||||
if (_code == QDialog::Accepted) {
|
if (_code == QDialog::Accepted)
|
||||||
|
{
|
||||||
bool isTagChanged = getTag(_in) != getTag(_result);
|
bool isTagChanged = getTag(_in) != getTag(_result);
|
||||||
|
|
||||||
if (isTagChanged) {
|
if (isTagChanged) { RenameItemTag(RENAME_INBOUND, getTag(_in), getTag(_result)); }
|
||||||
RenameItemTag(RENAME_INBOUND, getTag(_in), getTag(_result));
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_in))
|
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_in))
|
||||||
inbounds.remove(getTag(_in));
|
inbounds.remove(getTag(_in));
|
||||||
DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result))
|
DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result))
|
||||||
inbounds[getTag(_result)] = _result;
|
inbounds[getTag(_result)] = _result;
|
||||||
}
|
}
|
||||||
} else if (isOutbound) {
|
}
|
||||||
|
else if (isOutbound)
|
||||||
|
{
|
||||||
currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
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);
|
QvMessageBoxWarn(this, tr("Edit Inbound"), tr("No inbound tag found: ") + currentInboundOutboundTag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -790,25 +845,30 @@ void RouteEditor::on_editBtn_clicked()
|
|||||||
auto protocol = _out["protocol"].toString().toLower();
|
auto protocol = _out["protocol"].toString().toLower();
|
||||||
int _code;
|
int _code;
|
||||||
|
|
||||||
if (protocol != "vmess" && protocol != "shadowsocks" && protocol != "socks") {
|
if (protocol != "vmess" && protocol != "shadowsocks" && protocol != "socks")
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Unsupported Outbound Type"),
|
QvMessageBoxWarn(this, tr("Unsupported Outbound Type"),
|
||||||
tr("This outbound entry is not supported by the GUI editor.") + NEWLINE +
|
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);
|
JsonEditor w(_out, this);
|
||||||
statusLabel->setText(tr("Opening JSON editor"));
|
statusLabel->setText(tr("Opening JSON editor"));
|
||||||
_result = OUTBOUND(w.OpenEditor());
|
_result = OUTBOUND(w.OpenEditor());
|
||||||
_code = w.result();
|
_code = w.result();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
OutboundEditor w(_out, this);
|
OutboundEditor w(_out, this);
|
||||||
statusLabel->setText(tr("Opening default outbound editor."));
|
statusLabel->setText(tr("Opening default outbound editor."));
|
||||||
_result = w.OpenEditor();
|
_result = w.OpenEditor();
|
||||||
_code = w.result();
|
_code = w.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_code == QDialog::Accepted) {
|
if (_code == QDialog::Accepted)
|
||||||
|
{
|
||||||
bool isTagChanged = getTag(_out) != getTag(_result);
|
bool isTagChanged = getTag(_out) != getTag(_result);
|
||||||
|
|
||||||
if (isTagChanged) {
|
if (isTagChanged)
|
||||||
|
{
|
||||||
DEBUG(MODULE_UI, "Outbound tag is changed: " + QString(isTagChanged))
|
DEBUG(MODULE_UI, "Outbound tag is changed: " + QString(isTagChanged))
|
||||||
RenameItemTag(RENAME_OUTBOUND, getTag(_out), getTag(_result));
|
RenameItemTag(RENAME_OUTBOUND, getTag(_out), getTag(_result));
|
||||||
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_out))
|
DEBUG(MODULE_UI, "Removed old tag: " + getTag(_out))
|
||||||
@ -819,7 +879,9 @@ void RouteEditor::on_editBtn_clicked()
|
|||||||
outbounds[getTag(_result)] = _result;
|
outbounds[getTag(_result)] = _result;
|
||||||
statusLabel->setText(tr("OK"));
|
statusLabel->setText(tr("OK"));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Cannot apply 'edit' operation to non-inbound and non-outbound")
|
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();
|
auto newTag = ruleTagLineEdit->text();
|
||||||
|
|
||||||
if (newTag.isEmpty()) {
|
if (newTag.isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Tag is empty, this is ILLEGAL!")
|
LOG(MODULE_UI, "Tag is empty, this is ILLEGAL!")
|
||||||
QvMessageBoxWarn(this, tr("Renaming a tag"), tr("New tag is empty, please try another."));
|
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.")
|
LOG(MODULE_UI, "No tag changed, returning.")
|
||||||
QvMessageBoxInfo(this, tr("Renaming a tag"), tr("New tag is the same as the original one."));
|
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.")
|
LOG(MODULE_UI, "Tag duplicate detected.")
|
||||||
QvMessageBoxWarn(this, tr("Renaming a tag"), tr("Duplicate rule tag detected, please try another."));
|
QvMessageBoxWarn(this, tr("Renaming a tag"), tr("Duplicate rule tag detected, please try another."));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
RenameItemTag(RENAME_RULE, CurrentRule.QV2RAY_RULE_TAG, newTag);
|
RenameItemTag(RENAME_RULE, CurrentRule.QV2RAY_RULE_TAG, newTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,131 +1,134 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <list>
|
#include "ConnectionStyle.hpp"
|
||||||
|
#include "FlowScene.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
#include "NodeData.hpp"
|
||||||
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QListWidgetItem>
|
#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::ConnectionStyle;
|
||||||
|
using QtNodes::FlowScene;
|
||||||
|
using QtNodes::Node;
|
||||||
|
|
||||||
#include "ui_w_RoutesEditor.h"
|
|
||||||
#include "ui/messaging/QvMessageBus.hpp"
|
#include "ui/messaging/QvMessageBus.hpp"
|
||||||
|
#include "ui_w_RoutesEditor.h"
|
||||||
|
|
||||||
enum ROUTE_EDIT_MODE {
|
enum ROUTE_EDIT_MODE
|
||||||
|
{
|
||||||
RENAME_INBOUND,
|
RENAME_INBOUND,
|
||||||
RENAME_OUTBOUND,
|
RENAME_OUTBOUND,
|
||||||
RENAME_RULE,
|
RENAME_RULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
class RouteEditor : public QDialog, private Ui::RouteEditor
|
class RouteEditor
|
||||||
|
: public QDialog
|
||||||
|
, private Ui::RouteEditor
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RouteEditor(QJsonObject connection, QWidget *parent = nullptr);
|
explicit RouteEditor(QJsonObject connection, QWidget *parent = nullptr);
|
||||||
~RouteEditor();
|
~RouteEditor();
|
||||||
CONFIGROOT OpenEditor();
|
CONFIGROOT OpenEditor();
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_buttonBox_accepted();
|
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:
|
public slots:
|
||||||
void onNodeClicked(QtNodes::Node &n);
|
void onNodeClicked(QtNodes::Node &n);
|
||||||
void onConnectionCreated(QtNodes::Connection const &c);
|
void onConnectionCreated(QtNodes::Connection const &c);
|
||||||
void onConnectionDeleted(QtNodes::Connection const &c);
|
void onConnectionDeleted(QtNodes::Connection const &c);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, const QString newTag);
|
void RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, const QString newTag);
|
||||||
void ShowCurrentRuleDetail();
|
void ShowCurrentRuleDetail();
|
||||||
//
|
//
|
||||||
QString currentRuleTag;
|
QString currentRuleTag;
|
||||||
QString currentInboundOutboundTag;
|
QString currentInboundOutboundTag;
|
||||||
QMap<QString, QStringList> balancers;
|
QMap<QString, QStringList> balancers;
|
||||||
QString domainStrategy;
|
QString domainStrategy;
|
||||||
QString defaultOutbound;
|
QString defaultOutbound;
|
||||||
//
|
//
|
||||||
QMap<QString, INBOUND> inbounds;
|
QMap<QString, INBOUND> inbounds;
|
||||||
QMap<QString, OUTBOUND> outbounds;
|
QMap<QString, OUTBOUND> outbounds;
|
||||||
QMap<QString, RuleObject> rules;
|
QMap<QString, RuleObject> rules;
|
||||||
//
|
//
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
CONFIGROOT original;
|
CONFIGROOT original;
|
||||||
//
|
//
|
||||||
// ---------------------------- Node Graph Impl --------------------------
|
// ---------------------------- Node Graph Impl --------------------------
|
||||||
void SetupNodeWidget();
|
void SetupNodeWidget();
|
||||||
QMap<QString, Node *> inboundNodes;
|
QMap<QString, Node *> inboundNodes;
|
||||||
QMap<QString, Node *> outboundNodes;
|
QMap<QString, Node *> outboundNodes;
|
||||||
QMap<QString, Node *> ruleNodes;
|
QMap<QString, Node *> ruleNodes;
|
||||||
//
|
//
|
||||||
FlowScene *nodeScene;
|
FlowScene *nodeScene;
|
||||||
// ---------------------------- Extra Source File Headers ----------------
|
// ---------------------------- Extra Source File Headers ----------------
|
||||||
void AddInbound(INBOUND in);
|
void AddInbound(INBOUND in);
|
||||||
void AddOutbound(OUTBOUND out);
|
void AddOutbound(OUTBOUND out);
|
||||||
void AddRule(RuleObject rule);
|
void AddRule(RuleObject rule);
|
||||||
QString AddNewRule();
|
QString AddNewRule();
|
||||||
void ResolveDefaultOutboundTag(QString original, QString newTag);
|
void ResolveDefaultOutboundTag(QString original, QString newTag);
|
||||||
};
|
};
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
// WARNING
|
// WARNING
|
||||||
// Since it's required for this file to know the content of the macros defined in another CPP file.
|
// Since it's required for this file to know the content of the macros defined
|
||||||
// We included an CPP file instead of the proper HPP file.
|
// in another CPP file. We included an CPP file instead of the proper HPP file.
|
||||||
#include "w_RoutesEditor.cpp"
|
#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)
|
void RouteEditor::AddInbound(INBOUND in)
|
||||||
{
|
{
|
||||||
QString tag = getTag(in);
|
QString tag = getTag(in);
|
||||||
|
|
||||||
if (inbounds.contains(tag)) {
|
if (inbounds.contains(tag)) { tag = tag + "_" + GenerateRandomString(5); }
|
||||||
tag = tag + "_" + GenerateRandomString(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
in["tag"] = tag;
|
in["tag"] = tag;
|
||||||
auto _nodeData = make_unique<QvInboundNodeModel>(make_shared<InboundNodeData>(tag));
|
auto _nodeData = make_unique<QvInboundNodeModel>(make_shared<InboundNodeData>(tag));
|
||||||
@ -29,9 +27,7 @@ void RouteEditor::AddOutbound(OUTBOUND out)
|
|||||||
{
|
{
|
||||||
QString tag = getTag(out);
|
QString tag = getTag(out);
|
||||||
|
|
||||||
if (outbounds.contains(tag)) {
|
if (outbounds.contains(tag)) { tag = tag + "_" + GenerateRandomString(5); }
|
||||||
tag = tag + "_" + GenerateRandomString(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
out["tag"] = tag;
|
out["tag"] = tag;
|
||||||
auto _nodeData = make_unique<QvOutboundNodeModel>(make_shared<OutboundNodeData>(tag));
|
auto _nodeData = make_unique<QvOutboundNodeModel>(make_shared<OutboundNodeData>(tag));
|
||||||
@ -64,9 +60,7 @@ QString RouteEditor::AddNewRule()
|
|||||||
void RouteEditor::AddRule(RuleObject rule)
|
void RouteEditor::AddRule(RuleObject rule)
|
||||||
{
|
{
|
||||||
// Prevent duplicate
|
// Prevent duplicate
|
||||||
if (ruleNodes.contains(rule.QV2RAY_RULE_TAG)) {
|
if (ruleNodes.contains(rule.QV2RAY_RULE_TAG)) { rule.QV2RAY_RULE_TAG += "-" + GenerateRandomString(5); }
|
||||||
rule.QV2RAY_RULE_TAG += "-" + GenerateRandomString(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
rules[rule.QV2RAY_RULE_TAG] = rule;
|
rules[rule.QV2RAY_RULE_TAG] = rule;
|
||||||
auto pos = nodeGraphWidget->pos();
|
auto pos = nodeGraphWidget->pos();
|
||||||
@ -76,25 +70,34 @@ void RouteEditor::AddRule(RuleObject rule)
|
|||||||
auto &node = nodeScene->createNode(std::move(_nodeData));
|
auto &node = nodeScene->createNode(std::move(_nodeData));
|
||||||
nodeScene->setNodePosition(node, pos);
|
nodeScene->setNodePosition(node, pos);
|
||||||
|
|
||||||
for (auto inTag : rule.inboundTag) {
|
for (auto inTag : rule.inboundTag)
|
||||||
if (!inboundNodes.contains(inTag)) {
|
{
|
||||||
|
if (!inboundNodes.contains(inTag))
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "No inbound tag found for rule: " + rule.QV2RAY_RULE_TAG + ", inbound tag: " + inTag)
|
LOG(MODULE_UI, "No inbound tag found for rule: " + rule.QV2RAY_RULE_TAG + ", inbound tag: " + inTag)
|
||||||
QvMessageBoxWarn(this, tr("No Inbound"), tr("No inbound item found: ") + inTag);
|
QvMessageBoxWarn(this, tr("No Inbound"), tr("No inbound item found: ") + inTag);
|
||||||
rule.inboundTag.removeAll(inTag);
|
rule.inboundTag.removeAll(inTag);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
auto inboundNode = inboundNodes[inTag];
|
auto inboundNode = inboundNodes[inTag];
|
||||||
nodeScene->createConnection(node, 0, *inboundNode, 0);
|
nodeScene->createConnection(node, 0, *inboundNode, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not using balancers (use outbound tag)
|
// If not using balancers (use outbound tag)
|
||||||
if (!rule.QV2RAY_RULE_USE_BALANCER) {
|
if (!rule.QV2RAY_RULE_USE_BALANCER)
|
||||||
if (outboundNodes.contains(rule.outboundTag)) {
|
{
|
||||||
|
if (outboundNodes.contains(rule.outboundTag))
|
||||||
|
{
|
||||||
DEBUG(MODULE_GRAPH, "Found outbound tag: " + rule.outboundTag + ", for rule: " + rule.QV2RAY_RULE_TAG)
|
DEBUG(MODULE_GRAPH, "Found outbound tag: " + rule.outboundTag + ", for rule: " + rule.QV2RAY_RULE_TAG)
|
||||||
nodeScene->createConnection(*outboundNodes[rule.outboundTag], 0, node, 0);
|
nodeScene->createConnection(*outboundNodes[rule.outboundTag], 0, node, 0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_GRAPH, "Outbound tag not found: " + rule.outboundTag + ", for: " + rule.QV2RAY_RULE_TAG)
|
LOG(MODULE_GRAPH, "Outbound tag not found: " + rule.outboundTag + ", for: " + rule.QV2RAY_RULE_TAG)
|
||||||
//QvMessageBoxWarn(this, tr("No outbound tag"), tr("Please connect the rule with an outbound."));
|
// 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
|
// Do not use reference here, we need deep
|
||||||
void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, QString newTag)
|
void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, QString newTag)
|
||||||
{
|
{
|
||||||
switch (mode) {
|
switch (mode)
|
||||||
|
{
|
||||||
case RENAME_RULE:
|
case RENAME_RULE:
|
||||||
if (rules.contains(originalTag) && ruleNodes.contains(originalTag)) {
|
if (rules.contains(originalTag) && ruleNodes.contains(originalTag))
|
||||||
if (rules.contains(newTag) && rules.contains(newTag)) {
|
{
|
||||||
|
if (rules.contains(newTag) && rules.contains(newTag))
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
|
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
|
||||||
newTag += "_" + GenerateRandomString(5);
|
newTag += "_" + GenerateRandomString(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node = static_cast<QvRuleNodeDataModel *>(ruleNodes[originalTag]->nodeDataModel());
|
auto node = static_cast<QvRuleNodeDataModel *>(ruleNodes[originalTag]->nodeDataModel());
|
||||||
|
|
||||||
if (node == nullptr) {
|
if (node == nullptr) { LOG(MODULE_GRAPH, "EMPTY NODE WARN") }
|
||||||
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
|
|
||||||
}
|
|
||||||
|
|
||||||
node->setData(newTag);
|
node->setData(newTag);
|
||||||
//
|
//
|
||||||
@ -125,27 +129,30 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
|
|||||||
rules[newTag].QV2RAY_RULE_TAG = newTag;
|
rules[newTag].QV2RAY_RULE_TAG = newTag;
|
||||||
ruleNodes[newTag] = ruleNodes.take(originalTag);
|
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);
|
auto items = ruleListWidget->findItems(originalTag, Qt::MatchExactly);
|
||||||
|
|
||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) { LOG(MODULE_UI, "Cannot find a node: " + originalTag) }
|
||||||
LOG(MODULE_UI, "Cannot find a node: " + originalTag)
|
else
|
||||||
} else {
|
{
|
||||||
items.first()->setText(newTag);
|
items.first()->setText(newTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentRuleTag == originalTag) {
|
if (currentRuleTag == originalTag) { currentRuleTag = newTag; }
|
||||||
currentRuleTag = newTag;
|
}
|
||||||
}
|
else
|
||||||
} else {
|
{
|
||||||
LOG(MODULE_UI, "There's nothing match " + originalTag + " in the containers.")
|
LOG(MODULE_UI, "There's nothing match " + originalTag + " in the containers.")
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RENAME_OUTBOUND:
|
case RENAME_OUTBOUND:
|
||||||
if (outbounds.contains(originalTag) && outboundNodes.contains(originalTag)) {
|
if (outbounds.contains(originalTag) && outboundNodes.contains(originalTag))
|
||||||
if (outbounds.contains(newTag) && outboundNodes.contains(newTag)) {
|
{
|
||||||
|
if (outbounds.contains(newTag) && outboundNodes.contains(newTag))
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
|
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
|
||||||
newTag += "_" + GenerateRandomString(5);
|
newTag += "_" + GenerateRandomString(5);
|
||||||
}
|
}
|
||||||
@ -154,34 +161,39 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
|
|||||||
outboundNodes[newTag] = outboundNodes.take(originalTag);
|
outboundNodes[newTag] = outboundNodes.take(originalTag);
|
||||||
auto node = static_cast<QvOutboundNodeModel *>(outboundNodes[newTag]->nodeDataModel());
|
auto node = static_cast<QvOutboundNodeModel *>(outboundNodes[newTag]->nodeDataModel());
|
||||||
|
|
||||||
if (node == nullptr) {
|
if (node == nullptr) { LOG(MODULE_GRAPH, "EMPTY NODE WARN") }
|
||||||
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
|
|
||||||
}
|
|
||||||
|
|
||||||
node->setData(newTag);
|
node->setData(newTag);
|
||||||
|
|
||||||
// Change outbound tag in rules accordingly.
|
// Change outbound tag in rules accordingly.
|
||||||
for (auto k : rules.keys()) {
|
for (auto k : rules.keys())
|
||||||
|
{
|
||||||
auto v = rules[k];
|
auto v = rules[k];
|
||||||
|
|
||||||
if (v.outboundTag == originalTag) {
|
if (v.outboundTag == originalTag)
|
||||||
|
{
|
||||||
v.outboundTag = newTag;
|
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;
|
rules[k] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve default outbound.
|
// Resolve default outbound.
|
||||||
ResolveDefaultOutboundTag(originalTag, newTag);
|
ResolveDefaultOutboundTag(originalTag, newTag);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
|
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RENAME_INBOUND:
|
case RENAME_INBOUND:
|
||||||
if (inbounds.contains(originalTag) && inboundNodes.contains(originalTag)) {
|
if (inbounds.contains(originalTag) && inboundNodes.contains(originalTag))
|
||||||
if (inbounds.contains(newTag) && inboundNodes.contains(newTag)) {
|
{
|
||||||
|
if (inbounds.contains(newTag) && inboundNodes.contains(newTag))
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
|
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
|
||||||
newTag += "_" + GenerateRandomString(5);
|
newTag += "_" + GenerateRandomString(5);
|
||||||
}
|
}
|
||||||
@ -190,26 +202,29 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag,
|
|||||||
inboundNodes[newTag] = inboundNodes.take(originalTag);
|
inboundNodes[newTag] = inboundNodes.take(originalTag);
|
||||||
auto node = static_cast<QvInboundNodeModel *>(inboundNodes[newTag]->nodeDataModel());
|
auto node = static_cast<QvInboundNodeModel *>(inboundNodes[newTag]->nodeDataModel());
|
||||||
|
|
||||||
if (node == nullptr) {
|
if (node == nullptr) { LOG(MODULE_GRAPH, "EMPTY NODE WARN") }
|
||||||
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
|
|
||||||
}
|
|
||||||
|
|
||||||
node->setData(newTag);
|
node->setData(newTag);
|
||||||
|
|
||||||
// Change inbound tag in rules accordingly.
|
// Change inbound tag in rules accordingly.
|
||||||
// k -> rule tag
|
// k -> rule tag
|
||||||
// v -> rule object
|
// v -> rule object
|
||||||
for (auto k : rules.keys()) {
|
for (auto k : rules.keys())
|
||||||
|
{
|
||||||
auto v = rules[k];
|
auto v = rules[k];
|
||||||
|
|
||||||
if (v.inboundTag.contains(originalTag)) {
|
if (v.inboundTag.contains(originalTag))
|
||||||
|
{
|
||||||
v.inboundTag.append(newTag);
|
v.inboundTag.append(newTag);
|
||||||
v.inboundTag.removeAll(originalTag);
|
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;
|
rules[k] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
|
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)
|
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;
|
auto isDefaultChanged = original == defaultOutbound;
|
||||||
defaultOutboundCombo->clear();
|
defaultOutboundCombo->clear();
|
||||||
defaultOutboundCombo->addItems(outbounds.keys());
|
defaultOutboundCombo->addItems(outbounds.keys());
|
||||||
|
|
||||||
if (!isDefaultChanged) {
|
if (!isDefaultChanged)
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Default outbound is not changed: retaining: " + defaultOutbound)
|
LOG(MODULE_UI, "Default outbound is not changed: retaining: " + defaultOutbound)
|
||||||
// Just simply restore the default one.
|
// Just simply restore the default one.
|
||||||
defaultOutboundCombo->setCurrentText(defaultOutbound);
|
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.")
|
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.
|
// Removed the default one, so set the first one as the default.
|
||||||
if (outbounds.isEmpty()) {
|
if (outbounds.isEmpty()) { defaultOutbound.clear(); }
|
||||||
defaultOutbound.clear();
|
else
|
||||||
} else {
|
{
|
||||||
defaultOutbound = getTag(outbounds.first());
|
defaultOutbound = getTag(outbounds.first());
|
||||||
defaultOutboundCombo->addItem(outbounds.firstKey());
|
defaultOutboundCombo->addItem(outbounds.firstKey());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Default outbound is renamed, ")
|
LOG(MODULE_UI, "Default outbound is renamed, ")
|
||||||
defaultOutboundCombo->setCurrentText(newTag);
|
defaultOutboundCombo->setCurrentText(newTag);
|
||||||
defaultOutbound = newTag;
|
defaultOutbound = newTag;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include <QMetaEnum>
|
|
||||||
|
|
||||||
#include "QvMessageBus.hpp"
|
#include "QvMessageBus.hpp"
|
||||||
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
|
||||||
|
#include <QMetaEnum>
|
||||||
|
|
||||||
namespace Qv2ray::ui::messaging
|
namespace Qv2ray::ui::messaging
|
||||||
{
|
{
|
||||||
QvMessageBusObject::QvMessageBusObject()
|
QvMessageBusObject::QvMessageBusObject()
|
||||||
@ -15,4 +16,4 @@ namespace Qv2ray::ui::messaging
|
|||||||
LOG(MODULE_MESSAGING, "Emitting signal: " + QString(metaEnum.valueToKey(msg)));
|
LOG(MODULE_MESSAGING, "Emitting signal: " + QString(metaEnum.valueToKey(msg)));
|
||||||
emit QvSendMessage(msg);
|
emit QvSendMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
} // namespace Qv2ray::ui::messaging
|
||||||
|
@ -6,28 +6,27 @@
|
|||||||
#define QvMessageBusSlotSig const QvMBMessage &msg
|
#define QvMessageBusSlotSig const QvMBMessage &msg
|
||||||
#define QvMessageBusSlotIdentifier on_QvMessageReceived
|
#define QvMessageBusSlotIdentifier on_QvMessageReceived
|
||||||
|
|
||||||
#define QvMessageBusSlotDecl void QvMessageBusSlotIdentifier(QvMessageBusSlotSig);
|
#define QvMessageBusSlotDecl void QvMessageBusSlotIdentifier(QvMessageBusSlotSig)
|
||||||
#define QvMessageBusSlotImpl(CLASSNAME) void CLASSNAME::QvMessageBusSlotIdentifier(QvMessageBusSlotSig)
|
#define QvMessageBusSlotImpl(CLASSNAME) void CLASSNAME::QvMessageBusSlotIdentifier(QvMessageBusSlotSig)
|
||||||
|
|
||||||
#define MBShowDefaultImpl \
|
#define MBShowDefaultImpl \
|
||||||
case SHOW_WINDOWS:\
|
case SHOW_WINDOWS: \
|
||||||
this->setWindowOpacity(1);\
|
this->setWindowOpacity(1); \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#define MBHideDefaultImpl \
|
#define MBHideDefaultImpl \
|
||||||
case HIDE_WINDOWS:\
|
case HIDE_WINDOWS: \
|
||||||
this->setWindowOpacity(0);\
|
this->setWindowOpacity(0); \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#define MBRetranslateDefaultImpl \
|
#define MBRetranslateDefaultImpl \
|
||||||
case RETRANSLATE:\
|
case RETRANSLATE: this->retranslateUi(this); break;
|
||||||
this->retranslateUi(this);\
|
|
||||||
break;
|
|
||||||
|
|
||||||
namespace Qv2ray::ui::messaging
|
namespace Qv2ray::ui::messaging
|
||||||
{
|
{
|
||||||
Q_NAMESPACE
|
Q_NAMESPACE
|
||||||
enum QvMBMessage {
|
enum QvMBMessage
|
||||||
|
{
|
||||||
/// Show all windows.
|
/// Show all windows.
|
||||||
SHOW_WINDOWS,
|
SHOW_WINDOWS,
|
||||||
/// Hide all windows.
|
/// Hide all windows.
|
||||||
@ -43,20 +42,20 @@ namespace Qv2ray::ui::messaging
|
|||||||
//
|
//
|
||||||
class QvMessageBusObject : public QObject
|
class QvMessageBusObject : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QvMessageBusObject();
|
explicit QvMessageBusObject();
|
||||||
|
|
||||||
//
|
//
|
||||||
void EmitGlobalSignal(const QvMBMessage &msg);
|
void EmitGlobalSignal(const QvMBMessage &msg);
|
||||||
signals:
|
signals:
|
||||||
void QvSendMessage(const QvMBMessage &msg);
|
void QvSendMessage(const QvMBMessage &msg);
|
||||||
//private slots:
|
// private slots:
|
||||||
// void on_QvMessageReceived(QvMessage msg);
|
// void on_QvMessageReceived(QvMessage msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Danger, new is used here. Possible memory leak (hope not so much leak)
|
// Danger, new is used here. Possible memory leak (hope not so much leak)
|
||||||
inline QvMessageBusObject messageBus = QvMessageBusObject();
|
inline QvMessageBusObject messageBus = QvMessageBusObject();
|
||||||
}
|
} // namespace Qv2ray::ui::messaging
|
||||||
|
|
||||||
using namespace Qv2ray::ui::messaging;
|
using namespace Qv2ray::ui::messaging;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "ui/models/InboundNodeModel.hpp"
|
#include "ui/models/InboundNodeModel.hpp"
|
||||||
|
|
||||||
QvInboundNodeModel::QvInboundNodeModel(std::shared_ptr<InboundNodeData> data): NodeDataModel()
|
QvInboundNodeModel::QvInboundNodeModel(std::shared_ptr<InboundNodeData> data) : NodeDataModel()
|
||||||
{
|
{
|
||||||
_in = data;
|
_in = data;
|
||||||
_label = new QLabel();
|
_label = new QLabel();
|
||||||
|
@ -1,68 +1,72 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtCore/qglobal.h>
|
|
||||||
#include "ui/models/NodeModelsBase.hpp"
|
#include "ui/models/NodeModelsBase.hpp"
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
class QvInboundNodeModel : public NodeDataModel
|
class QvInboundNodeModel : public NodeDataModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QvInboundNodeModel(std::shared_ptr<InboundNodeData> data);
|
explicit QvInboundNodeModel(std::shared_ptr<InboundNodeData> data);
|
||||||
~QvInboundNodeModel()
|
~QvInboundNodeModel()
|
||||||
{
|
{
|
||||||
//if (_label) {
|
// if (_label) {
|
||||||
// delete _label;
|
// delete _label;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString caption() const override
|
QString caption() const override
|
||||||
{
|
{
|
||||||
return "Nothing";
|
return "Nothing";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool captionVisible() const override
|
bool captionVisible() const override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int nPorts(PortType portType) const override
|
unsigned int nPorts(PortType portType) const override
|
||||||
{
|
{
|
||||||
return portType == PortType::Out ? 1 : 0;
|
return portType == PortType::Out ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString name() const override
|
QString name() const override
|
||||||
{
|
{
|
||||||
return "InboundNode";
|
return "InboundNode";
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
|
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
|
||||||
{
|
{
|
||||||
Q_UNUSED(portType);
|
Q_UNUSED(portType);
|
||||||
Q_UNUSED(portIndex);
|
Q_UNUSED(portIndex);
|
||||||
return inboundType;
|
return inboundType;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<NodeData> outData(PortIndex) override
|
std::shared_ptr<NodeData> outData(PortIndex) override
|
||||||
{
|
{
|
||||||
return _in;
|
return _in;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInData(std::shared_ptr<NodeData>, int) override {}
|
void setInData(std::shared_ptr<NodeData>, int) override
|
||||||
void setData(const QString &data)
|
{
|
||||||
{
|
}
|
||||||
_in = make_shared<InboundNodeData>(data);
|
void setData(const QString &data)
|
||||||
_label->setText(data);
|
{
|
||||||
_label->adjustSize();
|
_in = make_shared<InboundNodeData>(data);
|
||||||
}
|
_label->setText(data);
|
||||||
|
_label->adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
QWidget *embeddedWidget() override
|
QWidget *embeddedWidget() override
|
||||||
{
|
{
|
||||||
return _label;
|
return _label;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
NodeValidationState modelValidationState = NodeValidationState::Warning;
|
private:
|
||||||
QString modelValidationError = tr("Missing or incorrect inputs");
|
NodeValidationState modelValidationState = NodeValidationState::Warning;
|
||||||
//
|
QString modelValidationError = tr("Missing or incorrect inputs");
|
||||||
std::shared_ptr<InboundNodeData> _in;
|
//
|
||||||
QLabel *_label;
|
std::shared_ptr<InboundNodeData> _in;
|
||||||
|
QLabel *_label;
|
||||||
};
|
};
|
||||||
|
@ -1,101 +1,99 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
|
|
||||||
#include "NodeDataModel.hpp"
|
#include "NodeDataModel.hpp"
|
||||||
#include "PortType.hpp"
|
#include "PortType.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
using QtNodes::PortType;
|
#include <QLabel>
|
||||||
using QtNodes::PortIndex;
|
|
||||||
using QtNodes::NodeData;
|
using QtNodes::NodeData;
|
||||||
using QtNodes::NodeDataType;
|
|
||||||
using QtNodes::NodeDataModel;
|
using QtNodes::NodeDataModel;
|
||||||
using QtNodes::NodeValidationState;
|
|
||||||
|
|
||||||
|
|
||||||
using QtNodes::NodeDataType;
|
using QtNodes::NodeDataType;
|
||||||
|
using QtNodes::NodeValidationState;
|
||||||
|
using QtNodes::PortIndex;
|
||||||
|
using QtNodes::PortType;
|
||||||
|
|
||||||
using QtNodes::NodeData;
|
using QtNodes::NodeData;
|
||||||
|
using QtNodes::NodeDataType;
|
||||||
|
|
||||||
const int GRAPH_NODE_LABEL_FONTSIZE_INCREMENT = 3;
|
const int GRAPH_NODE_LABEL_FONTSIZE_INCREMENT = 3;
|
||||||
|
|
||||||
namespace Qv2ray::ui::nodemodels
|
namespace Qv2ray::ui::nodemodels
|
||||||
{
|
{
|
||||||
const NodeDataType outboundType = {"outbound", "Outbound Object"};
|
const NodeDataType outboundType = { "outbound", "Outbound Object" };
|
||||||
const NodeDataType inboundType = {"inbound", "Inbound Object"};
|
const NodeDataType inboundType = { "inbound", "Inbound Object" };
|
||||||
/// The class can potentially incapsulate any user data
|
/// The class can potentially incapsulate any user data
|
||||||
/// need to be transferred within the Node Editor graph
|
/// need to be transferred within the Node Editor graph
|
||||||
class InboundNodeData : public NodeData
|
class InboundNodeData : public NodeData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InboundNodeData()
|
InboundNodeData(){ DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.") } InboundNodeData(QString in)
|
||||||
{
|
: _inboundTag(in)
|
||||||
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
|
{
|
||||||
}
|
}
|
||||||
InboundNodeData(QString in) : _inboundTag(in) { }
|
|
||||||
|
|
||||||
NodeDataType type() const override
|
NodeDataType type() const override
|
||||||
{
|
{
|
||||||
return inboundType;
|
return inboundType;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GetInbound()
|
QString GetInbound()
|
||||||
{
|
{
|
||||||
return _inboundTag;
|
return _inboundTag;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
QString _inboundTag;
|
private:
|
||||||
|
QString _inboundTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The class can potentially incapsulate any user data
|
/// The class can potentially incapsulate any user data
|
||||||
/// need to be transferred within the Node Editor graph
|
/// need to be transferred within the Node Editor graph
|
||||||
class OutboundNodeData : public NodeData
|
class OutboundNodeData : public NodeData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OutboundNodeData() : _outboundTag()
|
OutboundNodeData()
|
||||||
{
|
: _outboundTag(){ DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.") } OutboundNodeData(QString out)
|
||||||
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
|
: _outboundTag(out)
|
||||||
}
|
{
|
||||||
OutboundNodeData(QString out) : _outboundTag(out) { }
|
}
|
||||||
|
|
||||||
NodeDataType type() const override
|
NodeDataType type() const override
|
||||||
{
|
{
|
||||||
return outboundType;
|
return outboundType;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GetOutbound()
|
QString GetOutbound()
|
||||||
{
|
{
|
||||||
return _outboundTag;
|
return _outboundTag;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
QString _outboundTag;
|
private:
|
||||||
|
QString _outboundTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The class can potentially incapsulate any user data
|
/// The class can potentially incapsulate any user data
|
||||||
/// need to be transferred within the Node Editor graph
|
/// need to be transferred within the Node Editor graph
|
||||||
class RuleNodeData : public NodeData
|
class RuleNodeData : public NodeData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RuleNodeData() : _ruleTag()
|
RuleNodeData()
|
||||||
{
|
: _ruleTag(){ DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.") } RuleNodeData(QString out) : _ruleTag(out)
|
||||||
DEBUG(MODULE_GRAPH, "DANGER: Initialising a data model without value.")
|
{
|
||||||
}
|
}
|
||||||
RuleNodeData(QString out) : _ruleTag(out) { }
|
|
||||||
|
|
||||||
NodeDataType type() const override
|
NodeDataType type() const override
|
||||||
{
|
{
|
||||||
return outboundType;
|
return outboundType;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GetRuleTag()
|
QString GetRuleTag()
|
||||||
{
|
{
|
||||||
return _ruleTag;
|
return _ruleTag;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
QString _ruleTag;
|
private:
|
||||||
|
QString _ruleTag;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Qv2ray::ui::nodemodels
|
||||||
|
|
||||||
|
|
||||||
using namespace Qv2ray::ui::nodemodels;
|
using namespace Qv2ray::ui::nodemodels;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "ui/models/OutboundNodeModel.hpp"
|
#include "ui/models/OutboundNodeModel.hpp"
|
||||||
|
|
||||||
QvOutboundNodeModel::QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data): NodeDataModel()
|
QvOutboundNodeModel::QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data) : NodeDataModel()
|
||||||
{
|
{
|
||||||
_out = data;
|
_out = data;
|
||||||
_label = new QLabel();
|
_label = new QLabel();
|
||||||
|
@ -1,74 +1,80 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QtCore/qglobal.h>
|
|
||||||
#include "ui/models/NodeModelsBase.hpp"
|
#include "ui/models/NodeModelsBase.hpp"
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
class QvOutboundNodeModel : public NodeDataModel
|
class QvOutboundNodeModel : public NodeDataModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data);
|
explicit QvOutboundNodeModel(std::shared_ptr<OutboundNodeData> data);
|
||||||
~QvOutboundNodeModel()
|
~QvOutboundNodeModel()
|
||||||
{
|
{
|
||||||
//if (_label) {
|
// if (_label) {
|
||||||
// delete _label;
|
// delete _label;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString caption() const override
|
QString caption() const override
|
||||||
{
|
{
|
||||||
return "Nothing";
|
return "Nothing";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool captionVisible() const override
|
bool captionVisible() const override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int nPorts(PortType portType) const override
|
unsigned int nPorts(PortType portType) const override
|
||||||
{
|
{
|
||||||
return portType == PortType::In ? 1 : 0;
|
return portType == PortType::In ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString name() const override
|
QString name() const override
|
||||||
{
|
{
|
||||||
return "OutboundNode";
|
return "OutboundNode";
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
|
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
|
||||||
{
|
{
|
||||||
Q_UNUSED(portType);
|
Q_UNUSED(portType);
|
||||||
Q_UNUSED(portIndex);
|
Q_UNUSED(portIndex);
|
||||||
return outboundType;
|
return outboundType;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<NodeData> outData(PortIndex) override
|
std::shared_ptr<NodeData> outData(PortIndex) override
|
||||||
{
|
{
|
||||||
return _out;
|
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 setInData(vector<shared_ptr<NodeData>>, int) override
|
||||||
void setData(const QString &data)
|
{
|
||||||
{
|
}
|
||||||
_out = make_shared<OutboundNodeData>(data);
|
void setData(const QString &data)
|
||||||
_label->setText(_out->GetOutbound());
|
{
|
||||||
_label->adjustSize();
|
_out = make_shared<OutboundNodeData>(data);
|
||||||
}
|
_label->setText(_out->GetOutbound());
|
||||||
|
_label->adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
QWidget *embeddedWidget() override
|
QWidget *embeddedWidget() override
|
||||||
{
|
{
|
||||||
return _label;
|
return _label;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
|
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
|
||||||
{
|
{
|
||||||
return ConnectionPolicy::Many;
|
return ConnectionPolicy::Many;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
NodeValidationState modelValidationState = NodeValidationState::Warning;
|
private:
|
||||||
QString modelValidationError = tr("Missing or incorrect inputs");
|
NodeValidationState modelValidationState = NodeValidationState::Warning;
|
||||||
//
|
QString modelValidationError = tr("Missing or incorrect inputs");
|
||||||
std::shared_ptr<OutboundNodeData> _out;
|
//
|
||||||
QLabel *_label;
|
std::shared_ptr<OutboundNodeData> _out;
|
||||||
|
QLabel *_label;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "ui/models/RuleNodeModel.hpp"
|
#include "ui/models/RuleNodeModel.hpp"
|
||||||
|
|
||||||
QvRuleNodeDataModel::QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data): NodeDataModel()
|
QvRuleNodeDataModel::QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data) : NodeDataModel()
|
||||||
{
|
{
|
||||||
_ruleTag = data;
|
_ruleTag = data;
|
||||||
_label = new QLabel();
|
_label = new QLabel();
|
||||||
|
@ -1,98 +1,103 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtCore/qglobal.h>
|
|
||||||
#include "ui/models/NodeModelsBase.hpp"
|
#include "ui/models/NodeModelsBase.hpp"
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
class QvRuleNodeDataModel : public NodeDataModel
|
class QvRuleNodeDataModel : public NodeDataModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data);
|
QvRuleNodeDataModel(std::shared_ptr<RuleNodeData> data);
|
||||||
~QvRuleNodeDataModel()
|
~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) {
|
return 1;
|
||||||
// delete _label;
|
}
|
||||||
//}
|
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 NodeDataType();
|
||||||
{
|
}
|
||||||
return "Nothing";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool captionVisible() const override
|
std::shared_ptr<NodeData> outData(PortIndex port) override
|
||||||
{
|
{
|
||||||
return false;
|
Q_UNUSED(port)
|
||||||
}
|
return _ruleTag;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int nPorts(PortType portType) const override
|
void setInData(std::shared_ptr<NodeData>, int) override
|
||||||
{
|
{
|
||||||
if (portType == PortType::In) {
|
}
|
||||||
return 1;
|
void setInData(vector<shared_ptr<NodeData>>, int) override
|
||||||
} else if (portType == PortType::Out) {
|
{
|
||||||
return 1;
|
}
|
||||||
} else {
|
void setData(const QString &data)
|
||||||
return 0;
|
{
|
||||||
}
|
_ruleTag = make_shared<RuleNodeData>(data);
|
||||||
}
|
_label->setText(_ruleTag->GetRuleTag());
|
||||||
|
_label->adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
QString name() const override
|
QWidget *embeddedWidget() override
|
||||||
{
|
{
|
||||||
return "RuleNode";
|
return _label;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeDataType dataType(PortType portType, PortIndex portIndex) const override
|
ConnectionPolicy portInConnectionPolicy(PortIndex) const override
|
||||||
{
|
{
|
||||||
Q_UNUSED(portIndex)
|
return ConnectionPolicy::Many;
|
||||||
|
}
|
||||||
|
|
||||||
switch (portType) {
|
ConnectionPolicy portOutConnectionPolicy(PortIndex) const override
|
||||||
case PortType::In:
|
{
|
||||||
return inboundType;
|
return ConnectionPolicy::One;
|
||||||
|
}
|
||||||
|
|
||||||
case PortType::Out:
|
private:
|
||||||
return outboundType;
|
NodeValidationState modelValidationState = NodeValidationState::Warning;
|
||||||
|
QString modelValidationError = tr("Missing or incorrect inputs");
|
||||||
case PortType::None:
|
//
|
||||||
break;
|
shared_ptr<RuleNodeData> _ruleTag;
|
||||||
}
|
QLabel *_label;
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
#include "w_ExportConfig.hpp"
|
#include "w_ExportConfig.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#include "core/connection/Serialization.hpp"
|
#include "core/connection/Serialization.hpp"
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
||||||
// Private initialiser
|
// Private initialiser
|
||||||
ConfigExporter::ConfigExporter(QWidget *parent) :
|
ConfigExporter::ConfigExporter(QWidget *parent) : QDialog(parent), qzxing(this)
|
||||||
QDialog(parent),
|
|
||||||
qzxing(this)
|
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
QvMessageBusConnect(ConfigExporter);
|
QvMessageBusConnect(ConfigExporter);
|
||||||
@ -14,10 +13,9 @@ ConfigExporter::ConfigExporter(QWidget *parent) :
|
|||||||
|
|
||||||
QvMessageBusSlotImpl(ConfigExporter)
|
QvMessageBusSlotImpl(ConfigExporter)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ ConfigExporter::~ConfigExporter()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
//ConfigExporter::ConfigExporter(QWidget *parent) : ConfigExporter(parent)
|
// ConfigExporter::ConfigExporter(QWidget *parent) : ConfigExporter(parent)
|
||||||
//{
|
//{
|
||||||
// // WIP
|
// // WIP
|
||||||
// // /auto &x = connection;
|
// // /auto &x = connection;
|
||||||
@ -49,17 +47,13 @@ void ConfigExporter::changeEvent(QEvent *e)
|
|||||||
{
|
{
|
||||||
QDialog::changeEvent(e);
|
QDialog::changeEvent(e);
|
||||||
|
|
||||||
switch (e->type()) {
|
switch (e->type())
|
||||||
case QEvent::LanguageChange:
|
{
|
||||||
retranslateUi(this);
|
case QEvent::LanguageChange: retranslateUi(this); break;
|
||||||
break;
|
|
||||||
|
|
||||||
case QEvent::Resize:
|
case QEvent::Resize: imageLabel->setPixmap(QPixmap::fromImage(image)); break;
|
||||||
imageLabel->setPixmap(QPixmap::fromImage(image));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,32 +1,36 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui_w_ExportConfig.h"
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
|
||||||
#include "3rdparty/qzxing/src/QZXing.h"
|
#include "3rdparty/qzxing/src/QZXing.h"
|
||||||
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "ui/messaging/QvMessageBus.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:
|
public:
|
||||||
explicit ConfigExporter(QWidget *parent = nullptr);
|
explicit ConfigExporter(QWidget *parent = nullptr);
|
||||||
~ConfigExporter();
|
~ConfigExporter();
|
||||||
void OpenExport();
|
void OpenExport();
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
protected:
|
|
||||||
void changeEvent(QEvent *e);
|
|
||||||
private slots:
|
|
||||||
void on_closeBtn_clicked();
|
|
||||||
|
|
||||||
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();
|
void on_copyImageBtn_clicked();
|
||||||
private:
|
|
||||||
QZXing qzxing;
|
void on_copyVMessBtn_clicked();
|
||||||
QImage image;
|
|
||||||
QString message;
|
private:
|
||||||
|
QZXing qzxing;
|
||||||
|
QImage image;
|
||||||
|
QString message;
|
||||||
};
|
};
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
#include <QDebug>
|
#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 <QFile>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include "3rdparty/qzxing/src/QZXing.h"
|
|
||||||
|
|
||||||
#include "core/CoreUtils.hpp"
|
ImportConfigWindow::ImportConfigWindow(QWidget *parent) : QDialog(parent)
|
||||||
#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)
|
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
nameTxt->setText(QDateTime::currentDateTime().toString("MMdd_hhmm"));
|
nameTxt->setText(QDateTime::currentDateTime().toString("MMdd_hhmm"));
|
||||||
@ -30,10 +29,9 @@ ImportConfigWindow::ImportConfigWindow(QWidget *parent)
|
|||||||
|
|
||||||
QvMessageBusSlotImpl(ImportConfigWindow)
|
QvMessageBusSlotImpl(ImportConfigWindow)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +41,8 @@ ImportConfigWindow::~ImportConfigWindow()
|
|||||||
|
|
||||||
QMap<QString, CONFIGROOT> ImportConfigWindow::OpenImport(bool partialImport)
|
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->setChecked(!outboundsOnly);
|
||||||
keepImportedInboundCheckBox->setEnabled(!partialImport);
|
keepImportedInboundCheckBox->setEnabled(!partialImport);
|
||||||
routeEditBtn->setEnabled(!partialImport);
|
routeEditBtn->setEnabled(!partialImport);
|
||||||
@ -61,9 +60,7 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
|
|||||||
{
|
{
|
||||||
bool hideQv2ray = hideQv2rayCB->isChecked();
|
bool hideQv2ray = hideQv2rayCB->isChecked();
|
||||||
|
|
||||||
if (hideQv2ray) {
|
if (hideQv2ray) { messageBus.EmitGlobalSignal(QvMBMessage::HIDE_WINDOWS); }
|
||||||
messageBus.EmitGlobalSignal(QvMBMessage::HIDE_WINDOWS);
|
|
||||||
}
|
|
||||||
|
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
QThread::msleep(static_cast<ulong>(doubleSpinBox->value() * 1000));
|
QThread::msleep(static_cast<ulong>(doubleSpinBox->value() * 1000));
|
||||||
@ -72,24 +69,29 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
|
|||||||
auto _r = w.result();
|
auto _r = w.result();
|
||||||
// Explicitly delete w to call UNREGISTER_WINDOW
|
// Explicitly delete w to call UNREGISTER_WINDOW
|
||||||
|
|
||||||
if (hideQv2ray) {
|
if (hideQv2ray)
|
||||||
|
{
|
||||||
messageBus.EmitGlobalSignal(QvMBMessage::SHOW_WINDOWS);
|
messageBus.EmitGlobalSignal(QvMBMessage::SHOW_WINDOWS);
|
||||||
//ShowAllGlobalWindow();
|
// ShowAllGlobalWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_r == QDialog::Accepted) {
|
if (_r == QDialog::Accepted)
|
||||||
|
{
|
||||||
QZXing decoder;
|
QZXing decoder;
|
||||||
decoder.setDecoder(QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13);
|
decoder.setDecoder(QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13);
|
||||||
auto str = decoder.decodeImage(pix);
|
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()))
|
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."));
|
QvMessageBoxWarn(this, tr("Capture QRCode"), tr("Cannot find a valid QRCode from this region."));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
|
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
|
||||||
//QvMessageBoxWarn(this, tr("Capture QRCode"), tr("Successfully imported a QR code form the screen."));
|
// QvMessageBoxWarn(this, tr("Capture QRCode"), tr("Successfully
|
||||||
//this->show();
|
// imported a QR code form the screen.")); this->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,26 +99,30 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
|
|||||||
void ImportConfigWindow::on_beginImportBtn_clicked()
|
void ImportConfigWindow::on_beginImportBtn_clicked()
|
||||||
{
|
{
|
||||||
QString aliasPrefix = nameTxt->text();
|
QString aliasPrefix = nameTxt->text();
|
||||||
//auto conf = GetGlobalConfig();
|
// auto conf = GetGlobalConfig();
|
||||||
|
|
||||||
switch (tabWidget->currentIndex()) {
|
switch (tabWidget->currentIndex())
|
||||||
case 0: {
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
//// From File...
|
//// From File...
|
||||||
//bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
|
// bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
|
||||||
//QString path = fileLineTxt->text();
|
// QString path = fileLineTxt->text();
|
||||||
//
|
//
|
||||||
//if (!V2rayKernelInstance::ValidateConfig(path)) {
|
// if (!V2rayKernelInstance::ValidateConfig(path)) {
|
||||||
// QvMessageBoxWarn(this, tr("Import config file"), tr("Failed to check the validity of the config file."));
|
// QvMessageBoxWarn(this, tr("Import config file"), tr("Failed to
|
||||||
// return;
|
// check the validity of the config file.")); return;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//aliasPrefix += "_" + QFileInfo(path).fileName();
|
// aliasPrefix += "_" + QFileInfo(path).fileName();
|
||||||
////CONFIGROOT config = ConvertConfigFromFile(path, ImportAsComplex);
|
////CONFIGROOT config = ConvertConfigFromFile(path,
|
||||||
//connections[aliasPrefix] = config;
|
/// ImportAsComplex);
|
||||||
//break;
|
// connections[aliasPrefix] = config;
|
||||||
|
// break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1: {
|
case 1:
|
||||||
|
{
|
||||||
QStringList linkList = SplitLines(vmessConnectionStringTxt->toPlainText());
|
QStringList linkList = SplitLines(vmessConnectionStringTxt->toPlainText());
|
||||||
//
|
//
|
||||||
// Clear UI and error lists
|
// 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.")
|
LOG(MODULE_IMPORT, QSTRN(linkList.count()) + " string found in vmess box.")
|
||||||
|
|
||||||
while (!linkList.isEmpty()) {
|
while (!linkList.isEmpty())
|
||||||
|
{
|
||||||
aliasPrefix = nameTxt->text();
|
aliasPrefix = nameTxt->text();
|
||||||
auto link = linkList.takeFirst();
|
auto link = linkList.takeFirst();
|
||||||
QString errMessage;
|
QString errMessage;
|
||||||
CONFIGROOT config = ConvertConfigFromString(link, &aliasPrefix, &errMessage);
|
CONFIGROOT config = ConvertConfigFromString(link, &aliasPrefix, &errMessage);
|
||||||
|
|
||||||
// If the config is empty or we have any err messages.
|
// 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.
|
// To prevent duplicated values.
|
||||||
linkErrors[link] = QSTRN(linkErrors.count() + 1) + ": " + errMessage;
|
linkErrors[link] = QSTRN(linkErrors.count() + 1) + ": " + errMessage;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
connections[aliasPrefix] = config;
|
connections[aliasPrefix] = config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!linkErrors.isEmpty()) {
|
if (!linkErrors.isEmpty())
|
||||||
for (auto item : linkErrors) {
|
{
|
||||||
|
for (auto item : linkErrors)
|
||||||
|
{
|
||||||
vmessConnectionStringTxt->appendPlainText(linkErrors.key(item));
|
vmessConnectionStringTxt->appendPlainText(linkErrors.key(item));
|
||||||
errorsList->addItem(item);
|
errorsList->addItem(item);
|
||||||
}
|
}
|
||||||
@ -173,10 +185,13 @@ void ImportConfigWindow::on_selectImageBtn_clicked()
|
|||||||
decoder.setDecoder(QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13);
|
decoder.setDecoder(QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13);
|
||||||
auto str = decoder.decodeImage(QImage::fromData(buf));
|
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."));
|
QvMessageBoxWarn(this, tr("QRCode scanning failed"), tr("Cannot find any QRCode from the image."));
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
|
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,9 +199,7 @@ void ImportConfigWindow::on_errorsList_currentItemChanged(QListWidgetItem *curre
|
|||||||
{
|
{
|
||||||
Q_UNUSED(previous)
|
Q_UNUSED(previous)
|
||||||
|
|
||||||
if (current == nullptr) {
|
if (current == nullptr) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto currentErrorText = current->text();
|
auto currentErrorText = current->text();
|
||||||
auto vmessEntry = linkErrors.key(currentErrorText);
|
auto vmessEntry = linkErrors.key(currentErrorText);
|
||||||
@ -194,9 +207,7 @@ void ImportConfigWindow::on_errorsList_currentItemChanged(QListWidgetItem *curre
|
|||||||
auto startPos = vmessConnectionStringTxt->toPlainText().indexOf(vmessEntry);
|
auto startPos = vmessConnectionStringTxt->toPlainText().indexOf(vmessEntry);
|
||||||
auto endPos = startPos + vmessEntry.length();
|
auto endPos = startPos + vmessEntry.length();
|
||||||
|
|
||||||
if (startPos < 0) {
|
if (startPos < 0) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select vmess string that is invalid.
|
// Select vmess string that is invalid.
|
||||||
QTextCursor c = vmessConnectionStringTxt->textCursor();
|
QTextCursor c = vmessConnectionStringTxt->textCursor();
|
||||||
@ -208,36 +219,43 @@ void ImportConfigWindow::on_editFileBtn_clicked()
|
|||||||
{
|
{
|
||||||
QFile file(fileLineTxt->text());
|
QFile file(fileLineTxt->text());
|
||||||
|
|
||||||
if (!file.exists()) {
|
if (!file.exists())
|
||||||
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Provided file not found: ") + fileLineTxt->text());
|
{
|
||||||
|
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Provided file not found: ") + fileLineTxt->text());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto jsonString = StringFromFile(&file);
|
auto jsonString = StringFromFile(&file);
|
||||||
auto jsonCheckingError = VerifyJsonString(jsonString);
|
auto jsonCheckingError = VerifyJsonString(jsonString);
|
||||||
|
|
||||||
if (!jsonCheckingError.isEmpty()) {
|
if (!jsonCheckingError.isEmpty())
|
||||||
|
{
|
||||||
LOG(MODULE_FILEIO, "Currupted JSON file detected")
|
LOG(MODULE_FILEIO, "Currupted JSON file detected")
|
||||||
|
|
||||||
if (QvMessageBoxAsk(this, tr("Edit file as JSON"), tr("The file you selected has json syntax error. Continue editing may make you lose data. Would you like to continue?") + NEWLINE + jsonCheckingError) != QMessageBox::Yes) {
|
if (QvMessageBoxAsk(
|
||||||
return;
|
this, tr("Edit file as JSON"),
|
||||||
} else {
|
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.")
|
LOG(MODULE_FILEIO, "Continue editing curruped json file, data loss is expected.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto json = JsonFromString(jsonString);
|
auto json = JsonFromString(jsonString);
|
||||||
JsonEditor editor(json, this);
|
JsonEditor editor(json, this);
|
||||||
json = editor.OpenEditor();
|
json = editor.OpenEditor();
|
||||||
|
|
||||||
if (editor.result() == QDialog::Accepted) {
|
if (editor.result() == QDialog::Accepted)
|
||||||
|
{
|
||||||
auto str = JsonToString(json);
|
auto str = JsonToString(json);
|
||||||
bool result = StringToFile(str, file);
|
bool result = StringToFile(str, file);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) { QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions")); }
|
||||||
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions"));
|
}
|
||||||
}
|
else
|
||||||
} else {
|
{
|
||||||
LOG(MODULE_FILEIO, "Canceled saving a file.")
|
LOG(MODULE_FILEIO, "Canceled saving a file.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +267,8 @@ void ImportConfigWindow::on_connectionEditBtn_clicked()
|
|||||||
bool isChanged = w.result() == QDialog::Accepted;
|
bool isChanged = w.result() == QDialog::Accepted;
|
||||||
QString alias = w.GetFriendlyName();
|
QString alias = w.GetFriendlyName();
|
||||||
|
|
||||||
if (isChanged) {
|
if (isChanged)
|
||||||
|
{
|
||||||
OUTBOUNDS outboundsList;
|
OUTBOUNDS outboundsList;
|
||||||
outboundsList.push_back(outboundEntry);
|
outboundsList.push_back(outboundEntry);
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
@ -257,7 +276,9 @@ void ImportConfigWindow::on_connectionEditBtn_clicked()
|
|||||||
//
|
//
|
||||||
connections[alias] = root;
|
connections[alias] = root;
|
||||||
accept();
|
accept();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +296,8 @@ void ImportConfigWindow::on_subscriptionButton_clicked()
|
|||||||
auto importToComplex = !keepImportedInboundCheckBox->isEnabled();
|
auto importToComplex = !keepImportedInboundCheckBox->isEnabled();
|
||||||
connections.clear();
|
connections.clear();
|
||||||
|
|
||||||
if (importToComplex) {
|
if (importToComplex)
|
||||||
|
{
|
||||||
auto _result = w.GetSelectedConfig();
|
auto _result = w.GetSelectedConfig();
|
||||||
connections[_result.first] = _result.second;
|
connections[_result.first] = _result.second;
|
||||||
}
|
}
|
||||||
@ -290,10 +312,13 @@ void ImportConfigWindow::on_routeEditBtn_clicked()
|
|||||||
bool isChanged = w.result() == QDialog::Accepted;
|
bool isChanged = w.result() == QDialog::Accepted;
|
||||||
QString alias = nameTxt->text();
|
QString alias = nameTxt->text();
|
||||||
|
|
||||||
if (isChanged) {
|
if (isChanged)
|
||||||
|
{
|
||||||
connections[alias] = result;
|
connections[alias] = result;
|
||||||
accept();
|
accept();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,47 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include <QString>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "ui_w_ImportConfig.h"
|
|
||||||
#include "ui/messaging/QvMessageBus.hpp"
|
#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:
|
public:
|
||||||
explicit ImportConfigWindow(QWidget *parent = nullptr);
|
explicit ImportConfigWindow(QWidget *parent = nullptr);
|
||||||
~ImportConfigWindow();
|
~ImportConfigWindow();
|
||||||
QMap<QString, CONFIGROOT> OpenImport(bool outboundsOnly = false);
|
QMap<QString, CONFIGROOT> OpenImport(bool outboundsOnly = false);
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void on_selectFileBtn_clicked();
|
void on_selectFileBtn_clicked();
|
||||||
|
|
||||||
void on_qrFromScreenBtn_clicked();
|
void on_qrFromScreenBtn_clicked();
|
||||||
void on_beginImportBtn_clicked();
|
void on_beginImportBtn_clicked();
|
||||||
void on_selectImageBtn_clicked();
|
void on_selectImageBtn_clicked();
|
||||||
void on_errorsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
|
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:
|
private:
|
||||||
QMap<QString, CONFIGROOT> connections;
|
QMap<QString, CONFIGROOT> connections;
|
||||||
QMap<QString, QString> linkErrors;
|
QMap<QString, QString> linkErrors;
|
||||||
};
|
};
|
||||||
|
@ -1,76 +1,86 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "w_MainWindow.hpp"
|
#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_ImportConfig.hpp"
|
||||||
#include "w_PreferencesWindow.hpp"
|
#include "w_PreferencesWindow.hpp"
|
||||||
#include "w_SubscriptionManager.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 <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 <QCloseEvent>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDesktopServices>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
#include <QKeyEvent>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QDesktopServices>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVersionNumber>
|
#include <QVersionNumber>
|
||||||
#include <QKeyEvent>
|
|
||||||
|
|
||||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
// MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related
|
||||||
#include "components/pac/QvPACHandler.hpp"
|
// operations.
|
||||||
|
|
||||||
#include "core/connection/ConnectionIO.hpp"
|
|
||||||
#include "ui/widgets/ConnectionInfoWidget.hpp"
|
|
||||||
|
|
||||||
// MainWindow.cpp --> Main MainWindow source file, handles mostly UI-related operations.
|
|
||||||
|
|
||||||
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
|
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
|
||||||
//
|
//
|
||||||
#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_) \
|
#define SUBSCRIPTION_CONFIG_MODIFY_ASK(_item_) \
|
||||||
if (!CheckConfigType(_item_, REGULAR)) { \
|
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.") + \
|
if (QvMessageBoxAsk(this, QObject::tr("Editing a subscription config"),
|
||||||
NEWLINE + QObject::tr("All changes will be overwritten when the subscriptions are updated next time.") + \
|
QObject::tr("You are trying to edit a config loaded from subscription.") + \
|
||||||
NEWLINE + QObject::tr("Are you still going to do so?")) != QMessageBox::Yes) { \
|
NEWLINE + QObject::tr("All changes will be
|
||||||
return; \
|
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_) \
|
#define SUBSCRIPTION_CONFIG_MODIFY_DENY(_item_) \
|
||||||
if (!CheckConfigType(_item_, REGULAR)) { \
|
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")); \
|
QvMessageBoxWarn(this, QObject::tr("Editing a subscription config"),
|
||||||
return; \
|
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 IsConnectableItem(item) (item != nullptr && item->childCount() == 0 &&
|
||||||
#define IsSelectionConnectable (!connectionListWidget->selectedItems().empty() && IsConnectableItem(connectionListWidget->selectedItems().first()))
|
(CheckConfigType(item, REGULAR) || CheckConfigType(item, SUBSCRIPTION))) #define
|
||||||
|
IsSelectionConnectable (!connectionListWidget->selectedItems().empty() &&
|
||||||
|
IsConnectableItem(connectionListWidget->selectedItems().first()))
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MainWindow *MainWindow::mwInstance = nullptr;
|
MainWindow *MainWindow::mwInstance = nullptr;
|
||||||
|
|
||||||
QvMessageBusSlotImpl(MainWindow)
|
QvMessageBusSlotImpl(MainWindow)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
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);
|
setupUi(this);
|
||||||
MainWindow::mwInstance = this;
|
MainWindow::mwInstance = this;
|
||||||
@ -86,8 +96,8 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
this->setWindowIcon(QIcon(":/assets/icons/qv2ray.png"));
|
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"));
|
hTray.setIcon(QIcon(GlobalConfig.uiConfig.useDarkTrayIcon ? ":/assets/icons/ui_dark/tray.png" : ":/assets/icons/ui_light/tray.png"));
|
||||||
importConfigButton->setIcon(QICON_R("import.png"));
|
importConfigButton->setIcon(QICON_R("import.png"));
|
||||||
//pingTestBtn->setIcon(QICON_R("ping_gauge.png"));
|
// pingTestBtn->setIcon(QICON_R("ping_gauge.png"));
|
||||||
//shareBtn->setIcon(QICON_R("share.png"));
|
// shareBtn->setIcon(QICON_R("share.png"));
|
||||||
updownImageBox->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
|
updownImageBox->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
|
||||||
updownImageBox_2->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();
|
this->show();
|
||||||
QvMessageBoxWarn(this, tr("V2ray vcore terminated."),
|
QvMessageBoxWarn(this, tr("V2ray vcore terminated."),
|
||||||
tr("V2ray vcore terminated unexpectedly.") + NEWLINE + NEWLINE +
|
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::OnConnected, this, &MainWindow::OnConnected);
|
||||||
connect(ConnectionManager, &QvConnectionHandler::OnDisConnected, this, &MainWindow::OnDisConnected);
|
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_ShowHide, &QAction::triggered, this, &MainWindow::ToggleVisibility);
|
||||||
connect(action_Tray_ShowPreferencesWindow, &QAction::triggered, this, &MainWindow::on_preferencesBtn_clicked);
|
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_Start, &QAction::triggered, this,
|
||||||
//connect(action_Tray_Stop, &QAction::triggered, this, &MainWindow::on_stopButton_clicked);
|
// &MainWindow::on_startButton_clicked); connect(action_Tray_Stop,
|
||||||
//connect(action_Tray_Reconnect, &QAction::triggered, this, &MainWindow::on_reconnectButton_clicked);
|
// &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_Quit, &QAction::triggered, this, &MainWindow::on_actionExit_triggered);
|
||||||
connect(action_Tray_SetSystemProxy, &QAction::triggered, this, &MainWindow::MWSetSystemProxy);
|
connect(action_Tray_SetSystemProxy, &QAction::triggered, this, &MainWindow::MWSetSystemProxy);
|
||||||
connect(action_Tray_ClearSystemProxy, &QAction::triggered, this, &MainWindow::MWClearSystemProxy);
|
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);
|
connect(action_RCM_ShareQR, &QAction::triggered, this, &MainWindow::on_action_RCM_ShareQR_triggered);
|
||||||
//
|
//
|
||||||
// Globally invokable signals.
|
// Globally invokable signals.
|
||||||
//connect(this, &MainWindow::Connect, this, &MainWindow::on_startButton_clicked);
|
// connect(this, &MainWindow::Connect, this,
|
||||||
//connect(this, &MainWindow::DisConnect, this, &MainWindow::on_stopButton_clicked);
|
// &MainWindow::on_startButton_clicked); connect(this,
|
||||||
//connect(this, &MainWindow::ReConnect, this, &MainWindow::on_reconnectButton_clicked);
|
// &MainWindow::DisConnect, this, &MainWindow::on_stopButton_clicked);
|
||||||
|
// connect(this, &MainWindow::ReConnect, this,
|
||||||
|
// &MainWindow::on_reconnectButton_clicked);
|
||||||
//
|
//
|
||||||
hTray.setContextMenu(tray_RootMenu);
|
hTray.setContextMenu(tray_RootMenu);
|
||||||
hTray.show();
|
hTray.show();
|
||||||
@ -183,13 +197,15 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
LOG(MODULE_UI, "Loading data...")
|
LOG(MODULE_UI, "Loading data...")
|
||||||
auto groups = ConnectionManager->AllGroups();
|
auto groups = ConnectionManager->AllGroups();
|
||||||
|
|
||||||
for (auto group : groups) {
|
for (auto group : groups)
|
||||||
|
{
|
||||||
auto groupItem = new QTreeWidgetItem(QStringList() << "" << ConnectionManager->GetDisplayName(group));
|
auto groupItem = new QTreeWidgetItem(QStringList() << "" << ConnectionManager->GetDisplayName(group));
|
||||||
connectionListWidget->addTopLevelItem(groupItem);
|
connectionListWidget->addTopLevelItem(groupItem);
|
||||||
connectionListWidget->setItemWidget(groupItem, 0, new ConnectionItemWidget(group, connectionListWidget));
|
connectionListWidget->setItemWidget(groupItem, 0, new ConnectionItemWidget(group, connectionListWidget));
|
||||||
auto connections = ConnectionManager->Connections(group);
|
auto connections = ConnectionManager->Connections(group);
|
||||||
|
|
||||||
for (auto connection : connections) {
|
for (auto connection : connections)
|
||||||
|
{
|
||||||
auto connectionItem = new QTreeWidgetItem(QStringList() << "" << ConnectionManager->GetDisplayName(connection));
|
auto connectionItem = new QTreeWidgetItem(QStringList() << "" << ConnectionManager->GetDisplayName(connection));
|
||||||
groupItem->addChild(connectionItem);
|
groupItem->addChild(connectionItem);
|
||||||
auto widget = new ConnectionItemWidget(connection, connectionListWidget);
|
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
|
// Find and start if there is an auto-connection
|
||||||
auto needShowWindow = true;
|
auto needShowWindow = true;
|
||||||
|
|
||||||
if (!GlobalConfig.autoStartId.isEmpty()) {
|
if (!GlobalConfig.autoStartId.isEmpty())
|
||||||
|
{
|
||||||
auto id = ConnectionId(GlobalConfig.autoStartId);
|
auto id = ConnectionId(GlobalConfig.autoStartId);
|
||||||
needShowWindow = ConnectionManager->StartConnection(id).has_value();
|
needShowWindow = ConnectionManager->StartConnection(id).has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needShowWindow) {
|
if (needShowWindow) { this->show(); }
|
||||||
this->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
//// If we are not connected to anything, show the MainWindow.
|
//// If we are not connected to anything, show the MainWindow.
|
||||||
if (needShowWindow) {
|
if (needShowWindow) {}
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef DISABLE_AUTO_UPDATE
|
#ifndef DISABLE_AUTO_UPDATE
|
||||||
requestHelper = new QvHttpRequestHelper();
|
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");
|
requestHelper->get("https://api.github.com/repos/Qv2ray/Qv2ray/releases/latest");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (StartupOption.enableToolbarPlguin) {
|
if (StartupOption.enableToolbarPlguin)
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Plugin daemon is enabled.")
|
LOG(MODULE_UI, "Plugin daemon is enabled.")
|
||||||
StartProcessingPlugins();
|
StartProcessingPlugins();
|
||||||
}
|
}
|
||||||
@ -231,33 +246,35 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
splitter->setSizes(QList<int>() << 100 << 300);
|
splitter->setSizes(QList<int>() << 100 << 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::keyPressEvent(QKeyEvent *e)
|
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.
|
// If pressed enter or return on connectionListWidget.
|
||||||
// Try to connect to the selected connection.
|
// Try to connect to the selected connection.
|
||||||
//if (focusWidget() == connectionListWidget) {
|
// if (focusWidget() == connectionListWidget) {
|
||||||
// if (!IsSelectionConnectable) return;
|
// if (!IsSelectionConnectable) return;
|
||||||
//
|
//
|
||||||
// auto selections = connectionListWidget->selectedItems();
|
// auto selections = connectionListWidget->selectedItems();
|
||||||
// QVariant v;
|
// QVariant v;
|
||||||
// auto vv = v.value<QvConnectionObject>();
|
// auto vv = v.value<QvConnectionObject>();
|
||||||
// ShowAndSetConnection(ItemConnectionIdentifier(selections.first()), true, true);
|
// ShowAndSetConnection(ItemConnectionIdentifier(selections.first()),
|
||||||
|
// true, true);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_action_StartThis_triggered()
|
void MainWindow::on_action_StartThis_triggered()
|
||||||
{
|
{
|
||||||
//if (!IsSelectionConnectable) {
|
// if (!IsSelectionConnectable) {
|
||||||
// QvMessageBoxWarn(this, tr("No connection selected!"), tr("Please select a config from the list."));
|
// QvMessageBoxWarn(this, tr("No connection selected!"), tr("Please
|
||||||
// return;
|
// select a config from the list.")); return;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//CurrentSelectedItemPtr = connectionListWidget->selectedItems().first();
|
// CurrentSelectedItemPtr = connectionListWidget->selectedItems().first();
|
||||||
//CurrentConnectionIdentifier = ItemConnectionIdentifier(CurrentSelectedItemPtr);
|
// CurrentConnectionIdentifier =
|
||||||
//on_reconnectButton_clicked();
|
// ItemConnectionIdentifier(CurrentSelectedItemPtr);
|
||||||
|
// on_reconnectButton_clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_AUTO_UPDATE
|
#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 newVersion = QVersionNumber::fromString(root["tag_name"].toString("v").remove(0, 1));
|
||||||
QVersionNumber currentVersion = QVersionNumber::fromString(QString(QV2RAY_VERSION_STRING).remove(0, 1));
|
QVersionNumber currentVersion = QVersionNumber::fromString(QString(QV2RAY_VERSION_STRING).remove(0, 1));
|
||||||
QVersionNumber ignoredVersion = QVersionNumber::fromString(GlobalConfig.ignoredVersion);
|
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.
|
// If the version is newer than us.
|
||||||
// And new version is newer than the ignored version.
|
// 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.")
|
LOG(MODULE_UPDATE, "New version detected.")
|
||||||
auto link = root["html_url"].toString("");
|
auto link = root["html_url"].toString("");
|
||||||
auto result = QvMessageBoxAsk(this, tr("Update"),
|
auto result =
|
||||||
tr("Found a new version: ") + root["tag_name"].toString("") +
|
QvMessageBoxAsk(this, tr("Update"),
|
||||||
"\r\n" +
|
tr("Found a new version: ") + root["tag_name"].toString("") + "\r\n" + root["name"].toString("") +
|
||||||
root["name"].toString("") +
|
"\r\n------------\r\n" + root["body"].toString("") + "\r\n------------\r\n" + tr("Download Link: ") + link,
|
||||||
"\r\n------------\r\n" +
|
QMessageBox::Ignore);
|
||||||
root["body"].toString("") +
|
|
||||||
"\r\n------------\r\n" +
|
|
||||||
tr("Download Link: ") + link, QMessageBox::Ignore);
|
|
||||||
|
|
||||||
if (result == QMessageBox::Yes) {
|
if (result == QMessageBox::Yes) { QDesktopServices::openUrl(QUrl::fromUserInput(link)); }
|
||||||
QDesktopServices::openUrl(QUrl::fromUserInput(link));
|
else if (result == QMessageBox::Ignore)
|
||||||
} else if (result == QMessageBox::Ignore) {
|
{
|
||||||
// Set and save ingored version.
|
// Set and save ingored version.
|
||||||
GlobalConfig.ignoredVersion = newVersion.toString();
|
GlobalConfig.ignoredVersion = newVersion.toString();
|
||||||
//SaveGlobalConfig(GlobalConfig);
|
// SaveGlobalConfig(GlobalConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,12 +325,14 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||||||
}
|
}
|
||||||
void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason)
|
void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason)
|
||||||
{
|
{
|
||||||
switch (reason) {
|
switch (reason)
|
||||||
|
{
|
||||||
case QSystemTrayIcon::Trigger:
|
case QSystemTrayIcon::Trigger:
|
||||||
// Toggle Show/Hide
|
// Toggle Show/Hide
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
// Every single click will trigger the Show/Hide toggling.
|
// 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();
|
ToggleVisibility();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@ -325,13 +343,13 @@ void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason)
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MainWindow::ToggleVisibility()
|
void MainWindow::ToggleVisibility()
|
||||||
{
|
{
|
||||||
if (this->isHidden()) {
|
if (this->isHidden())
|
||||||
|
{
|
||||||
this->show();
|
this->show();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
setWindowState(Qt::WindowNoState);
|
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);
|
SetWindowPos(HWND(this->winId()), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||||
#endif
|
#endif
|
||||||
tray_RootMenu->actions()[0]->setText(tr("Hide"));
|
tray_RootMenu->actions()[0]->setText(tr("Hide"));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
this->hide();
|
this->hide();
|
||||||
tray_RootMenu->actions()[0]->setText(tr("Show"));
|
tray_RootMenu->actions()[0]->setText(tr("Show"));
|
||||||
}
|
}
|
||||||
@ -348,9 +368,7 @@ void MainWindow::ToggleVisibility()
|
|||||||
|
|
||||||
void MainWindow::on_actionExit_triggered()
|
void MainWindow::on_actionExit_triggered()
|
||||||
{
|
{
|
||||||
if (StartupOption.enableToolbarPlguin) {
|
if (StartupOption.enableToolbarPlguin) { StopProcessingPlugins(); }
|
||||||
StopProcessingPlugins();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitQv2ray();
|
ExitQv2ray();
|
||||||
}
|
}
|
||||||
@ -366,13 +384,14 @@ void MainWindow::on_clearlogButton_clicked()
|
|||||||
void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
||||||
{
|
{
|
||||||
Q_UNUSED(previous)
|
Q_UNUSED(previous)
|
||||||
//CurrentItem = current;
|
// CurrentItem = current;
|
||||||
//isRenamingInProgress = false;
|
// isRenamingInProgress = false;
|
||||||
//
|
//
|
||||||
//if (!IsConnectableItem(current)) return;
|
// if (!IsConnectableItem(current)) return;
|
||||||
//
|
//
|
||||||
//// no need to check !isRenamingInProgress since it's always true.
|
//// 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);
|
////on_connectionListWidget_itemClicked(current, 0);
|
||||||
}
|
}
|
||||||
void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint &pos)
|
void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint &pos)
|
||||||
@ -381,52 +400,55 @@ void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint
|
|||||||
auto _pos = QCursor::pos();
|
auto _pos = QCursor::pos();
|
||||||
auto item = connectionListWidget->itemAt(connectionListWidget->mapFromGlobal(_pos));
|
auto item = connectionListWidget->itemAt(connectionListWidget->mapFromGlobal(_pos));
|
||||||
|
|
||||||
if (GetItemWidget(item)->IsConnection()) {
|
if (GetItemWidget(item)->IsConnection()) { connectionListMenu->popup(_pos); }
|
||||||
connectionListMenu->popup(_pos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void MainWindow::on_action_RCM_RenameConnection_triggered()
|
void MainWindow::on_action_RCM_RenameConnection_triggered()
|
||||||
{
|
{
|
||||||
//auto item = connectionListWidget->currentItem();
|
// auto item = connectionListWidget->currentItem();
|
||||||
//SUBSCRIPTION_CONFIG_MODIFY_DENY(item)
|
// SUBSCRIPTION_CONFIG_MODIFY_DENY(item)
|
||||||
//item->setFlags(item->flags() | Qt::ItemIsEditable);
|
// item->setFlags(item->flags() | Qt::ItemIsEditable);
|
||||||
//isRenamingInProgress = true;
|
// isRenamingInProgress = true;
|
||||||
//connectionListWidget->editItem(item);
|
// connectionListWidget->editItem(item);
|
||||||
//renameOriginalIdentifier = ItemConnectionIdentifier(item);
|
// renameOriginalIdentifier = ItemConnectionIdentifier(item);
|
||||||
}
|
}
|
||||||
void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
|
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;
|
// return;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//isRenamingInProgress = false;
|
// isRenamingInProgress = false;
|
||||||
//// In this case it's after we entered the name.
|
//// In this case it's after we entered the name.
|
||||||
//// and tell user you should not rename a config from subscription.
|
//// and tell user you should not rename a config from subscription.
|
||||||
//auto newIdentifier = renameOriginalIdentifier;
|
// auto newIdentifier = renameOriginalIdentifier;
|
||||||
//newIdentifier.connectionName = item->text(0);
|
// newIdentifier.connectionName = item->text(0);
|
||||||
//LOG(CONNECTION, "RENAME: " + renameOriginalIdentifier.IdentifierString() + " -> " + newIdentifier.IdentifierString())
|
// LOG(CONNECTION, "RENAME: " + renameOriginalIdentifier.IdentifierString()
|
||||||
|
// + " -> " + newIdentifier.IdentifierString())
|
||||||
//
|
//
|
||||||
//// If I really did some changes.
|
//// If I really did some changes.
|
||||||
//if (renameOriginalIdentifier != newIdentifier) {
|
// if (renameOriginalIdentifier != newIdentifier) {
|
||||||
// bool canContinueRename = true;
|
// bool canContinueRename = true;
|
||||||
//
|
//
|
||||||
// if (newIdentifier.connectionName.trimmed().isEmpty()) {
|
// if (newIdentifier.connectionName.trimmed().isEmpty()) {
|
||||||
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name cannot be empty"));
|
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name
|
||||||
// canContinueRename = false;
|
// cannot be empty")); canContinueRename = false;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
// QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
||||||
// //if (GlobalConfig.configs.contains(newIdentifier.connectionName)) {
|
// //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;
|
// // canContinueRename = false;
|
||||||
// //}
|
// //}
|
||||||
//
|
//
|
||||||
// if (!IsValidFileName(newIdentifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION)) {
|
// if (!IsValidFileName(newIdentifier.connectionName +
|
||||||
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name you suggested is not valid, please try another."));
|
// QV2RAY_CONFIG_FILE_EXTENSION)) {
|
||||||
// canContinueRename = false;
|
// QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name you
|
||||||
|
// suggested is not valid, please try another.")); canContinueRename
|
||||||
|
// = false;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if (!canContinueRename) {
|
// if (!canContinueRename) {
|
||||||
@ -448,8 +470,10 @@ void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
|
|||||||
// //GlobalConfig.configs.removeOne(renameOriginalIdentifier.connectionName);
|
// //GlobalConfig.configs.removeOne(renameOriginalIdentifier.connectionName);
|
||||||
// //GlobalConfig.configs.push_back(newIdentifier.connectionName);
|
// //GlobalConfig.configs.push_back(newIdentifier.connectionName);
|
||||||
// //
|
// //
|
||||||
// //connections[newIdentifier] = connections.take(renameOriginalIdentifier);
|
// //connections[newIdentifier] =
|
||||||
// //RenameConnection(renameOriginalIdentifier.connectionName, newIdentifier.connectionName);
|
// connections.take(renameOriginalIdentifier);
|
||||||
|
// //RenameConnection(renameOriginalIdentifier.connectionName,
|
||||||
|
// newIdentifier.connectionName);
|
||||||
// //LOG(UI, "Saving a global config")
|
// //LOG(UI, "Saving a global config")
|
||||||
// //SaveGlobalConfig(GlobalConfig);
|
// //SaveGlobalConfig(GlobalConfig);
|
||||||
// ////
|
// ////
|
||||||
@ -462,35 +486,38 @@ void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
|
|||||||
// // on_reconnectButton_clicked();
|
// // on_reconnectButton_clicked();
|
||||||
// // }
|
// // }
|
||||||
// //}
|
// //}
|
||||||
// //OnConfigListChanged(CurrentConnectionIdentifier.connectionName == renameOriginalName);
|
// //OnConfigListChanged(CurrentConnectionIdentifier.connectionName ==
|
||||||
|
// renameOriginalName);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
void MainWindow::on_removeConfigButton_clicked()
|
void MainWindow::on_removeConfigButton_clicked()
|
||||||
{
|
{
|
||||||
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
||||||
//QList<ConnectionIdentifier> connlist;
|
// QList<ConnectionIdentifier> connlist;
|
||||||
//
|
//
|
||||||
//for (auto item : connectionListWidget->selectedItems()) {
|
// for (auto item : connectionListWidget->selectedItems()) {
|
||||||
// if (IsConnectableItem(item)) {
|
// if (IsConnectableItem(item)) {
|
||||||
// connlist.append(ItemConnectionIdentifier(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.
|
// // Remove nothing means doing nothing.
|
||||||
// return;
|
// 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;
|
// return;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//// A triple-state flag which indicates if the user wants to remove the configs loaded from a subscription.
|
//// A triple-state flag which indicates if the user wants to remove the
|
||||||
//int subscriptionRemovalCheckStatus = -1;
|
/// configs loaded from a subscription.
|
||||||
|
// int subscriptionRemovalCheckStatus = -1;
|
||||||
//
|
//
|
||||||
//for (auto conn : connlist) {
|
// for (auto conn : connlist) {
|
||||||
// if (conn == CurrentConnectionIdentifier) {
|
// if (conn == CurrentConnectionIdentifier) {
|
||||||
// on_stopButton_clicked();
|
// on_stopButton_clicked();
|
||||||
// CurrentConnectionIdentifier = ConnectionIdentifier();
|
// CurrentConnectionIdentifier = ConnectionIdentifier();
|
||||||
@ -499,8 +526,10 @@ void MainWindow::on_removeConfigButton_clicked()
|
|||||||
// auto connData = connections[conn];
|
// auto connData = connections[conn];
|
||||||
//
|
//
|
||||||
// // Remove auto start config.
|
// // Remove auto start config.
|
||||||
// if (GlobalConfig.autoStartConfig.subscriptionName == connData.subscriptionName &&
|
// if (GlobalConfig.autoStartConfig.subscriptionName ==
|
||||||
// GlobalConfig.autoStartConfig.connectionName == connData.connectionName)
|
// connData.subscriptionName &&
|
||||||
|
// GlobalConfig.autoStartConfig.connectionName ==
|
||||||
|
// connData.connectionName)
|
||||||
// // If all those settings match.
|
// // If all those settings match.
|
||||||
// {
|
// {
|
||||||
// GlobalConfig.autoStartConfig.subscriptionName.clear();
|
// GlobalConfig.autoStartConfig.subscriptionName.clear();
|
||||||
@ -510,44 +539,53 @@ void MainWindow::on_removeConfigButton_clicked()
|
|||||||
// if (connData.configType == CONNECTION_REGULAR) {
|
// if (connData.configType == CONNECTION_REGULAR) {
|
||||||
// // Just remove the regular configs.
|
// // Just remove the regular configs.
|
||||||
// if (!connData.subscriptionName.isEmpty()) {
|
// if (!connData.subscriptionName.isEmpty()) {
|
||||||
// LOG(UI, "Unexpected subscription name in a single regular config.")
|
// LOG(UI, "Unexpected subscription name in a single regular
|
||||||
// connData.subscriptionName.clear();
|
// config.") connData.subscriptionName.clear();
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// GlobalConfig.configs.removeOne(conn.connectionName);
|
// GlobalConfig.configs.removeOne(conn.connectionName);
|
||||||
//
|
//
|
||||||
// if (!RemoveConnection(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) {
|
// } else if (connData.configType == CONNECTION_SUBSCRIPTION) {
|
||||||
// if (subscriptionRemovalCheckStatus == -1) {
|
// 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
|
// ? 1 // Yes i want
|
||||||
// : 0; // No please keep
|
// : 0; // No please keep
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if (subscriptionRemovalCheckStatus == 1) {
|
// if (subscriptionRemovalCheckStatus == 1) {
|
||||||
// if (!RemoveSubscriptionConnection(connData.subscriptionName, connData.connectionName)) {
|
// if (!RemoveSubscriptionConnection(connData.subscriptionName,
|
||||||
// QvMessageBoxWarn(this, tr("Removing this Connection"), tr("Failed to delete connection file, please delete manually."));
|
// connData.connectionName)) {
|
||||||
|
// QvMessageBoxWarn(this, tr("Removing this Connection"),
|
||||||
|
// tr("Failed to delete connection file, please delete
|
||||||
|
// manually."));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// } else {
|
// } else {
|
||||||
// LOG(SETTINGS, "Unknown config type -> Not regular nor subscription...")
|
// LOG(SETTINGS, "Unknown config type -> Not regular nor
|
||||||
|
// subscription...")
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//LOG(UI, "Saving GlobalConfig")
|
// LOG(UI, "Saving GlobalConfig")
|
||||||
//SaveGlobalConfig(GlobalConfig);
|
// SaveGlobalConfig(GlobalConfig);
|
||||||
//OnConfigListChanged(false);
|
// OnConfigListChanged(false);
|
||||||
//ShowAndSetConnection(CurrentConnectionIdentifier, false, false);
|
// ShowAndSetConnection(CurrentConnectionIdentifier, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_importConfigButton_clicked()
|
void MainWindow::on_importConfigButton_clicked()
|
||||||
{
|
{
|
||||||
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
||||||
//ImportConfigWindow w(this);
|
// ImportConfigWindow w(this);
|
||||||
//auto configs = w.OpenImport();
|
// auto configs = w.OpenImport();
|
||||||
//if (!configs.isEmpty()) {
|
// if (!configs.isEmpty()) {
|
||||||
// for (auto conf : configs) {
|
// for (auto conf : configs) {
|
||||||
// auto name = configs.key(conf, "");
|
// auto name = configs.key(conf, "");
|
||||||
//
|
//
|
||||||
@ -569,26 +607,26 @@ void MainWindow::on_editConfigButton_clicked()
|
|||||||
void MainWindow::on_action_RCM_ConvToComplex_triggered()
|
void MainWindow::on_action_RCM_ConvToComplex_triggered()
|
||||||
{
|
{
|
||||||
//// Check if we have a connection selected...
|
//// Check if we have a connection selected...
|
||||||
//if (!IsSelectionConnectable) {
|
// if (!IsSelectionConnectable) {
|
||||||
// QvMessageBoxWarn(this, tr("No Config Selected"), tr("Please Select a Config"));
|
// QvMessageBoxWarn(this, tr("No Config Selected"), tr("Please Select a
|
||||||
// return;
|
// Config")); return;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//auto selectedFirst = connectionListWidget->currentItem();
|
// auto selectedFirst = connectionListWidget->currentItem();
|
||||||
//auto _identifier = ItemConnectionIdentifier(selectedFirst);
|
// auto _identifier = ItemConnectionIdentifier(selectedFirst);
|
||||||
//SUBSCRIPTION_CONFIG_MODIFY_DENY(selectedFirst)
|
// SUBSCRIPTION_CONFIG_MODIFY_DENY(selectedFirst)
|
||||||
////
|
////
|
||||||
//auto outBoundRoot = connections[_identifier].config;
|
// auto outBoundRoot = connections[_identifier].config;
|
||||||
//CONFIGROOT root;
|
// CONFIGROOT root;
|
||||||
//bool isChanged = false;
|
// bool isChanged = false;
|
||||||
////
|
////
|
||||||
//LOG(UI, "INFO: Opening route editor.")
|
// LOG(UI, "INFO: Opening route editor.")
|
||||||
//RouteEditor routeWindow(outBoundRoot, this);
|
// RouteEditor routeWindow(outBoundRoot, this);
|
||||||
//root = routeWindow.OpenEditor();
|
// root = routeWindow.OpenEditor();
|
||||||
//isChanged = routeWindow.result() == QDialog::Accepted;
|
// isChanged = routeWindow.result() == QDialog::Accepted;
|
||||||
//QString alias = _identifier.connectionName;
|
// QString alias = _identifier.connectionName;
|
||||||
//
|
//
|
||||||
//if (isChanged) {
|
// if (isChanged) {
|
||||||
// connections[_identifier].config = root;
|
// connections[_identifier].config = root;
|
||||||
// // true indicates the alias will NOT change
|
// // true indicates the alias will NOT change
|
||||||
// SaveConnectionConfig(root, &alias, true);
|
// SaveConnectionConfig(root, &alias, true);
|
||||||
@ -603,7 +641,7 @@ void MainWindow::on_action_RCM_EditJson_triggered()
|
|||||||
|
|
||||||
void MainWindow::on_action_RCM_ShareQR_triggered()
|
void MainWindow::on_action_RCM_ShareQR_triggered()
|
||||||
{
|
{
|
||||||
//on_shareBtn_clicked();
|
// on_shareBtn_clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_subsButton_clicked()
|
void MainWindow::on_subsButton_clicked()
|
||||||
@ -616,9 +654,7 @@ void MainWindow::on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item
|
|||||||
Q_UNUSED(column)
|
Q_UNUSED(column)
|
||||||
auto widget = GetItemWidget(item);
|
auto widget = GetItemWidget(item);
|
||||||
|
|
||||||
if (widget->IsConnection()) {
|
if (widget->IsConnection()) { widget->BeginConnection(); }
|
||||||
widget->BeginConnection();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnDisConnected(const ConnectionId &id)
|
void MainWindow::OnDisConnected(const ConnectionId &id)
|
||||||
@ -628,14 +664,13 @@ void MainWindow::OnDisConnected(const ConnectionId &id)
|
|||||||
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE);
|
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE);
|
||||||
connetionStatusLabel->setText(tr("Disconnected"));
|
connetionStatusLabel->setText(tr("Disconnected"));
|
||||||
|
|
||||||
if (systemProxyEnabled) {
|
if (systemProxyEnabled) { MWClearSystemProxy(false); }
|
||||||
MWClearSystemProxy(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//QFile(QV2RAY_GENERATED_FILE_PATH).remove();
|
// QFile(QV2RAY_GENERATED_FILE_PATH).remove();
|
||||||
|
|
||||||
if (GlobalConfig.inboundConfig.pacConfig.enablePAC) {
|
if (GlobalConfig.inboundConfig.pacConfig.enablePAC)
|
||||||
//pacServer.StopServer();
|
{
|
||||||
|
// pacServer.StopServer();
|
||||||
LOG(MODULE_UI, "Stopping PAC server")
|
LOG(MODULE_UI, "Stopping PAC server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,56 +690,64 @@ void MainWindow::OnConnected(const ConnectionId &id)
|
|||||||
bool httpEnabled = GlobalConfig.inboundConfig.useHTTP;
|
bool httpEnabled = GlobalConfig.inboundConfig.useHTTP;
|
||||||
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
|
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
|
||||||
|
|
||||||
if (usePAC) {
|
if (usePAC)
|
||||||
|
{
|
||||||
bool canStartPAC = true;
|
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;
|
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")
|
LOG(MODULE_PROXY, "PAC Local IP is empty, default to 127.0.0.1")
|
||||||
pacIP = "127.0.0.1";
|
pacIP = "127.0.0.1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pacUseSocks) {
|
if (pacUseSocks)
|
||||||
if (socksEnabled) {
|
{
|
||||||
pacProxyString = "SOCKS5 " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.socks_port);
|
if (socksEnabled) { pacProxyString = "SOCKS5 " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.socks_port); }
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "PAC is using SOCKS, but it is not enabled")
|
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;
|
canStartPAC = false;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (httpEnabled) {
|
else
|
||||||
pacProxyString = "PROXY " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.http_port);
|
{
|
||||||
} else {
|
if (httpEnabled) { pacProxyString = "PROXY " + pacIP + ":" + QSTRN(GlobalConfig.inboundConfig.http_port); }
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "PAC is using HTTP, but it is not enabled")
|
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;
|
canStartPAC = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canStartPAC) {
|
if (canStartPAC)
|
||||||
//pacServer.SetProxyString(pacProxyString);
|
{
|
||||||
//pacServer.StartListen();
|
// pacServer.SetProxyString(pacProxyString);
|
||||||
} else {
|
// pacServer.StartListen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Not starting PAC due to previous error.")
|
LOG(MODULE_PROXY, "Not starting PAC due to previous error.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GlobalConfig.inboundConfig.setSystemProxy) {
|
if (GlobalConfig.inboundConfig.setSystemProxy) { MWSetSystemProxy(); }
|
||||||
MWSetSystemProxy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::onConnectionWidgetFocusRequested(const ConnectionItemWidget *_widget)
|
void MainWindow::onConnectionWidgetFocusRequested(const ConnectionItemWidget *_widget)
|
||||||
{
|
{
|
||||||
if (_widget == nullptr) {
|
if (_widget == nullptr) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto _item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard | Qt::MatchRecursive)) {
|
for (auto _item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard | Qt::MatchRecursive))
|
||||||
if (GetItemWidget(_item_) == _widget) {
|
{
|
||||||
|
if (GetItemWidget(_item_) == _widget)
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Setting current item.")
|
LOG(MODULE_UI, "Setting current item.")
|
||||||
connectionListWidget->setCurrentItem(_item_);
|
connectionListWidget->setCurrentItem(_item_);
|
||||||
connectionListWidget->scrollToItem(_item_);
|
connectionListWidget->scrollToItem(_item_);
|
||||||
@ -717,28 +760,31 @@ void MainWindow::onConnectionWidgetFocusRequested(const ConnectionItemWidget *_w
|
|||||||
void MainWindow::on_connectionFilterTxt_textEdited(const QString &arg1)
|
void MainWindow::on_connectionFilterTxt_textEdited(const QString &arg1)
|
||||||
{
|
{
|
||||||
// No recursive since we only need top level item
|
// No recursive since we only need top level item
|
||||||
for (auto _top_item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard)) {
|
for (auto _top_item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard))
|
||||||
//auto topWidget = GetItemWidget(_top_item_);
|
{
|
||||||
|
// auto topWidget = GetItemWidget(_top_item_);
|
||||||
bool isTotallyHide = true;
|
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);
|
auto _child_ = _top_item_->child(i);
|
||||||
|
|
||||||
if (GetItemWidget(_child_)->NameMatched(arg1)) {
|
if (GetItemWidget(_child_)->NameMatched(arg1))
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Setting current item.")
|
LOG(MODULE_UI, "Setting current item.")
|
||||||
// Show the child
|
// Show the child
|
||||||
_child_->setHidden(false);
|
_child_->setHidden(false);
|
||||||
isTotallyHide = false;
|
isTotallyHide = false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_child_->setHidden(true);
|
_child_->setHidden(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_top_item_->setHidden(isTotallyHide);
|
_top_item_->setHidden(isTotallyHide);
|
||||||
|
|
||||||
if (!isTotallyHide) {
|
if (!isTotallyHide) { connectionListWidget->expandItem(_top_item_); }
|
||||||
connectionListWidget->expandItem(_top_item_);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -748,11 +794,12 @@ void MainWindow::on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int
|
|||||||
infoWidget->ShowDetails(GetItemWidget(item)->Identifier());
|
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);
|
Q_UNUSED(id);
|
||||||
// This may not be, or may not precisely be, speed per second if low-level has "any" latency.
|
// This may not be, or may not precisely be, speed per second if low-level
|
||||||
// (Hope not...)
|
// has "any" latency. (Hope not...)
|
||||||
speedChartWidget->AddPointData(upSpeed, downSpeed);
|
speedChartWidget->AddPointData(upSpeed, downSpeed);
|
||||||
//
|
//
|
||||||
auto totalSpeedUp = FormatBytes(upSpeed) + "/s";
|
auto totalSpeedUp = FormatBytes(upSpeed) + "/s";
|
||||||
@ -763,7 +810,8 @@ void MainWindow::onConnectionStatsArrived(const ConnectionId &id, const quint64
|
|||||||
netspeedLabel->setText(totalSpeedUp + NEWLINE + totalSpeedDown);
|
netspeedLabel->setText(totalSpeedUp + NEWLINE + totalSpeedDown);
|
||||||
dataamountLabel->setText(totalDataUp + NEWLINE + totalDataDown);
|
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)
|
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;
|
auto maxLines = GlobalConfig.uiConfig.maximumLogLines;
|
||||||
QTextBlock block = masterLogBrowser->document()->begin();
|
QTextBlock block = masterLogBrowser->document()->begin();
|
||||||
|
|
||||||
while (block.isValid()) {
|
while (block.isValid())
|
||||||
if (masterLogBrowser->document()->blockCount() > maxLines) {
|
{
|
||||||
|
if (masterLogBrowser->document()->blockCount() > maxLines)
|
||||||
|
{
|
||||||
QTextCursor cursor(block);
|
QTextCursor cursor(block);
|
||||||
block = block.next();
|
block = block.next();
|
||||||
cursor.select(QTextCursor::BlockUnderCursor);
|
cursor.select(QTextCursor::BlockUnderCursor);
|
||||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||||
cursor.removeSelectedText();
|
cursor.removeSelectedText();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val >= max * 0.8 || val >= max - 20)
|
if (val >= max * 0.8 || val >= max - 20) bar->setValue(max);
|
||||||
bar->setValue(max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::OnEditRequested(const ConnectionId &id)
|
void MainWindow::OnEditRequested(const ConnectionId &id)
|
||||||
{
|
{
|
||||||
auto outBoundRoot = ConnectionManager->GetConnectionRoot(id);
|
auto outBoundRoot = ConnectionManager->GetConnectionRoot(id);
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
bool isChanged = false;
|
bool isChanged = false;
|
||||||
|
|
||||||
if (IsComplexConfig(outBoundRoot)) {
|
if (IsComplexConfig(outBoundRoot))
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "INFO: Opening route editor.")
|
LOG(MODULE_UI, "INFO: Opening route editor.")
|
||||||
RouteEditor routeWindow(outBoundRoot, this);
|
RouteEditor routeWindow(outBoundRoot, this);
|
||||||
root = routeWindow.OpenEditor();
|
root = routeWindow.OpenEditor();
|
||||||
isChanged = routeWindow.result() == QDialog::Accepted;
|
isChanged = routeWindow.result() == QDialog::Accepted;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "INFO: Opening single connection edit window.")
|
LOG(MODULE_UI, "INFO: Opening single connection edit window.")
|
||||||
auto out = OUTBOUND(outBoundRoot["outbounds"].toArray().first().toObject());
|
auto out = OUTBOUND(outBoundRoot["outbounds"].toArray().first().toObject());
|
||||||
OutboundEditor w(out, this);
|
OutboundEditor w(out, this);
|
||||||
@ -816,18 +869,21 @@ void MainWindow::OnEditRequested(const ConnectionId &id)
|
|||||||
root.insert("outbounds", outboundsList);
|
root.insert("outbounds", outboundsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChanged) {
|
if (isChanged)
|
||||||
//if (CheckConfigType(firstSelected, SUBSCRIPTION)) {
|
{
|
||||||
|
// if (CheckConfigType(firstSelected, SUBSCRIPTION)) {
|
||||||
// auto name = connections[_identifier].connectionName;
|
// auto name = connections[_identifier].connectionName;
|
||||||
// // Assume name will not change.
|
// // Assume name will not change.
|
||||||
// SaveSubscriptionConfig(root, connections[_identifier].subscriptionName, &name);
|
// SaveSubscriptionConfig(root,
|
||||||
|
// connections[_identifier].subscriptionName, &name);
|
||||||
//} else {
|
//} else {
|
||||||
// connections[_identifier].config = root;
|
// connections[_identifier].config = root;
|
||||||
// // true indicates the alias will NOT change
|
// // true indicates the alias will NOT change
|
||||||
// SaveConnectionConfig(root, &alias, true);
|
// SaveConnectionConfig(root, &alias, true);
|
||||||
//}
|
//}
|
||||||
ConnectionManager->UpdateConnection(id, root);
|
ConnectionManager->UpdateConnection(id, root);
|
||||||
//OnConfigListChanged(alias == CurrentConnectionIdentifier.connectionName);
|
// OnConfigListChanged(alias ==
|
||||||
|
// CurrentConnectionIdentifier.connectionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MainWindow::OnJsonEditRequested(const ConnectionId &id)
|
void MainWindow::OnJsonEditRequested(const ConnectionId &id)
|
||||||
@ -835,7 +891,5 @@ void MainWindow::OnJsonEditRequested(const ConnectionId &id)
|
|||||||
JsonEditor w(ConnectionManager->GetConnectionRoot(id), this);
|
JsonEditor w(ConnectionManager->GetConnectionRoot(id), this);
|
||||||
auto root = CONFIGROOT(w.OpenEditor());
|
auto root = CONFIGROOT(w.OpenEditor());
|
||||||
|
|
||||||
if (w.result() == QDialog::Accepted) {
|
if (w.result() == QDialog::Accepted) { ConnectionManager->UpdateConnection(id, root); }
|
||||||
ConnectionManager->UpdateConnection(id, root);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,114 +1,116 @@
|
|||||||
#pragma once
|
#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 <QMainWindow>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QSystemTrayIcon>
|
#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/ConnectionInfoWidget.hpp"
|
||||||
|
#include "ui/widgets/ConnectionItemWidget.hpp"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow, Ui::MainWindow
|
class MainWindow
|
||||||
|
: public QMainWindow
|
||||||
|
, Ui::MainWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget *parent = nullptr);
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
signals:
|
signals:
|
||||||
void Connect() const;
|
void Connect() const;
|
||||||
void DisConnect() const;
|
void DisConnect() const;
|
||||||
void ReConnect() const;
|
void ReConnect() const;
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
private slots:
|
private slots:
|
||||||
void on_action_RCM_ShareQR_triggered();
|
void on_action_RCM_ShareQR_triggered();
|
||||||
void on_activatedTray(QSystemTrayIcon::ActivationReason reason);
|
void on_activatedTray(QSystemTrayIcon::ActivationReason reason);
|
||||||
void on_actionExit_triggered();
|
void on_actionExit_triggered();
|
||||||
void on_preferencesBtn_clicked();
|
void on_preferencesBtn_clicked();
|
||||||
void on_clearlogButton_clicked();
|
void on_clearlogButton_clicked();
|
||||||
void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
|
void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
|
||||||
void on_connectionListWidget_customContextMenuRequested(const QPoint &pos);
|
void on_connectionListWidget_customContextMenuRequested(const QPoint &pos);
|
||||||
void on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int column);
|
void on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int column);
|
||||||
void on_removeConfigButton_clicked();
|
void on_removeConfigButton_clicked();
|
||||||
void on_importConfigButton_clicked();
|
void on_importConfigButton_clicked();
|
||||||
void on_editConfigButton_clicked();
|
void on_editConfigButton_clicked();
|
||||||
void on_subsButton_clicked();
|
void on_subsButton_clicked();
|
||||||
//
|
//
|
||||||
void ToggleVisibility();
|
void ToggleVisibility();
|
||||||
#ifndef DISABLE_AUTO_UPDATE
|
#ifndef DISABLE_AUTO_UPDATE
|
||||||
void VersionUpdate(QByteArray &data);
|
void VersionUpdate(QByteArray &data);
|
||||||
#endif
|
#endif
|
||||||
//
|
//
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static MainWindow *mwInstance;
|
static MainWindow *mwInstance;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
void closeEvent(QCloseEvent *) override;
|
void closeEvent(QCloseEvent *) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
//
|
//
|
||||||
void OnConnected(const ConnectionId &id);
|
void OnConnected(const ConnectionId &id);
|
||||||
void OnDisConnected(const ConnectionId &id);
|
void OnDisConnected(const ConnectionId &id);
|
||||||
void OnEditRequested(const ConnectionId &id);
|
void OnEditRequested(const ConnectionId &id);
|
||||||
void OnJsonEditRequested(const ConnectionId &id);
|
void OnJsonEditRequested(const ConnectionId &id);
|
||||||
|
|
||||||
void onConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
|
void onConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
|
||||||
//void onConnectionConnected(const ConnectionId &id);
|
// void onConnectionConnected(const ConnectionId &id);
|
||||||
//void onConnectionDisConnected(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 onConnectionStatsArrived(const ConnectionId &id, const quint64 upSpeed, const quint64 downSpeed, const quint64 totalUp,
|
||||||
void onVCoreLogArrived(const ConnectionId &id, const QString &log);
|
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_StartThis_triggered();
|
||||||
void on_action_RCM_ConvToComplex_triggered();
|
void on_action_RCM_EditJson_triggered();
|
||||||
void on_action_RCM_RenameConnection_triggered();
|
void on_action_RCM_ConvToComplex_triggered();
|
||||||
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
void on_action_RCM_RenameConnection_triggered();
|
||||||
void on_connectionFilterTxt_textEdited(const QString &arg1);
|
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||||
void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
|
void on_connectionFilterTxt_textEdited(const QString &arg1);
|
||||||
|
void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTreeWidgetItem *CurrentItem;
|
QTreeWidgetItem *CurrentItem;
|
||||||
// Charts
|
// Charts
|
||||||
SpeedWidget *speedChartWidget;
|
SpeedWidget *speedChartWidget;
|
||||||
QMenu *connectionListMenu;
|
QMenu *connectionListMenu;
|
||||||
#ifndef DISABLE_AUTO_UPDATE
|
#ifndef DISABLE_AUTO_UPDATE
|
||||||
QvHttpRequestHelper *requestHelper;
|
QvHttpRequestHelper *requestHelper;
|
||||||
#endif
|
#endif
|
||||||
QSystemTrayIcon hTray;
|
QSystemTrayIcon hTray;
|
||||||
//PACServer pacServer;
|
// PACServer pacServer;
|
||||||
//QvTCPingModel tcpingHelper;
|
// QvTCPingModel tcpingHelper;
|
||||||
SyntaxHighlighter *vCoreLogHighlighter;
|
SyntaxHighlighter *vCoreLogHighlighter;
|
||||||
ConnectionInfoWidget *infoWidget;
|
ConnectionInfoWidget *infoWidget;
|
||||||
//
|
//
|
||||||
// Actions in the system tray menu
|
// Actions in the system tray menu
|
||||||
//
|
//
|
||||||
QMenu *tray_RootMenu = new QMenu(this);
|
QMenu *tray_RootMenu = new QMenu(this);
|
||||||
QAction *action_Tray_ShowHide;
|
QAction *action_Tray_ShowHide;
|
||||||
QAction *action_Tray_ShowPreferencesWindow;
|
QAction *action_Tray_ShowPreferencesWindow;
|
||||||
QAction *action_Tray_Quit;
|
QAction *action_Tray_Quit;
|
||||||
// --> Connectivities
|
// --> Connectivities
|
||||||
QAction *action_Tray_Start;
|
QAction *action_Tray_Start;
|
||||||
QAction *action_Tray_Reconnect ;
|
QAction *action_Tray_Reconnect;
|
||||||
QAction *action_Tray_Stop;
|
QAction *action_Tray_Stop;
|
||||||
// --> System proxy settings
|
// --> System proxy settings
|
||||||
QMenu *tray_SystemProxyMenu = new QMenu(this);
|
QMenu *tray_SystemProxyMenu = new QMenu(this);
|
||||||
QAction *action_Tray_SetSystemProxy;
|
QAction *action_Tray_SetSystemProxy;
|
||||||
QAction *action_Tray_ClearSystemProxy;
|
QAction *action_Tray_ClearSystemProxy;
|
||||||
//
|
//
|
||||||
// ----------------------------------- Extra Headers For w_MainWindow_extra.cpp Handling V2ray Connectivities.
|
// ----------------------------------- Extra Headers For w_MainWindow_extra.cpp Handling V2ray Connectivities.
|
||||||
bool systemProxyEnabled;
|
bool systemProxyEnabled;
|
||||||
void MWSetSystemProxy();
|
void MWSetSystemProxy();
|
||||||
void MWClearSystemProxy(bool);
|
void MWClearSystemProxy(bool);
|
||||||
void CheckSubscriptionsUpdate();
|
void CheckSubscriptionsUpdate();
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
// Supplementary file for MainWindow -- Basically the handler for connectivity management
|
// Supplementary file for MainWindow -- Basically the handler for connectivity
|
||||||
// and components interactions.
|
// management and components interactions. We NEED to include the cpp file to
|
||||||
// We NEED to include the cpp file to define the macros.
|
// define the macros.
|
||||||
#include "w_MainWindow.cpp"
|
|
||||||
#include "components/proxy/QvProxyConfigurator.hpp"
|
#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.
|
// //// 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) {
|
// //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)
|
// // // -- name as our current connected name)
|
||||||
// // if (!IsConnectableItem(item)) {
|
// // if (!IsConnectableItem(item)) {
|
||||||
// // LOG(UI, "Invalid Item found: " + item->text(0))
|
// // LOG(UI, "Invalid Item found: " + item->text(0))
|
||||||
@ -25,8 +28,8 @@
|
|||||||
// // }
|
// // }
|
||||||
// //}
|
// //}
|
||||||
// //
|
// //
|
||||||
// //LOG(UI, "Warning: Failed to find an item named: " + identifier.IdentifierString())
|
// //LOG(UI, "Warning: Failed to find an item named: " +
|
||||||
// return nullptr;
|
// identifier.IdentifierString()) return nullptr;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void MainWindow::MWClearSystemProxy(bool showMessage)
|
void MainWindow::MWClearSystemProxy(bool showMessage)
|
||||||
@ -35,9 +38,7 @@ void MainWindow::MWClearSystemProxy(bool showMessage)
|
|||||||
LOG(MODULE_UI, "Clearing System Proxy")
|
LOG(MODULE_UI, "Clearing System Proxy")
|
||||||
systemProxyEnabled = false;
|
systemProxyEnabled = false;
|
||||||
|
|
||||||
if (showMessage) {
|
if (showMessage) { hTray.showMessage("Qv2ray", tr("System proxy cleared."), windowIcon()); }
|
||||||
hTray.showMessage("Qv2ray", tr("System proxy cleared."), windowIcon());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::MWSetSystemProxy()
|
void MainWindow::MWSetSystemProxy()
|
||||||
@ -48,45 +49,58 @@ void MainWindow::MWSetSystemProxy()
|
|||||||
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
|
bool socksEnabled = GlobalConfig.inboundConfig.useSocks;
|
||||||
//
|
//
|
||||||
// Set system proxy if necessary
|
// Set system proxy if necessary
|
||||||
//bool isComplex = IsComplexConfig(connections[CurrentConnectionIdentifier].config);
|
// bool isComplex =
|
||||||
|
// IsComplexConfig(connections[CurrentConnectionIdentifier].config);
|
||||||
bool isComplex = true;
|
bool isComplex = true;
|
||||||
|
|
||||||
if (!isComplex) {
|
if (!isComplex)
|
||||||
|
{
|
||||||
// Is simple config and we will try to set system proxy.
|
// Is simple config and we will try to set system proxy.
|
||||||
LOG(MODULE_UI, "Preparing to set system proxy")
|
LOG(MODULE_UI, "Preparing to set system proxy")
|
||||||
//
|
//
|
||||||
QString proxyAddress;
|
QString proxyAddress;
|
||||||
bool canSetSystemProxy = true;
|
bool canSetSystemProxy = true;
|
||||||
|
|
||||||
if (usePAC) {
|
if (usePAC)
|
||||||
if ((httpEnabled && !pacUseSocks) || (socksEnabled && pacUseSocks)) {
|
{
|
||||||
|
if ((httpEnabled && !pacUseSocks) || (socksEnabled && pacUseSocks))
|
||||||
|
{
|
||||||
// If we use PAC and socks/http are properly configured for PAC
|
// If we use PAC and socks/http are properly configured for PAC
|
||||||
LOG(MODULE_PROXY, "System proxy uses PAC")
|
LOG(MODULE_PROXY, "System proxy uses PAC")
|
||||||
proxyAddress = "http://" + GlobalConfig.inboundConfig.listenip + ":" + QSTRN(GlobalConfig.inboundConfig.pacConfig.port) + "/pac";
|
proxyAddress = "http://" + GlobalConfig.inboundConfig.listenip + ":" + QSTRN(GlobalConfig.inboundConfig.pacConfig.port) + "/pac";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Not properly configured
|
// Not properly configured
|
||||||
LOG(MODULE_PROXY, "Failed to process pac due to following reasons:")
|
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 configured to use socks but socks is not enabled.")
|
||||||
LOG(MODULE_PROXY, " --> PAC is configuted to use http but http 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") +
|
QvMessageBoxWarn(this, tr("PAC Processing Failed"),
|
||||||
NEWLINE + tr("Qv2ray will continue, but will not set system proxy."));
|
tr("HTTP or SOCKS inbound is not properly configured for PAC") + NEWLINE +
|
||||||
|
tr("Qv2ray will continue, but will not set system proxy."));
|
||||||
canSetSystemProxy = false;
|
canSetSystemProxy = false;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Not using PAC
|
// Not using PAC
|
||||||
if (httpEnabled || socksEnabled) {
|
if (httpEnabled || socksEnabled)
|
||||||
|
{
|
||||||
// Not use PAC, System proxy should use HTTP or SOCKS
|
// Not use PAC, System proxy should use HTTP or SOCKS
|
||||||
LOG(MODULE_PROXY, "Setting up system proxy.")
|
LOG(MODULE_PROXY, "Setting up system proxy.")
|
||||||
// A 'proxy host' should be a host WITHOUT `http://` uri scheme
|
// A 'proxy host' should be a host WITHOUT `http://` uri scheme
|
||||||
proxyAddress = "localhost";
|
proxyAddress = "localhost";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_PROXY, "Neither of HTTP nor SOCKS is enabled, cannot set system proxy.")
|
LOG(MODULE_PROXY, "Neither of HTTP nor SOCKS is enabled, cannot set system proxy.")
|
||||||
QvMessageBoxWarn(this, tr("Cannot set system proxy"), tr("Both HTTP and SOCKS inbounds are not enabled"));
|
QvMessageBoxWarn(this, tr("Cannot set system proxy"), tr("Both HTTP and SOCKS inbounds are not enabled"));
|
||||||
canSetSystemProxy = false;
|
canSetSystemProxy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canSetSystemProxy) {
|
if (canSetSystemProxy)
|
||||||
|
{
|
||||||
LOG(MODULE_UI, "Setting system proxy for simple config.")
|
LOG(MODULE_UI, "Setting system proxy for simple config.")
|
||||||
auto httpPort = GlobalConfig.inboundConfig.useHTTP ? GlobalConfig.inboundConfig.http_port : 0;
|
auto httpPort = GlobalConfig.inboundConfig.useHTTP ? GlobalConfig.inboundConfig.http_port : 0;
|
||||||
auto socksPort = GlobalConfig.inboundConfig.useSocks ? GlobalConfig.inboundConfig.socks_port : 0;
|
auto socksPort = GlobalConfig.inboundConfig.useSocks ? GlobalConfig.inboundConfig.socks_port : 0;
|
||||||
@ -96,7 +110,9 @@ void MainWindow::MWSetSystemProxy()
|
|||||||
systemProxyEnabled = true;
|
systemProxyEnabled = true;
|
||||||
hTray.showMessage("Qv2ray", tr("System proxy settings applied."), windowIcon());
|
hTray.showMessage("Qv2ray", tr("System proxy settings applied."), windowIcon());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
hTray.showMessage("Qv2ray", tr("Cannot set proxy for complex config."), windowIcon());
|
hTray.showMessage("Qv2ray", tr("Cannot set proxy for complex config."), windowIcon());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,28 +121,29 @@ void MainWindow::CheckSubscriptionsUpdate()
|
|||||||
{
|
{
|
||||||
QStringList updateList;
|
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 subs = GlobalConfig.subscriptions.values()[index];
|
||||||
auto key = GlobalConfig.subscriptions.keys()[index];
|
auto key = GlobalConfig.subscriptions.keys()[index];
|
||||||
//
|
//
|
||||||
auto lastRenewDate = QDateTime::fromTime_t(subs.lastUpdated);
|
auto lastRenewDate = QDateTime::fromTime_t(subs.lastUpdated);
|
||||||
auto renewTime = lastRenewDate.addSecs(subs.updateInterval * 86400);
|
auto renewTime = lastRenewDate.addSecs(subs.updateInterval * 86400);
|
||||||
LOG(MODULE_SUBSCRIPTION, "Subscription \"" + key + "\": " + NEWLINE +
|
LOG(MODULE_SUBSCRIPTION, "Subscription \"" + key + "\": " + NEWLINE + " --> Last renewal time: " + lastRenewDate.toString() + NEWLINE +
|
||||||
" --> Last renewal time: " + lastRenewDate.toString() + NEWLINE +
|
" --> Renew interval: " + QSTRN(subs.updateInterval) + NEWLINE +
|
||||||
" --> Renew interval: " + QSTRN(subs.updateInterval) + NEWLINE +
|
" --> Ideal renew time: " + renewTime.toString())
|
||||||
" --> Ideal renew time: " + renewTime.toString())
|
|
||||||
|
|
||||||
if (renewTime <= QDateTime::currentDateTime()) {
|
if (renewTime <= QDateTime::currentDateTime())
|
||||||
|
{
|
||||||
LOG(MODULE_SUBSCRIPTION, "Subscription: " + key + " needs to be updated.")
|
LOG(MODULE_SUBSCRIPTION, "Subscription: " + key + " needs to be updated.")
|
||||||
updateList.append(key);
|
updateList.append(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!updateList.isEmpty()) {
|
if (!updateList.isEmpty())
|
||||||
|
{
|
||||||
QvMessageBoxWarn(this, tr("Update Subscriptions"),
|
QvMessageBoxWarn(this, tr("Update Subscriptions"),
|
||||||
tr("There are subscriptions need to be updated, please go to subscriptions window to update them.") + NEWLINE + NEWLINE +
|
tr("There are subscriptions need to be updated, please go to subscriptions window to update them.") + NEWLINE +
|
||||||
tr("These subscriptions are out-of-date: ") + NEWLINE + updateList.join(";"));
|
NEWLINE + tr("These subscriptions are out-of-date: ") + NEWLINE + updateList.join(";"));
|
||||||
on_subsButton_clicked();
|
on_subsButton_clicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,28 @@
|
|||||||
#include "w_PreferencesWindow.hpp"
|
#include "w_PreferencesWindow.hpp"
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QColorDialog>
|
|
||||||
#include <QStyleFactory>
|
|
||||||
#include <QStyle>
|
|
||||||
#include <QDesktopServices>
|
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
|
||||||
#include "common/HTTPRequestHelper.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/config/ConfigBackend.hpp"
|
||||||
#include "core/connection/ConnectionIO.hpp"
|
#include "core/connection/ConnectionIO.hpp"
|
||||||
#include "core/kernel/KernelInteractions.hpp"
|
|
||||||
#include "core/handler/ConnectionHandler.hpp"
|
#include "core/handler/ConnectionHandler.hpp"
|
||||||
#include "components/plugins/toolbar/QvToolbar.hpp"
|
#include "core/kernel/KernelInteractions.hpp"
|
||||||
#include "components/autolaunch/QvAutoLaunch.hpp"
|
|
||||||
#include "common/QvTranslator.hpp"
|
#include <QColorDialog>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
|
||||||
using Qv2ray::common::validation::IsValidIPAddress;
|
using Qv2ray::common::validation::IsValidIPAddress;
|
||||||
|
|
||||||
#define LOADINGCHECK if(!finishedLoading) return;
|
#define LOADINGCHECK \
|
||||||
#define NEEDRESTART if(finishedLoading) IsConnectionPropertyChanged = true;
|
if (!finishedLoading) return;
|
||||||
|
#define NEEDRESTART \
|
||||||
|
if (finishedLoading) IsConnectionPropertyChanged = true;
|
||||||
|
|
||||||
PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
|
PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent), CurrentConfig()
|
||||||
CurrentConfig()
|
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
QvMessageBusConnect(PreferencesWindow);
|
QvMessageBusConnect(PreferencesWindow);
|
||||||
@ -31,17 +32,14 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
|
|||||||
// Set network Toolbar page state.
|
// Set network Toolbar page state.
|
||||||
networkToolbarPage->setEnabled(StartupOption.enableToolbarPlguin);
|
networkToolbarPage->setEnabled(StartupOption.enableToolbarPlguin);
|
||||||
|
|
||||||
if (!StartupOption.enableToolbarPlguin) {
|
if (!StartupOption.enableToolbarPlguin)
|
||||||
networkToolbarInfoLabel->setText(tr("Qv2ray Network Toolbar is disabled and still under test. Add --withToolbarPlugin to enable."));
|
{ networkToolbarInfoLabel->setText(tr("Qv2ray Network Toolbar is disabled and still under test. Add --withToolbarPlugin to enable.")); }
|
||||||
}
|
|
||||||
|
|
||||||
// We add locales
|
// We add locales
|
||||||
languageComboBox->clear();
|
languageComboBox->clear();
|
||||||
QDirIterator it(":/translations");
|
QDirIterator it(":/translations");
|
||||||
|
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) { languageComboBox->addItem(it.next().split("/").last().split(".").first()); }
|
||||||
languageComboBox->addItem(it.next().split("/").last().split(".").first());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set auto start button state
|
// Set auto start button state
|
||||||
SetAutoStartButtonsState(GetLaunchAtLoginStatus());
|
SetAutoStartButtonsState(GetLaunchAtLoginStatus());
|
||||||
@ -120,26 +118,30 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
|
|||||||
//
|
//
|
||||||
DNSListTxt->clear();
|
DNSListTxt->clear();
|
||||||
|
|
||||||
for (auto dnsStr : CurrentConfig.connectionConfig.dnsList) {
|
for (auto dnsStr : CurrentConfig.connectionConfig.dnsList)
|
||||||
|
{
|
||||||
auto str = dnsStr.trimmed();
|
auto str = dnsStr.trimmed();
|
||||||
|
|
||||||
if (!str.isEmpty()) {
|
if (!str.isEmpty()) { DNSListTxt->appendPlainText(str); }
|
||||||
DNSListTxt->appendPlainText(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
cancelIgnoreVersionBtn->setEnabled(CurrentConfig.ignoredVersion != "");
|
cancelIgnoreVersionBtn->setEnabled(CurrentConfig.ignoredVersion != "");
|
||||||
ignoredNextVersion->setText(CurrentConfig.ignoredVersion);
|
ignoredNextVersion->setText(CurrentConfig.ignoredVersion);
|
||||||
|
|
||||||
for (auto i = 0; i < CurrentConfig.toolBarConfig.Pages.size(); i++) {
|
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)"));
|
{
|
||||||
|
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);
|
nsBarPagesList->setCurrentRow(0);
|
||||||
on_nsBarPagesList_currentRowChanged(0);
|
on_nsBarPagesList_currentRowChanged(0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
networkToolbarSettingsFrame->setEnabled(false);
|
networkToolbarSettingsFrame->setEnabled(false);
|
||||||
nsBarLinesList->setEnabled(false);
|
nsBarLinesList->setEnabled(false);
|
||||||
nsBarLineDelBTN->setEnabled(false);
|
nsBarLineDelBTN->setEnabled(false);
|
||||||
@ -153,22 +155,17 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
|
|||||||
auto autoStartConnId = ConnectionId(CurrentConfig.autoStartId);
|
auto autoStartConnId = ConnectionId(CurrentConfig.autoStartId);
|
||||||
auto autoStartGroupId = ConnectionManager->GetConnectionGroupId(autoStartConnId);
|
auto autoStartGroupId = ConnectionManager->GetConnectionGroupId(autoStartConnId);
|
||||||
|
|
||||||
for (auto group : ConnectionManager->AllGroups()) {
|
for (auto group : ConnectionManager->AllGroups()) { autoStartSubsCombo->addItem(ConnectionManager->GetDisplayName(group)); }
|
||||||
autoStartSubsCombo->addItem(ConnectionManager->GetDisplayName(group));
|
|
||||||
}
|
|
||||||
|
|
||||||
autoStartSubsCombo->setCurrentText(ConnectionManager->GetDisplayName(autoStartGroupId));
|
autoStartSubsCombo->setCurrentText(ConnectionManager->GetDisplayName(autoStartGroupId));
|
||||||
|
|
||||||
for (auto conn : ConnectionManager->Connections(autoStartGroupId)) {
|
for (auto conn : ConnectionManager->Connections(autoStartGroupId)) { autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(conn)); }
|
||||||
autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
autoStartConnCombo->setCurrentText(ConnectionManager->GetDisplayName(autoStartConnId));
|
autoStartConnCombo->setCurrentText(ConnectionManager->GetDisplayName(autoStartConnId));
|
||||||
|
|
||||||
// FP Settings
|
// FP Settings
|
||||||
if (CurrentConfig.connectionConfig.forwardProxyConfig.type.trimmed().isEmpty()) {
|
if (CurrentConfig.connectionConfig.forwardProxyConfig.type.trimmed().isEmpty())
|
||||||
CurrentConfig.connectionConfig.forwardProxyConfig.type = "http";
|
{ CurrentConfig.connectionConfig.forwardProxyConfig.type = "http"; }
|
||||||
}
|
|
||||||
|
|
||||||
fpGroupBox->setChecked(CurrentConfig.connectionConfig.forwardProxyConfig.enableForwardProxy);
|
fpGroupBox->setChecked(CurrentConfig.connectionConfig.forwardProxyConfig.enableForwardProxy);
|
||||||
fpUsernameTx->setText(CurrentConfig.connectionConfig.forwardProxyConfig.username);
|
fpUsernameTx->setText(CurrentConfig.connectionConfig.forwardProxyConfig.username);
|
||||||
@ -182,18 +179,17 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent),
|
|||||||
//
|
//
|
||||||
maxLogLinesSB->setValue(CurrentConfig.uiConfig.maximumLogLines);
|
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;
|
finishedLoading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QvMessageBusSlotImpl(PreferencesWindow)
|
QvMessageBusSlotImpl(PreferencesWindow)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,45 +200,57 @@ PreferencesWindow::~PreferencesWindow()
|
|||||||
void PreferencesWindow::on_buttonBox_accepted()
|
void PreferencesWindow::on_buttonBox_accepted()
|
||||||
{
|
{
|
||||||
// Note:
|
// Note:
|
||||||
// A signal-slot connection from buttonbox_accpted to QDialog::accepted() has been removed.
|
// A signal-slot connection from buttonbox_accpted to QDialog::accepted()
|
||||||
// To prevent closing this Dialog.
|
// has been removed. To prevent closing this Dialog.
|
||||||
QSet<int> ports;
|
QSet<int> ports;
|
||||||
auto size = 0;
|
auto size = 0;
|
||||||
|
|
||||||
if (CurrentConfig.inboundConfig.useHTTP) {
|
if (CurrentConfig.inboundConfig.useHTTP)
|
||||||
size ++;
|
{
|
||||||
|
size++;
|
||||||
ports << CurrentConfig.inboundConfig.http_port;
|
ports << CurrentConfig.inboundConfig.http_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentConfig.inboundConfig.useSocks) {
|
if (CurrentConfig.inboundConfig.useSocks)
|
||||||
size ++;
|
{
|
||||||
|
size++;
|
||||||
ports << CurrentConfig.inboundConfig.socks_port;
|
ports << CurrentConfig.inboundConfig.socks_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentConfig.inboundConfig.pacConfig.enablePAC) {
|
if (CurrentConfig.inboundConfig.pacConfig.enablePAC)
|
||||||
size ++;
|
{
|
||||||
|
size++;
|
||||||
ports << CurrentConfig.inboundConfig.pacConfig.port;
|
ports << CurrentConfig.inboundConfig.pacConfig.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StartupOption.noAPI) {
|
if (!StartupOption.noAPI)
|
||||||
size ++;
|
{
|
||||||
|
size++;
|
||||||
ports << CurrentConfig.apiConfig.statsPort;
|
ports << CurrentConfig.apiConfig.statsPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ports.size() != size) {
|
if (ports.size() != size)
|
||||||
|
{
|
||||||
// Duplicates detected.
|
// Duplicates detected.
|
||||||
QvMessageBoxWarn(this, tr("Preferences"), tr("Duplicated port numbers detected, please check the port number settings."));
|
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.inboundConfig.listenip.toLower() != "localhost" && !IsValidIPAddress(CurrentConfig.inboundConfig.listenip))
|
||||||
} else {
|
{
|
||||||
if (CurrentConfig.uiConfig.language != GlobalConfig.uiConfig.language) {
|
QvMessageBoxWarn(this, tr("Preferences"), tr("Invalid inbound listening address."));
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CurrentConfig.uiConfig.language != GlobalConfig.uiConfig.language)
|
||||||
|
{
|
||||||
qApp->removeTranslator(Qv2rayTranslator.get());
|
qApp->removeTranslator(Qv2rayTranslator.get());
|
||||||
Qv2rayTranslator = std::move(QvTranslator(CurrentConfig.uiConfig.language).pTranslator);
|
Qv2rayTranslator = std::move(QvTranslator(CurrentConfig.uiConfig.language).pTranslator);
|
||||||
|
|
||||||
// Install translator
|
// Install translator
|
||||||
if (!qApp->installTranslator(Qv2rayTranslator.get())) {
|
if (!qApp->installTranslator(Qv2rayTranslator.get()))
|
||||||
LOG(MODULE_UI, "Failed to translate UI to: " + CurrentConfig.uiConfig.language)
|
{ LOG(MODULE_UI, "Failed to translate UI to: " + CurrentConfig.uiConfig.language) }
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
messageBus.EmitGlobalSignal(QvMBMessage::RETRANSLATE);
|
messageBus.EmitGlobalSignal(QvMBMessage::RETRANSLATE);
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
@ -296,13 +304,14 @@ void PreferencesWindow::on_listenIPTxt_textEdited(const QString &arg1)
|
|||||||
NEEDRESTART
|
NEEDRESTART
|
||||||
CurrentConfig.inboundConfig.listenip = arg1;
|
CurrentConfig.inboundConfig.listenip = arg1;
|
||||||
|
|
||||||
if (IsValidIPAddress(arg1)) {
|
if (IsValidIPAddress(arg1)) { BLACK(listenIPTxt) }
|
||||||
BLACK(listenIPTxt)
|
else
|
||||||
} else {
|
{
|
||||||
RED(listenIPTxt)
|
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)
|
void PreferencesWindow::on_httpAuthUsernameTxt_textEdited(const QString &arg1)
|
||||||
@ -346,7 +355,8 @@ void PreferencesWindow::on_selectVAssetBtn_clicked()
|
|||||||
NEEDRESTART
|
NEEDRESTART
|
||||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Open V2ray assets folder"), QDir::currentPath());
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Open V2ray assets folder"), QDir::currentPath());
|
||||||
|
|
||||||
if (!dir.isEmpty()) {
|
if (!dir.isEmpty())
|
||||||
|
{
|
||||||
vCoreAssetsPathTxt->setText(dir);
|
vCoreAssetsPathTxt->setText(dir);
|
||||||
on_vCoreAssetsPathTxt_textEdited(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());
|
QString core = QFileDialog::getOpenFileName(this, tr("Open V2ray core file"), QDir::currentPath());
|
||||||
|
|
||||||
if (!core.isEmpty()) {
|
if (!core.isEmpty())
|
||||||
|
{
|
||||||
vCorePathTxt->setText(core);
|
vCorePathTxt->setText(core);
|
||||||
on_vCorePathTxt_textEdited(core);
|
on_vCorePathTxt_textEdited(core);
|
||||||
}
|
}
|
||||||
@ -370,13 +381,17 @@ void PreferencesWindow::on_vCorePathTxt_textEdited(const QString &arg1)
|
|||||||
|
|
||||||
void PreferencesWindow::on_DNSListTxt_textChanged()
|
void PreferencesWindow::on_DNSListTxt_textChanged()
|
||||||
{
|
{
|
||||||
if (finishedLoading) {
|
if (finishedLoading)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
QStringList hosts = DNSListTxt->toPlainText().replace("\r", "").split("\n");
|
QStringList hosts = DNSListTxt->toPlainText().replace("\r", "").split("\n");
|
||||||
CurrentConfig.connectionConfig.dnsList.clear();
|
CurrentConfig.connectionConfig.dnsList.clear();
|
||||||
|
|
||||||
foreach (auto host, hosts) {
|
foreach (auto host, hosts)
|
||||||
if (host != "" && host != "\r") {
|
{
|
||||||
|
if (host != "" && host != "\r")
|
||||||
|
{
|
||||||
// Not empty, so we save.
|
// Not empty, so we save.
|
||||||
CurrentConfig.connectionConfig.dnsList.push_back(host);
|
CurrentConfig.connectionConfig.dnsList.push_back(host);
|
||||||
NEEDRESTART
|
NEEDRESTART
|
||||||
@ -384,7 +399,9 @@ void PreferencesWindow::on_DNSListTxt_textChanged()
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLACK(DNSListTxt)
|
BLACK(DNSListTxt)
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
RED(DNSListTxt)
|
RED(DNSListTxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -408,19 +425,25 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
|
|||||||
|
|
||||||
// Setting up tProxy for linux
|
// Setting up tProxy for linux
|
||||||
// Steps:
|
// 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.
|
// --> 2. Change GlobalConfig.v2CorePath.
|
||||||
// --> 3. Call `pkexec setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the V2ray core.
|
// --> 3. Call `pkexec setcap
|
||||||
if (arg1 == Qt::Checked) {
|
// CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the V2ray core.
|
||||||
|
if (arg1 == Qt::Checked)
|
||||||
|
{
|
||||||
// We enable it!
|
// We enable it!
|
||||||
if (QvMessageBoxAsk(this, tr("Enable tProxy Support"),
|
if (QvMessageBoxAsk(this, tr("Enable tProxy Support"),
|
||||||
tr("This will append capabilities to the V2ray executable.") + NEWLINE + NEWLINE +
|
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("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 +
|
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) {
|
" https://github.com/Qv2ray/Qv2ray/wiki/FAQ ") != QMessageBox::Yes)
|
||||||
|
{
|
||||||
tProxyCheckBox->setChecked(false);
|
tProxyCheckBox->setChecked(false);
|
||||||
LOG(MODULE_UI, "Canceled enabling tProxy feature.")
|
LOG(MODULE_UI, "Canceled enabling tProxy feature.")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, "ENABLING tProxy Support")
|
LOG(MODULE_VCORE, "ENABLING tProxy Support")
|
||||||
LOG(MODULE_FILEIO, " --> Origin V2ray core file is at: " + CurrentConfig.v2CorePath)
|
LOG(MODULE_FILEIO, " --> Origin V2ray core file is at: " + CurrentConfig.v2CorePath)
|
||||||
auto v2ctlPath = QFileInfo(CurrentConfig.v2CorePath).absolutePath() + "/v2ctl";
|
auto v2ctlPath = QFileInfo(CurrentConfig.v2CorePath).absolutePath() + "/v2ctl";
|
||||||
@ -433,17 +456,22 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
|
|||||||
//
|
//
|
||||||
LOG(MODULE_FILEIO, " --> Copying files....")
|
LOG(MODULE_FILEIO, " --> Copying files....")
|
||||||
|
|
||||||
if (QFileInfo(CurrentConfig.v2CorePath).absoluteFilePath() != QFileInfo(QV2RAY_TPROXY_VCORE_PATH).absoluteFilePath()) {
|
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...>
|
// 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) + ": File already exists.")
|
||||||
LOG(MODULE_FILEIO, QString(QV2RAY_TPROXY_VCORE_PATH) + ": Deleting file.")
|
LOG(MODULE_FILEIO, QString(QV2RAY_TPROXY_VCORE_PATH) + ": Deleting file.")
|
||||||
QFile(QV2RAY_TPROXY_VCORE_PATH).remove();
|
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 + ": File already exists.")
|
||||||
LOG(MODULE_FILEIO, QV2RAY_TPROXY_VCTL_PATH + ": Deleting file.")
|
LOG(MODULE_FILEIO, QV2RAY_TPROXY_VCTL_PATH + ": Deleting file.")
|
||||||
QFile(QV2RAY_TPROXY_VCTL_PATH).remove();
|
QFile(QV2RAY_TPROXY_VCTL_PATH).remove();
|
||||||
@ -456,18 +484,22 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
|
|||||||
LOG(MODULE_FILEIO, " --> V2ray Ctl: " + vCtlresult)
|
LOG(MODULE_FILEIO, " --> V2ray Ctl: " + vCtlresult)
|
||||||
//
|
//
|
||||||
|
|
||||||
if (vCoreresult == "OK" && vCtlresult == "OK") {
|
if (vCoreresult == "OK" && vCtlresult == "OK")
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, " --> Done copying files.")
|
LOG(MODULE_VCORE, " --> Done copying files.")
|
||||||
on_vCorePathTxt_textEdited(QV2RAY_TPROXY_VCORE_PATH);
|
on_vCorePathTxt_textEdited(QV2RAY_TPROXY_VCORE_PATH);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, "FAILED to copy V2ray files. Aborting.")
|
LOG(MODULE_VCORE, "FAILED to copy V2ray files. Aborting.")
|
||||||
QvMessageBoxWarn(this, tr("Enable tProxy Support"),
|
QvMessageBoxWarn(this, tr("Enable tProxy Support"),
|
||||||
tr("Qv2ray cannot copy one or both V2ray files from: ") + NEWLINE + NEWLINE +
|
tr("Qv2ray cannot copy one or both V2ray files from: ") + NEWLINE + NEWLINE + CurrentConfig.v2CorePath +
|
||||||
CurrentConfig.v2CorePath + NEWLINE + v2ctlPath + NEWLINE + NEWLINE +
|
NEWLINE + v2ctlPath + NEWLINE + NEWLINE + tr("to this path: ") + NEWLINE + newPath);
|
||||||
tr("to this path: ") + NEWLINE + newPath);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG(MODULE_VCORE, "Skipped removing files since the current V2ray core is in the default path.")
|
LOG(MODULE_VCORE, "Skipped removing files since the current V2ray core is in the default path.")
|
||||||
LOG(MODULE_VCORE, " --> Actually because we don't know where else to obtain the files.")
|
LOG(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...")
|
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);
|
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))
|
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."));
|
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;
|
CurrentConfig.tProxySupport = true;
|
||||||
NEEDRESTART
|
NEEDRESTART
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
int ret = QProcess::execute("pkexec setcap -r " + CurrentConfig.v2CorePath);
|
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))
|
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."));
|
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
|
NEEDRESTART
|
||||||
CurrentConfig.inboundConfig.socksLocalIP = arg1;
|
CurrentConfig.inboundConfig.socksLocalIP = arg1;
|
||||||
|
|
||||||
if (IsValidIPAddress(arg1)) {
|
if (IsValidIPAddress(arg1)) { BLACK(socksUDPIP) }
|
||||||
BLACK(socksUDPIP)
|
else
|
||||||
} else {
|
{
|
||||||
RED(socksUDPIP)
|
RED(socksUDPIP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------- NET SPEED PLUGIN OPERATIONS -----------------------------------------------------------------
|
// ------------------- NET SPEED PLUGIN OPERATIONS
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
#define CurrentBarPage CurrentConfig.toolBarConfig.Pages[this->CurrentBarPageId]
|
#define CurrentBarPage CurrentConfig.toolBarConfig.Pages[this->CurrentBarPageId]
|
||||||
#define CurrentBarLine CurrentBarPage.Lines[this->CurrentBarLineId]
|
#define CurrentBarLine CurrentBarPage.Lines[this->CurrentBarLineId]
|
||||||
@ -557,7 +594,7 @@ void PreferencesWindow::on_nsBarPageAddBTN_clicked()
|
|||||||
{
|
{
|
||||||
QvBarPage page;
|
QvBarPage page;
|
||||||
CurrentConfig.toolBarConfig.Pages.push_back(page);
|
CurrentConfig.toolBarConfig.Pages.push_back(page);
|
||||||
CurrentBarPageId = CurrentConfig.toolBarConfig.Pages.size() - 1 ;
|
CurrentBarPageId = CurrentConfig.toolBarConfig.Pages.size() - 1;
|
||||||
// Add default line.
|
// Add default line.
|
||||||
QvBarLine line;
|
QvBarLine line;
|
||||||
CurrentBarPage.Lines.push_back(line);
|
CurrentBarPage.Lines.push_back(line);
|
||||||
@ -576,11 +613,13 @@ void PreferencesWindow::on_nsBarPageAddBTN_clicked()
|
|||||||
|
|
||||||
void PreferencesWindow::on_nsBarPageDelBTN_clicked()
|
void PreferencesWindow::on_nsBarPageDelBTN_clicked()
|
||||||
{
|
{
|
||||||
if (nsBarPagesList->currentRow() >= 0) {
|
if (nsBarPagesList->currentRow() >= 0)
|
||||||
|
{
|
||||||
CurrentConfig.toolBarConfig.Pages.removeAt(nsBarPagesList->currentRow());
|
CurrentConfig.toolBarConfig.Pages.removeAt(nsBarPagesList->currentRow());
|
||||||
nsBarPagesList->takeItem(nsBarPagesList->currentRow());
|
nsBarPagesList->takeItem(nsBarPagesList->currentRow());
|
||||||
|
|
||||||
if (nsBarPagesList->count() <= 0) {
|
if (nsBarPagesList->count() <= 0)
|
||||||
|
{
|
||||||
nsBarPageDelBTN->setEnabled(false);
|
nsBarPageDelBTN->setEnabled(false);
|
||||||
nsBarLineAddBTN->setEnabled(false);
|
nsBarLineAddBTN->setEnabled(false);
|
||||||
nsBarLineDelBTN->setEnabled(false);
|
nsBarLineDelBTN->setEnabled(false);
|
||||||
@ -613,12 +652,14 @@ void PreferencesWindow::on_nsBarLineAddBTN_clicked()
|
|||||||
|
|
||||||
void PreferencesWindow::on_nsBarLineDelBTN_clicked()
|
void PreferencesWindow::on_nsBarLineDelBTN_clicked()
|
||||||
{
|
{
|
||||||
if (nsBarLinesList->currentRow() >= 0) {
|
if (nsBarLinesList->currentRow() >= 0)
|
||||||
|
{
|
||||||
CurrentBarPage.Lines.removeAt(nsBarLinesList->currentRow());
|
CurrentBarPage.Lines.removeAt(nsBarLinesList->currentRow());
|
||||||
nsBarLinesList->takeItem(nsBarLinesList->currentRow());
|
nsBarLinesList->takeItem(nsBarLinesList->currentRow());
|
||||||
CurrentBarLineId = 0;
|
CurrentBarLineId = 0;
|
||||||
|
|
||||||
if (nsBarLinesList->count() <= 0) {
|
if (nsBarLinesList->count() <= 0)
|
||||||
|
{
|
||||||
networkToolbarSettingsFrame->setEnabled(false);
|
networkToolbarSettingsFrame->setEnabled(false);
|
||||||
nsBarLineDelBTN->setEnabled(false);
|
nsBarLineDelBTN->setEnabled(false);
|
||||||
}
|
}
|
||||||
@ -639,15 +680,19 @@ void PreferencesWindow::on_nsBarPagesList_currentRowChanged(int currentRow)
|
|||||||
nsBarPageYOffset->setValue(CurrentBarPage.OffsetYpx);
|
nsBarPageYOffset->setValue(CurrentBarPage.OffsetYpx);
|
||||||
nsBarLinesList->clear();
|
nsBarLinesList->clear();
|
||||||
|
|
||||||
if (!CurrentBarPage.Lines.empty()) {
|
if (!CurrentBarPage.Lines.empty())
|
||||||
for (auto line : CurrentBarPage.Lines) {
|
{
|
||||||
|
for (auto line : CurrentBarPage.Lines)
|
||||||
|
{
|
||||||
auto description = GetBarLineDescription(line);
|
auto description = GetBarLineDescription(line);
|
||||||
nsBarLinesList->addItem(description);
|
nsBarLinesList->addItem(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBarLinesList->setCurrentRow(0);
|
nsBarLinesList->setCurrentRow(0);
|
||||||
ShowLineParameters(CurrentBarLine);
|
ShowLineParameters(CurrentBarLine);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
networkToolbarSettingsFrame->setEnabled(false);
|
networkToolbarSettingsFrame->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -725,11 +770,9 @@ QString PreferencesWindow::GetBarLineDescription(QvBarLine barLine)
|
|||||||
QString result = "Empty";
|
QString result = "Empty";
|
||||||
result = NetSpeedPluginMessages[barLine.ContentType];
|
result = NetSpeedPluginMessages[barLine.ContentType];
|
||||||
|
|
||||||
if (barLine.ContentType == 0) {
|
if (barLine.ContentType == 0) { result += " (" + barLine.Message + ")"; }
|
||||||
result += " (" + barLine.Message + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result.append(barLine.Bold ? ", " + tr("Bold") : "");
|
result = result.append(barLine.Bold ? ", " + tr("Bold") : "");
|
||||||
result = result.append(barLine.Italic ? ", " + tr("Italic") : "");
|
result = result.append(barLine.Italic ? ", " + tr("Italic") : "");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -738,9 +781,7 @@ void PreferencesWindow::ShowLineParameters(QvBarLine &barLine)
|
|||||||
{
|
{
|
||||||
finishedLoading = false;
|
finishedLoading = false;
|
||||||
|
|
||||||
if (!barLine.Family.isEmpty()) {
|
if (!barLine.Family.isEmpty()) { fontComboBox->setCurrentFont(QFont(barLine.Family)); }
|
||||||
fontComboBox->setCurrentFont(QFont(barLine.Family));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
nsBarFontASB->setValue(barLine.ColorA);
|
nsBarFontASB->setValue(barLine.ColorA);
|
||||||
@ -749,10 +790,9 @@ void PreferencesWindow::ShowLineParameters(QvBarLine &barLine)
|
|||||||
nsBarFontRSB->setValue(barLine.ColorR);
|
nsBarFontRSB->setValue(barLine.ColorR);
|
||||||
//
|
//
|
||||||
QColor color = QColor::fromRgb(barLine.ColorR, barLine.ColorG, barLine.ColorB, barLine.ColorA);
|
QColor color = QColor::fromRgb(barLine.ColorR, barLine.ColorG, barLine.ColorB, barLine.ColorA);
|
||||||
QString s(QStringLiteral("background: #")
|
QString s(QStringLiteral("background: #") + ((color.red() < 16) ? "0" : "") + QString::number(color.red(), 16) +
|
||||||
+ ((color.red() < 16) ? "0" : "") + QString::number(color.red(), 16)
|
((color.green() < 16) ? "0" : "") + QString::number(color.green(), 16) + ((color.blue() < 16) ? "0" : "") +
|
||||||
+ ((color.green() < 16) ? "0" : "") + QString::number(color.green(), 16)
|
QString::number(color.blue(), 16) + ";");
|
||||||
+ ((color.blue() < 16) ? "0" : "") + QString::number(color.blue(), 16) + ";");
|
|
||||||
chooseColorBtn->setStyleSheet(s);
|
chooseColorBtn->setStyleSheet(s);
|
||||||
nsBarFontSizeSB->setValue(barLine.Size);
|
nsBarFontSizeSB->setValue(barLine.Size);
|
||||||
nsBarFontBoldCB->setChecked(barLine.Bold);
|
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);
|
QColorDialog d(QColor::fromRgb(CurrentBarLine.ColorR, CurrentBarLine.ColorG, CurrentBarLine.ColorB, CurrentBarLine.ColorA), this);
|
||||||
d.exec();
|
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);
|
d.selectedColor().getRgb(&CurrentBarLine.ColorR, &CurrentBarLine.ColorG, &CurrentBarLine.ColorB, &CurrentBarLine.ColorA);
|
||||||
ShowLineParameters(CurrentBarLine);
|
ShowLineParameters(CurrentBarLine);
|
||||||
SET_LINE_LIST_TEXT
|
SET_LINE_LIST_TEXT
|
||||||
@ -792,9 +833,10 @@ void PreferencesWindow::on_nsBarContentCombo_currentIndexChanged(const QString &
|
|||||||
|
|
||||||
void PreferencesWindow::on_applyNSBarSettingsBtn_clicked()
|
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.") +
|
if (QvMessageBoxAsk(this, tr("Apply network toolbar settings"),
|
||||||
NEWLINE +
|
tr("All other modified settings will be applied as well after this object.") + NEWLINE +
|
||||||
tr("Do you want to continue?")) == QMessageBox::Yes) {
|
tr("Do you want to continue?")) == QMessageBox::Yes)
|
||||||
|
{
|
||||||
auto conf = GlobalConfig;
|
auto conf = GlobalConfig;
|
||||||
conf.toolBarConfig = CurrentConfig.toolBarConfig;
|
conf.toolBarConfig = CurrentConfig.toolBarConfig;
|
||||||
SaveGlobalConfig(conf);
|
SaveGlobalConfig(conf);
|
||||||
@ -815,7 +857,8 @@ void PreferencesWindow::on_darkThemeCB_stateChanged(int arg1)
|
|||||||
#ifdef QV2RAY_USE_BUILTIN_DARKTHEME
|
#ifdef QV2RAY_USE_BUILTIN_DARKTHEME
|
||||||
themeCombo->setEnabled(arg1 != Qt::Checked);
|
themeCombo->setEnabled(arg1 != Qt::Checked);
|
||||||
|
|
||||||
if (arg1 == Qt::Checked) {
|
if (arg1 == Qt::Checked)
|
||||||
|
{
|
||||||
themeCombo->setCurrentIndex(QStyleFactory::keys().indexOf("Fusion"));
|
themeCombo->setCurrentIndex(QStyleFactory::keys().indexOf("Fusion"));
|
||||||
CurrentConfig.uiConfig.theme = "Fusion";
|
CurrentConfig.uiConfig.theme = "Fusion";
|
||||||
}
|
}
|
||||||
@ -840,7 +883,8 @@ void PreferencesWindow::on_pacGoBtn_clicked()
|
|||||||
LOG(MODULE_PROXY, "Downloading GFWList file.")
|
LOG(MODULE_PROXY, "Downloading GFWList file.")
|
||||||
bool withProxy = getGFWListWithProxyCB->isChecked();
|
bool withProxy = getGFWListWithProxyCB->isChecked();
|
||||||
|
|
||||||
switch (gfwListCB->currentIndex()) {
|
switch (gfwListCB->currentIndex())
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
gfwLocation = "https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt";
|
gfwLocation = "https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt";
|
||||||
fileContent = QString::fromUtf8(request.syncget(gfwLocation, withProxy));
|
fileContent = QString::fromUtf8(request.syncget(gfwLocation, withProxy));
|
||||||
@ -874,7 +918,8 @@ void PreferencesWindow::on_pacGoBtn_clicked()
|
|||||||
case 6:
|
case 6:
|
||||||
auto file = QFileDialog::getOpenFileName(this, tr("Select GFWList in base64"));
|
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."));
|
QvMessageBoxWarn(this, tr("Download GFWList"), tr("Operation is cancelled."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -888,9 +933,7 @@ void PreferencesWindow::on_pacGoBtn_clicked()
|
|||||||
pacGoBtn->setEnabled(true);
|
pacGoBtn->setEnabled(true);
|
||||||
gfwListCB->setEnabled(true);
|
gfwListCB->setEnabled(true);
|
||||||
|
|
||||||
if (!QDir(QV2RAY_RULES_DIR).exists()) {
|
if (!QDir(QV2RAY_RULES_DIR).exists()) { QDir(QV2RAY_RULES_DIR).mkpath(QV2RAY_RULES_DIR); }
|
||||||
QDir(QV2RAY_RULES_DIR).mkpath(QV2RAY_RULES_DIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringToFile(fileContent, QV2RAY_RULES_GFWLIST_PATH);
|
StringToFile(fileContent, QV2RAY_RULES_GFWLIST_PATH);
|
||||||
}
|
}
|
||||||
@ -900,7 +943,8 @@ void PreferencesWindow::on_pacPortSB_valueChanged(int arg1)
|
|||||||
LOADINGCHECK
|
LOADINGCHECK
|
||||||
NEEDRESTART
|
NEEDRESTART
|
||||||
CurrentConfig.inboundConfig.pacConfig.port = arg1;
|
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)
|
void PreferencesWindow::on_setSysProxyCB_stateChanged(int arg1)
|
||||||
@ -939,9 +983,7 @@ void PreferencesWindow::on_autoStartSubsCombo_currentIndexChanged(const QString
|
|||||||
auto list = ConnectionManager->Connections(groupId);
|
auto list = ConnectionManager->Connections(groupId);
|
||||||
autoStartConnCombo->clear();
|
autoStartConnCombo->clear();
|
||||||
|
|
||||||
for (auto id : list) {
|
for (auto id : list) { autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(id)); }
|
||||||
autoStartConnCombo->addItem(ConnectionManager->GetDisplayName(id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesWindow::on_autoStartConnCombo_currentIndexChanged(const QString &arg1)
|
void PreferencesWindow::on_autoStartConnCombo_currentIndexChanged(const QString &arg1)
|
||||||
@ -955,9 +997,7 @@ void PreferencesWindow::on_startWithLoginCB_stateChanged(int arg1)
|
|||||||
bool isEnabled = arg1 == Qt::Checked;
|
bool isEnabled = arg1 == Qt::Checked;
|
||||||
SetLaunchAtLoginStatus(isEnabled);
|
SetLaunchAtLoginStatus(isEnabled);
|
||||||
|
|
||||||
if (GetLaunchAtLoginStatus() != isEnabled) {
|
if (GetLaunchAtLoginStatus() != isEnabled) { QvMessageBoxWarn(this, tr("Start with boot"), tr("Failed to set auto start option.")); }
|
||||||
QvMessageBoxWarn(this, tr("Start with boot"), tr("Failed to set auto start option."));
|
|
||||||
}
|
|
||||||
|
|
||||||
SetAutoStartButtonsState(GetLaunchAtLoginStatus());
|
SetAutoStartButtonsState(GetLaunchAtLoginStatus());
|
||||||
}
|
}
|
||||||
@ -978,9 +1018,9 @@ void PreferencesWindow::on_fpAddressTx_textEdited(const QString &arg1)
|
|||||||
LOADINGCHECK
|
LOADINGCHECK
|
||||||
CurrentConfig.connectionConfig.forwardProxyConfig.serverAddress = arg1;
|
CurrentConfig.connectionConfig.forwardProxyConfig.serverAddress = arg1;
|
||||||
|
|
||||||
if (IsValidIPAddress(arg1)) {
|
if (IsValidIPAddress(arg1)) { BLACK(fpAddressTx) }
|
||||||
BLACK(fpAddressTx)
|
else
|
||||||
} else {
|
{
|
||||||
RED(fpAddressTx)
|
RED(fpAddressTx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1021,13 +1061,14 @@ void PreferencesWindow::on_pacProxyTxt_textChanged(const QString &arg1)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(arg1)
|
Q_UNUSED(arg1)
|
||||||
|
|
||||||
if (IsValidIPAddress(arg1)) {
|
if (IsValidIPAddress(arg1)) { BLACK(pacProxyTxt) }
|
||||||
BLACK(pacProxyTxt)
|
else
|
||||||
} else {
|
{
|
||||||
RED(pacProxyTxt)
|
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()
|
void PreferencesWindow::on_checkVCoreSettings_clicked()
|
||||||
@ -1036,11 +1077,12 @@ void PreferencesWindow::on_checkVCoreSettings_clicked()
|
|||||||
auto vAssetsPath = vCoreAssetsPathTxt->text();
|
auto vAssetsPath = vCoreAssetsPathTxt->text();
|
||||||
QString result;
|
QString result;
|
||||||
|
|
||||||
if (!V2rayKernelInstance::ValidateKernel(vcorePath, vAssetsPath, &result)) {
|
if (!V2rayKernelInstance::ValidateKernel(vcorePath, vAssetsPath, &result)) { QvMessageBoxWarn(this, tr("V2ray Core Settings"), result); }
|
||||||
QvMessageBoxWarn(this, tr("V2ray Core Settings"), result);
|
else
|
||||||
} else {
|
{
|
||||||
QvMessageBoxInfo(this, tr("V2ray Core Settings"), tr("V2ray path configuration check passed.") + NEWLINE + NEWLINE +
|
QvMessageBoxInfo(this, tr("V2ray Core Settings"),
|
||||||
tr("Current version of V2ray is: ") + NEWLINE + result);
|
tr("V2ray path configuration check passed.") + NEWLINE + NEWLINE + tr("Current version of V2ray is: ") + NEWLINE +
|
||||||
|
result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,180 +1,183 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include <ui_w_PreferencesWindow.h>
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "ui/messaging/QvMessageBus.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:
|
public:
|
||||||
explicit PreferencesWindow(QWidget *parent = nullptr);
|
explicit PreferencesWindow(QWidget *parent = nullptr);
|
||||||
~PreferencesWindow();
|
~PreferencesWindow();
|
||||||
signals:
|
signals:
|
||||||
void s_reload_config(bool need_restart);
|
void s_reload_config(bool need_restart);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_buttonBox_accepted();
|
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:
|
private:
|
||||||
void SetAutoStartButtonsState(bool isAutoStart);
|
void SetAutoStartButtonsState(bool isAutoStart);
|
||||||
// Set ui parameters for a line;
|
// Set ui parameters for a line;
|
||||||
void ShowLineParameters(QvBarLine &line);
|
void ShowLineParameters(QvBarLine &line);
|
||||||
QString GetBarLineDescription(QvBarLine line);
|
QString GetBarLineDescription(QvBarLine line);
|
||||||
//
|
//
|
||||||
int CurrentBarLineId;
|
int CurrentBarLineId;
|
||||||
int CurrentBarPageId;
|
int CurrentBarPageId;
|
||||||
//
|
//
|
||||||
bool IsConnectionPropertyChanged = false;
|
bool IsConnectionPropertyChanged = false;
|
||||||
bool finishedLoading = false;
|
bool finishedLoading = false;
|
||||||
Qv2rayConfig CurrentConfig;
|
Qv2rayConfig CurrentConfig;
|
||||||
};
|
};
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
#include "w_ScreenShot_Core.hpp"
|
#include "w_ScreenShot_Core.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QThread>
|
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#define QV2RAY_SCREENSHOT_DIM_RATIO 0.6f
|
#define QV2RAY_SCREENSHOT_DIM_RATIO 0.6f
|
||||||
|
|
||||||
ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubberBand::Rectangle, this))
|
ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubberBand::Rectangle, this))
|
||||||
{
|
{
|
||||||
setupUi(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"));
|
this->setStyle(QStyleFactory::create("Fusion"));
|
||||||
//
|
//
|
||||||
label->setAttribute(Qt::WA_TranslucentBackground);
|
label->setAttribute(Qt::WA_TranslucentBackground);
|
||||||
@ -30,8 +33,9 @@ ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubber
|
|||||||
QImage ScreenShotWindow::DoScreenShot()
|
QImage ScreenShotWindow::DoScreenShot()
|
||||||
{
|
{
|
||||||
LOG(MODULE_IMPORT, "We currently only support the current screen.")
|
LOG(MODULE_IMPORT, "We currently only support the current screen.")
|
||||||
// The msleep is the only solution which prevent capturing our windows again.
|
// The msleep is the only solution which prevent capturing our windows
|
||||||
// It works on KDE, https://www.qtcentre.org/threads/55708-Get-Desktop-Screenshot-Without-Application-Window-Being-Shown?p=248993#post248993
|
// 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);
|
QThread::msleep(100);
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
//
|
//
|
||||||
@ -45,8 +49,10 @@ QImage ScreenShotWindow::DoScreenShot()
|
|||||||
int r, g, b;
|
int r, g, b;
|
||||||
auto _xdesktopImg = desktopImage.toImage();
|
auto _xdesktopImg = desktopImage.toImage();
|
||||||
|
|
||||||
for (int i = 0; i < w; i++) {
|
for (int i = 0; i < w; i++)
|
||||||
for (int j = 0; j < h; j++) {
|
{
|
||||||
|
for (int j = 0; j < h; j++)
|
||||||
|
{
|
||||||
r = static_cast<int>(qRed(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
|
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);
|
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);
|
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());
|
imgH = abs(end.y() - origin.y());
|
||||||
imgX = origin.x() < end.x() ? origin.x() : end.x();
|
imgX = origin.x() < end.x() ? origin.x() : end.x();
|
||||||
imgY = origin.y() < end.y() ? origin.y() : end.y();
|
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);
|
rubber->setGeometry(imgX, imgY, imgW, imgH);
|
||||||
fg->setGeometry(rubber->geometry());
|
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);
|
fg->setPixmap(copied);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenShotWindow::event(QEvent *e)
|
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)
|
void ScreenShotWindow::keyPressEvent(QKeyEvent *e)
|
||||||
{
|
{
|
||||||
if (e->key() == Qt::Key_Escape) {
|
if (e->key() == Qt::Key_Escape) { reject(); }
|
||||||
reject();
|
else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
|
||||||
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
{
|
||||||
on_startBtn_clicked();
|
on_startBtn_clicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,13 +111,14 @@ void ScreenShotWindow::mousePressEvent(QMouseEvent *e)
|
|||||||
rubber->setGeometry(origin.x(), origin.y(), 0, 0);
|
rubber->setGeometry(origin.x(), origin.y(), 0, 0);
|
||||||
rubber->show();
|
rubber->show();
|
||||||
rubber->raise();
|
rubber->raise();
|
||||||
//label->hide();
|
// label->hide();
|
||||||
//startBtn->hide();
|
// startBtn->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
|
void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
if (e->buttons() & Qt::LeftButton) {
|
if (e->buttons() & Qt::LeftButton)
|
||||||
|
{
|
||||||
end = e->pos();
|
end = e->pos();
|
||||||
pSize();
|
pSize();
|
||||||
//
|
//
|
||||||
@ -120,15 +129,15 @@ void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
|
|||||||
QRect labelRect(label->contentsRect());
|
QRect labelRect(label->contentsRect());
|
||||||
QRect btnRect(startBtn->contentsRect());
|
QRect btnRect(startBtn->contentsRect());
|
||||||
|
|
||||||
if (imgY > labelRect.height()) {
|
if (imgY > labelRect.height()) { label->move(imgX, imgY - labelRect.height()); }
|
||||||
label->move(imgX, imgY - labelRect.height());
|
else
|
||||||
} else {
|
{
|
||||||
label->move(imgX, imgY);
|
label->move(imgX, imgY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height() - imgY - imgH > btnRect.height()) {
|
if (height() - imgY - imgH > btnRect.height()) { startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH); }
|
||||||
startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH);
|
else
|
||||||
} else {
|
{
|
||||||
startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH - btnRect.height());
|
startBtn->move(imgX + imgW - btnRect.width(), imgY + imgH - btnRect.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,12 +146,9 @@ void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScreenShotWindow::mouseReleaseEvent(QMouseEvent *e)
|
void ScreenShotWindow::mouseReleaseEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
if (e->button() == Qt::RightButton) {
|
if (e->button() == Qt::RightButton) { reject(); }
|
||||||
reject();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenShotWindow::~ScreenShotWindow()
|
ScreenShotWindow::~ScreenShotWindow()
|
||||||
|
@ -1,46 +1,48 @@
|
|||||||
#pragma once
|
#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"
|
#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:
|
public:
|
||||||
ScreenShotWindow();
|
ScreenShotWindow();
|
||||||
~ScreenShotWindow();
|
~ScreenShotWindow();
|
||||||
QImage DoScreenShot();
|
QImage DoScreenShot();
|
||||||
//
|
//
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *e) override;
|
bool event(QEvent *e) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_startBtn_clicked();
|
void on_startBtn_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRubberBand *rubber;
|
QRubberBand *rubber;
|
||||||
// Desktop Image
|
// Desktop Image
|
||||||
QPixmap desktopImage;
|
QPixmap desktopImage;
|
||||||
QImage windowBg;
|
QImage windowBg;
|
||||||
QImage resultImage;
|
QImage resultImage;
|
||||||
//
|
//
|
||||||
QPoint origin;
|
QPoint origin;
|
||||||
QPoint end;
|
QPoint end;
|
||||||
int imgW, imgH, imgX, imgY;
|
int imgW, imgH, imgX, imgY;
|
||||||
|
|
||||||
void pSize();
|
void pSize();
|
||||||
};
|
};
|
||||||
|
@ -1,33 +1,31 @@
|
|||||||
#include "w_SubscriptionManager.hpp"
|
#include "w_SubscriptionManager.hpp"
|
||||||
|
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
#include "core/config/ConfigBackend.hpp"
|
#include "core/config/ConfigBackend.hpp"
|
||||||
#include "core/handler/ConnectionHandler.hpp"
|
#include "core/handler/ConnectionHandler.hpp"
|
||||||
|
|
||||||
SubscribeEditor::SubscribeEditor(QWidget *parent) :
|
SubscribeEditor::SubscribeEditor(QWidget *parent) : QDialog(parent)
|
||||||
QDialog(parent)
|
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
QvMessageBusConnect(SubscribeEditor);
|
QvMessageBusConnect(SubscribeEditor);
|
||||||
addSubsButton->setIcon(QICON_R("add.png"));
|
addSubsButton->setIcon(QICON_R("add.png"));
|
||||||
removeSubsButton->setIcon(QICON_R("delete.png"));
|
removeSubsButton->setIcon(QICON_R("delete.png"));
|
||||||
|
|
||||||
for (auto subs : ConnectionManager->Subscriptions()) {
|
for (auto subs : ConnectionManager->Subscriptions())
|
||||||
subscriptionList->addTopLevelItem(new QTreeWidgetItem(QStringList() << ConnectionManager->GetDisplayName(subs) << subs.toString()));
|
{ subscriptionList->addTopLevelItem(new QTreeWidgetItem(QStringList() << ConnectionManager->GetDisplayName(subs) << subs.toString())); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QvMessageBusSlotImpl(SubscribeEditor)
|
QvMessageBusSlotImpl(SubscribeEditor)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg)
|
||||||
MBShowDefaultImpl
|
{
|
||||||
MBHideDefaultImpl
|
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl
|
||||||
MBRetranslateDefaultImpl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString, CONFIGROOT> SubscribeEditor::GetSelectedConfig()
|
QPair<QString, CONFIGROOT> SubscribeEditor::GetSelectedConfig()
|
||||||
{
|
{
|
||||||
return QPair<QString, CONFIGROOT> ();
|
return QPair<QString, CONFIGROOT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
SubscribeEditor::~SubscribeEditor()
|
SubscribeEditor::~SubscribeEditor()
|
||||||
@ -46,22 +44,26 @@ void SubscribeEditor::on_addSubsButton_clicked()
|
|||||||
|
|
||||||
void SubscribeEditor::on_updateButton_clicked()
|
void SubscribeEditor::on_updateButton_clicked()
|
||||||
{
|
{
|
||||||
//auto newName = subNameTxt->text().trimmed();
|
ConnectionManager->UpdateSubscription(currentSubId, withProxyCB->isChecked());
|
||||||
//auto newAddress = subAddrTxt->text().trimmed();
|
// auto newName = subNameTxt->text().trimmed();
|
||||||
//auto newUpdateInterval = updateIntervalSB->value();
|
// auto newAddress = subAddrTxt->text().trimmed();
|
||||||
//if (currentSubId != newName) {
|
// auto newUpdateInterval = updateIntervalSB->value();
|
||||||
|
// if (currentSubId != newName) {
|
||||||
// // Rename needed.
|
// // Rename needed.
|
||||||
// LOG(MODULE_SUBSCRIPTION, "Renaming a subscription, from " + currentSubId + " to: " + newName)
|
// LOG(MODULE_SUBSCRIPTION, "Renaming a subscription, from " +
|
||||||
// bool canGo = true;
|
// currentSubId + " to: " + newName) bool canGo = true;
|
||||||
//
|
//
|
||||||
// if (newName.isEmpty() || !IsValidFileName(newName)) {
|
// if (newName.isEmpty() || !IsValidFileName(newName)) {
|
||||||
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("The subscription name is invalid, please try another."));
|
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("The
|
||||||
// canGo = false;
|
// subscription name is invalid, please try another.")); canGo =
|
||||||
|
// false;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if (subscriptionList->findItems(newName, Qt::MatchExactly).count() > 0) {
|
// if (subscriptionList->findItems(newName, Qt::MatchExactly).count() >
|
||||||
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("New name of this subscription has been used already, please suggest another one"));
|
// 0) {
|
||||||
// canGo = false;
|
// QvMessageBoxWarn(this, tr("Renaming a subscription"), tr("New name
|
||||||
|
// of this subscription has been used already, please suggest another
|
||||||
|
// one")); canGo = false;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if (!canGo) {
|
// if (!canGo) {
|
||||||
@ -72,7 +74,8 @@ void SubscribeEditor::on_updateButton_clicked()
|
|||||||
// ////bool result = RenameSubscription(currentSubName, newName);
|
// ////bool result = RenameSubscription(currentSubName, newName);
|
||||||
// //
|
// //
|
||||||
// //if (!result) {
|
// //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;
|
// // return;
|
||||||
// //}
|
// //}
|
||||||
// subscriptions[newName] = subscriptions[currentSubId];
|
// subscriptions[newName] = subscriptions[currentSubId];
|
||||||
@ -93,68 +96,45 @@ void SubscribeEditor::on_updateButton_clicked()
|
|||||||
// // Update thing still down
|
// // Update thing still down
|
||||||
// subAddrTxt->setText(newAddress);
|
// subAddrTxt->setText(newAddress);
|
||||||
// updateIntervalSB->setValue(newUpdateInterval);
|
// 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) {
|
// if (subscriptions[currentSubId].address != newAddress) {
|
||||||
// LOG(MODULE_SUBSCRIPTION, "Setting new address, from " + subscriptions[currentSubId].address + " to: " + newAddress)
|
// LOG(MODULE_SUBSCRIPTION, "Setting new address, from " +
|
||||||
|
// subscriptions[currentSubId].address + " to: " + newAddress)
|
||||||
// subscriptions[currentSubId].address = newAddress;
|
// subscriptions[currentSubId].address = newAddress;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
////SaveConfig();
|
////SaveConfig();
|
||||||
//
|
//
|
||||||
////if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like to reload this subscription from the Url?")) == QMessageBox::Yes) {
|
////if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like
|
||||||
//// StartUpdateSubscription(currentSubId);
|
/// to reload this subscription from the Url?")) == QMessageBox::Yes) { /
|
||||||
|
/// StartUpdateSubscription(currentSubId);
|
||||||
////}
|
////}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscribeEditor::StartUpdateSubscription(const QString &subscriptionName)
|
void SubscribeEditor::StartUpdateSubscription(const QString &subscriptionName)
|
||||||
{
|
{
|
||||||
this->setEnabled(false);
|
this->setEnabled(false);
|
||||||
// auto data = helper.syncget(subscriptions[subscriptionName].address, withProxyCB->isChecked());
|
// auto data = helper.syncget(subscriptions[subscriptionName].address,
|
||||||
// auto content = DecodeSubscriptionString(data).trimmed();
|
// withProxyCB->isChecked()); auto content =
|
||||||
//if (!content.isEmpty()) {
|
|
||||||
// connectionsList->clear();
|
|
||||||
// auto vmessList = SplitLines(content);
|
|
||||||
// QDir(QV2RAY_SUBSCRIPTION_DIR + subscriptionName).removeRecursively();
|
|
||||||
// QDir().mkpath(QV2RAY_SUBSCRIPTION_DIR + subscriptionName);
|
|
||||||
//
|
|
||||||
// for (auto vmess : vmessList) {
|
|
||||||
// QString errMessage;
|
|
||||||
// QString _alias;
|
|
||||||
// auto config = ConvertConfigFromString(vmess.trimmed(), &_alias, &errMessage);
|
|
||||||
//
|
|
||||||
// if (!errMessage.isEmpty()) {
|
|
||||||
// LOG(MODULE_SUBSCRIPTION, "Processing a subscription with following error: " + errMessage)
|
|
||||||
// } else {
|
|
||||||
// //SaveSubscriptionConfig(config, subscriptionName, &_alias);
|
|
||||||
// connectionsList->addItem(_alias);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// subscriptions[subscriptionName].lastUpdated = system_clock::to_time_t(system_clock::now());
|
|
||||||
// lastUpdatedLabel->setText(timeToString(subscriptions[subscriptionName].lastUpdated));
|
|
||||||
// isUpdateInProgress = false;
|
|
||||||
//} else {
|
|
||||||
// LOG(MODULE_NETWORK, "We have received an empty string from the URL.")
|
|
||||||
// QvMessageBoxWarn(this, tr("Updating subscriptions"), tr("Failed to process the result from the upstream, please check your Url."));
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
this->setEnabled(true);
|
this->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscribeEditor::on_removeSubsButton_clicked()
|
void SubscribeEditor::on_removeSubsButton_clicked()
|
||||||
{
|
{
|
||||||
//if (subscriptionList->currentRow() < 0)
|
// if (subscriptionList->currentRow() < 0)
|
||||||
// return;
|
// return;
|
||||||
//
|
//
|
||||||
//auto name = subscriptionList->currentItem()->text();
|
// auto name = subscriptionList->currentItem()->text();
|
||||||
//subscriptionList->takeItem(subscriptionList->currentRow());
|
// subscriptionList->takeItem(subscriptionList->currentRow());
|
||||||
//subscriptions.remove(name);
|
// subscriptions.remove(name);
|
||||||
//
|
//
|
||||||
//if (!name.isEmpty()) {
|
// if (!name.isEmpty()) {
|
||||||
// QDir(QV2RAY_SUBSCRIPTION_DIR + name).removeRecursively();
|
// QDir(QV2RAY_SUBSCRIPTION_DIR + name).removeRecursively();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
@ -163,22 +143,22 @@ void SubscribeEditor::on_removeSubsButton_clicked()
|
|||||||
//// GlobalConfig.autoStartConfig = QvConnectionObject();
|
//// GlobalConfig.autoStartConfig = QvConnectionObject();
|
||||||
//// SaveGlobalConfig(GlobalConfig);
|
//// SaveGlobalConfig(GlobalConfig);
|
||||||
////}
|
////}
|
||||||
//groupBox_2->setEnabled(subscriptionList->count() > 0);
|
// groupBox_2->setEnabled(subscriptionList->count() > 0);
|
||||||
//SaveConfig();
|
// SaveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscribeEditor::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()) {
|
// if (!_.second.address.isEmpty()) {
|
||||||
// newConf[_.first] = _.second;
|
// newConf[_.first] = _.second;
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//GlobalConfig.subscriptions = newConf;
|
// GlobalConfig.subscriptions = newConf;
|
||||||
//SaveGlobalConfig(GlobalConfig);
|
// SaveGlobalConfig(GlobalConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscribeEditor::on_buttonBox_accepted()
|
void SubscribeEditor::on_buttonBox_accepted()
|
||||||
@ -195,9 +175,7 @@ void SubscribeEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int
|
|||||||
{
|
{
|
||||||
Q_UNUSED(column)
|
Q_UNUSED(column)
|
||||||
|
|
||||||
if (item == nullptr) {
|
if (item == nullptr) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSubId = GroupId(item->text(1));
|
currentSubId = GroupId(item->text(1));
|
||||||
//
|
//
|
||||||
@ -209,7 +187,5 @@ void SubscribeEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int
|
|||||||
//
|
//
|
||||||
connectionsList->clear();
|
connectionsList->clear();
|
||||||
|
|
||||||
for (auto conn : ConnectionManager->Connections(currentSubId)) {
|
for (auto conn : ConnectionManager->Connections(currentSubId)) { connectionsList->addItem(ConnectionManager->GetDisplayName(conn)); }
|
||||||
connectionsList->addItem(ConnectionManager->GetDisplayName(conn));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "ui_w_SubscriptionManager.h"
|
|
||||||
#include "ui/messaging/QvMessageBus.hpp"
|
|
||||||
#include "core/CoreSafeTypes.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:
|
public:
|
||||||
explicit SubscribeEditor(QWidget *parent = nullptr);
|
explicit SubscribeEditor(QWidget *parent = nullptr);
|
||||||
~SubscribeEditor();
|
~SubscribeEditor();
|
||||||
QPair<QString, CONFIGROOT> GetSelectedConfig();
|
QPair<QString, CONFIGROOT> GetSelectedConfig();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QvMessageBusSlotDecl
|
QvMessageBusSlotDecl;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_addSubsButton_clicked();
|
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:
|
private:
|
||||||
void StartUpdateSubscription(const QString &subscriptionName);
|
void StartUpdateSubscription(const QString &subscriptionName);
|
||||||
void SaveConfig();
|
void SaveConfig();
|
||||||
|
|
||||||
bool isUpdateInProgress = false;
|
bool isUpdateInProgress = false;
|
||||||
GroupId currentSubId = NullGroupId;
|
GroupId currentSubId = NullGroupId;
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#include "ConnectionInfoWidget.hpp"
|
#include "ConnectionInfoWidget.hpp"
|
||||||
|
|
||||||
|
#include "3rdparty/qzxing/src/QZXing.h"
|
||||||
#include "core/CoreUtils.hpp"
|
#include "core/CoreUtils.hpp"
|
||||||
#include "core/connection/Serialization.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);
|
setupUi(this);
|
||||||
duplicateBtn->setIcon(QICON_R("duplicate.png"));
|
duplicateBtn->setIcon(QICON_R("duplicate.png"));
|
||||||
@ -12,7 +13,8 @@ ConnectionInfoWidget::ConnectionInfoWidget(QWidget *parent): QWidget(parent)
|
|||||||
editJsonBtn->setIcon(QICON_R("json.png"));
|
editJsonBtn->setIcon(QICON_R("json.png"));
|
||||||
//
|
//
|
||||||
shareLinkTxt->setAutoFillBackground(true);
|
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->setCursor(QCursor(Qt::CursorShape::IBeamCursor));
|
||||||
shareLinkTxt->installEventFilter(this);
|
shareLinkTxt->installEventFilter(this);
|
||||||
//
|
//
|
||||||
@ -30,10 +32,12 @@ void ConnectionInfoWidget::ShowDetails(const tuple<GroupId, ConnectionId> &_iden
|
|||||||
duplicateBtn->setEnabled(isConnection);
|
duplicateBtn->setEnabled(isConnection);
|
||||||
editBtn->setEnabled(isConnection);
|
editBtn->setEnabled(isConnection);
|
||||||
|
|
||||||
if (isConnection) {
|
if (isConnection)
|
||||||
|
{
|
||||||
groupLabel->setText(ConnectionManager->GetDisplayName(groupId, 175));
|
groupLabel->setText(ConnectionManager->GetDisplayName(groupId, 175));
|
||||||
protocolLabel->setText(ConnectionManager->GetConnectionProtocolString(connectionId));
|
protocolLabel->setText(ConnectionManager->GetConnectionProtocolString(connectionId));
|
||||||
auto [host, port] = ConnectionManager->GetConnectionInfo(connectionId);
|
auto [protocol, host, port] = ConnectionManager->GetConnectionData(connectionId);
|
||||||
|
Q_UNUSED(protocol)
|
||||||
addressLabel->setText(host);
|
addressLabel->setText(host);
|
||||||
portLabel->setNum(port);
|
portLabel->setNum(port);
|
||||||
//
|
//
|
||||||
@ -48,7 +52,9 @@ void ConnectionInfoWidget::ShowDetails(const tuple<GroupId, ConnectionId> &_iden
|
|||||||
qrLabel->setPixmap(QPixmap::fromImage(img));
|
qrLabel->setPixmap(QPixmap::fromImage(img));
|
||||||
//
|
//
|
||||||
connectBtn->setIcon(ConnectionManager->IsConnected(connectionId) ? QICON_R("stop.png") : QICON_R("connect.png"));
|
connectBtn->setIcon(ConnectionManager->IsConnected(connectionId) ? QICON_R("stop.png") : QICON_R("connect.png"));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
connectBtn->setIcon(QICON_R("connect.png"));
|
connectBtn->setIcon(QICON_R("connect.png"));
|
||||||
groupLabel->setText(tr("N/A"));
|
groupLabel->setText(tr("N/A"));
|
||||||
protocolLabel->setText(tr("N/A"));
|
protocolLabel->setText(tr("N/A"));
|
||||||
@ -66,9 +72,9 @@ ConnectionInfoWidget::~ConnectionInfoWidget()
|
|||||||
|
|
||||||
void ConnectionInfoWidget::on_connectBtn_clicked()
|
void ConnectionInfoWidget::on_connectBtn_clicked()
|
||||||
{
|
{
|
||||||
if (ConnectionManager->IsConnected(connectionId)) {
|
if (ConnectionManager->IsConnected(connectionId)) { ConnectionManager->StopConnection(); }
|
||||||
ConnectionManager->StopConnection();
|
else
|
||||||
} else {
|
{
|
||||||
ConnectionManager->StartConnection(connectionId);
|
ConnectionManager->StartConnection(connectionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,11 +96,11 @@ void ConnectionInfoWidget::on_deleteBtn_clicked()
|
|||||||
|
|
||||||
bool ConnectionInfoWidget::eventFilter(QObject *object, QEvent *event)
|
bool ConnectionInfoWidget::eventFilter(QObject *object, QEvent *event)
|
||||||
{
|
{
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
if (event->type() == QEvent::MouseButtonRelease)
|
||||||
if (shareLinkTxt->underMouse()) {
|
{
|
||||||
if (!shareLinkTxt->hasSelectedText()) {
|
if (shareLinkTxt->underMouse())
|
||||||
shareLinkTxt->selectAll();
|
{
|
||||||
}
|
if (!shareLinkTxt->hasSelectedText()) { shareLinkTxt->selectAll(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,51 +109,50 @@ bool ConnectionInfoWidget::eventFilter(QObject *object, QEvent *event)
|
|||||||
|
|
||||||
void ConnectionInfoWidget::OnConnected(const ConnectionId &id)
|
void ConnectionInfoWidget::OnConnected(const ConnectionId &id)
|
||||||
{
|
{
|
||||||
if (connectionId == id) {
|
if (connectionId == id) { connectBtn->setIcon(QICON_R("stop.png")); }
|
||||||
connectBtn->setIcon(QICON_R("stop.png"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionInfoWidget::OnDisConnected(const ConnectionId &id)
|
void ConnectionInfoWidget::OnDisConnected(const ConnectionId &id)
|
||||||
{
|
{
|
||||||
if (connectionId == id) {
|
if (connectionId == id) { connectBtn->setIcon(QICON_R("connect.png")); }
|
||||||
connectBtn->setIcon(QICON_R("connect.png"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//MWTryPingConnection(CurrentConnectionIdentifier);
|
// MWTryPingConnection(CurrentConnectionIdentifier);
|
||||||
void ConnectionInfoWidget::on_duplicateBtn_clicked()
|
void ConnectionInfoWidget::on_duplicateBtn_clicked()
|
||||||
{
|
{
|
||||||
//QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
// QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
|
||||||
//if (!IsSelectionConnectable) {
|
// if (!IsSelectionConnectable) {
|
||||||
// return;
|
// return;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//auto selectedFirst = connectionListWidget->currentItem();
|
// auto selectedFirst = connectionListWidget->currentItem();
|
||||||
//auto _identifier = ItemConnectionIdentifier(selectedFirst);
|
// auto _identifier = ItemConnectionIdentifier(selectedFirst);
|
||||||
//SUBSCRIPTION_CONFIG_MODIFY_ASK(selectedFirst)
|
// SUBSCRIPTION_CONFIG_MODIFY_ASK(selectedFirst)
|
||||||
//CONFIGROOT conf;
|
// CONFIGROOT conf;
|
||||||
//// Alias may change.
|
//// Alias may change.
|
||||||
//QString alias = _identifier.connectionName;
|
// QString alias = _identifier.connectionName;
|
||||||
//bool isComplex = IsComplexConfig(connections[_identifier].config);
|
// bool isComplex = IsComplexConfig(connections[_identifier].config);
|
||||||
//
|
//
|
||||||
//if (connections[_identifier].configType == CONNECTION_REGULAR) {
|
// if (connections[_identifier].configType == CONNECTION_REGULAR) {
|
||||||
// conf = ConvertConfigFromFile(QV2RAY_CONFIG_DIR + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
|
// conf = ConvertConfigFromFile(QV2RAY_CONFIG_DIR +
|
||||||
|
// _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
|
||||||
//} else {
|
//} else {
|
||||||
// conf = ConvertConfigFromFile(QV2RAY_SUBSCRIPTION_DIR + _identifier.subscriptionName + "/" + _identifier.connectionName + QV2RAY_CONFIG_FILE_EXTENSION, isComplex);
|
// conf = ConvertConfigFromFile(QV2RAY_SUBSCRIPTION_DIR +
|
||||||
// alias = _identifier.subscriptionName + "_" + _identifier.connectionName;
|
// _identifier.subscriptionName + "/" + _identifier.connectionName +
|
||||||
|
// QV2RAY_CONFIG_FILE_EXTENSION, isComplex); alias =
|
||||||
|
// _identifier.subscriptionName + "_" + _identifier.connectionName;
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//SaveConnectionConfig(conf, &alias, false);
|
// SaveConnectionConfig(conf, &alias, false);
|
||||||
//GlobalConfig.configs.push_back(alias);
|
// GlobalConfig.configs.push_back(alias);
|
||||||
//SaveGlobalConfig(GlobalConfig);
|
// SaveGlobalConfig(GlobalConfig);
|
||||||
//this->OnConfigListChanged(false);}
|
// this->OnConfigListChanged(false);}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionInfoWidget::on_latencyBtn_clicked()
|
void ConnectionInfoWidget::on_latencyBtn_clicked()
|
||||||
{
|
{
|
||||||
if (connectionId != NullConnectionId) {
|
if (connectionId != NullConnectionId) { ConnectionManager->StartLatencyTest(connectionId); }
|
||||||
ConnectionManager->StartLatencyTest(connectionId);
|
else
|
||||||
} else {
|
{
|
||||||
ConnectionManager->StartLatencyTest(groupId);
|
ConnectionManager->StartLatencyTest(groupId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include "ui_ConnectionInfoWidget.h"
|
|
||||||
#include "core/handler/ConnectionHandler.hpp"
|
#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:
|
public:
|
||||||
explicit ConnectionInfoWidget(QWidget *parent = nullptr);
|
explicit ConnectionInfoWidget(QWidget *parent = nullptr);
|
||||||
void ShowDetails(const tuple<GroupId, ConnectionId> &_identifier);
|
void ShowDetails(const tuple<GroupId, ConnectionId> &_identifier);
|
||||||
~ConnectionInfoWidget();
|
~ConnectionInfoWidget();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void OnEditRequested(const ConnectionId &id);
|
void OnEditRequested(const ConnectionId &id);
|
||||||
void OnJsonEditRequested(const ConnectionId &id);
|
void OnJsonEditRequested(const ConnectionId &id);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_connectBtn_clicked();
|
void on_connectBtn_clicked();
|
||||||
void on_editBtn_clicked();
|
void on_editBtn_clicked();
|
||||||
void on_editJsonBtn_clicked();
|
void on_editJsonBtn_clicked();
|
||||||
void on_deleteBtn_clicked();
|
void on_deleteBtn_clicked();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *object, QEvent *event) override;
|
bool eventFilter(QObject *object, QEvent *event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void OnConnected(const ConnectionId &id);
|
void OnConnected(const ConnectionId &id);
|
||||||
void OnDisConnected(const ConnectionId &id);
|
void OnDisConnected(const ConnectionId &id);
|
||||||
void on_duplicateBtn_clicked();
|
void on_duplicateBtn_clicked();
|
||||||
void on_latencyBtn_clicked();
|
void on_latencyBtn_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConnectionId connectionId = NullConnectionId;
|
ConnectionId connectionId = NullConnectionId;
|
||||||
GroupId groupId = NullGroupId;
|
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