mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-21 11:20:49 +08:00
Merge branch 'dev' into dev-master
This commit is contained in:
commit
b9fdbdd1a4
4
.github/ISSUE_TEMPLATE/bug---english.md
vendored
4
.github/ISSUE_TEMPLATE/bug---english.md
vendored
@ -45,7 +45,7 @@ Please paste your Qv2ray log here:
|
||||
|
||||
<!-- Please check all the operating systems and installation sources that you confirmed to have problems. -->
|
||||
|
||||
### Open Preferences -> Aabout, and enter the following info
|
||||
### Open Preferences -> About, and enter the following info
|
||||
|
||||
```
|
||||
Version:
|
||||
@ -82,3 +82,5 @@ Extra build info:
|
||||
## Additional Info
|
||||
|
||||
<!-- Feel free to write down any info you consider helpful to resolve the bug. -->
|
||||
|
||||
*Please hide your server address and UUID if you wish to post the vmess string or your connection setting.*
|
||||
|
3
.github/ISSUE_TEMPLATE/bug.md
vendored
3
.github/ISSUE_TEMPLATE/bug.md
vendored
@ -82,3 +82,6 @@ assignees: ''
|
||||
## 附加信息
|
||||
|
||||
<!-- 你认为对修复 bug 有帮助的任何信息都可以在此写出来。 -->
|
||||
|
||||
*请注意打码隐私相关信息。*
|
||||
|
||||
|
18
.github/workflows/build-qv2ray-cmake.yml
vendored
18
.github/workflows/build-qv2ray-cmake.yml
vendored
@ -74,7 +74,7 @@ jobs:
|
||||
path: ../Qt
|
||||
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
|
||||
- name: Installing Qt - ${{ matrix.arch }}
|
||||
uses: jurplel/install-qt-action@v2.5.0
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ matrix.qt_version }}
|
||||
arch: ${{ matrix.qtarch }}
|
||||
@ -118,6 +118,7 @@ jobs:
|
||||
shell: bash
|
||||
if: matrix.platform == 'macos-latest'
|
||||
run: |
|
||||
sudo xcode-select -s "/Applications/Xcode_10.3.app"
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DDS_STORE_SCRIPT=ON
|
||||
@ -142,8 +143,8 @@ jobs:
|
||||
if: matrix.platform == 'ubuntu-16.04'
|
||||
shell: bash
|
||||
env:
|
||||
CC: /usr/bin/gcc-9
|
||||
CXX: /usr/bin/g++-9
|
||||
CC: /usr/bin/gcc-7
|
||||
CXX: /usr/bin/g++-7
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
@ -171,12 +172,23 @@ jobs:
|
||||
cd ..
|
||||
squashfs-root/AppRun AppDir/usr/share/applications/qv2ray.desktop -appimage -no-strip -always-overwrite
|
||||
mv ./Qv2ray*.AppImage ./Qv2ray.AppImage
|
||||
wget https://github.com/Qv2ray/Distribution/releases/download/0.0.0/fakeDeb.tar.gz
|
||||
tar xzf fakeDeb.tar.gz
|
||||
cd fakeDeb
|
||||
cp ../Qv2ray.AppImage opt/qv2ray/Qv2ray.AppImage
|
||||
dpkg-deb -b . ../qv2ray.deb
|
||||
- name: Linux - ${{ matrix.qt_version }} - Uploading artifact
|
||||
if: matrix.platform == 'ubuntu-16.04'
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: Qv2ray-${{ github.sha }}.linux-${{ matrix.arch }}.qt${{ matrix.qt_version }}.AppImage
|
||||
path: build/Qv2ray.AppImage
|
||||
- name: Linux - ${{ matrix.qt_version }} - Uploading debian package
|
||||
if: matrix.platform == 'ubuntu-16.04'
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: Qv2ray-${{ github.sha }}.linux-${{ matrix.arch }}.qt${{ matrix.qt_version }}.deb
|
||||
path: build/qv2ray.deb
|
||||
- name: Linux - ${{ matrix.qt_version }} - Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v1-release
|
||||
if: github.event_name == 'release' && matrix.platform == 'ubuntu-16.04' && matrix.qt_version == '5.14.2'
|
||||
|
28
.github/workflows/deb.yml
vendored
28
.github/workflows/deb.yml
vendored
@ -21,8 +21,9 @@ jobs:
|
||||
|
||||
linux:
|
||||
strategy:
|
||||
matrix:
|
||||
distro: [stable, unstable]
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro: [stable, unstable]
|
||||
needs: check_commit_msg
|
||||
if: ${{ !contains( needs.check_commit_msg.outputs.commit_message, 'NO_DEB') }}
|
||||
name: Debian ${{ matrix.distro }}
|
||||
@ -40,20 +41,39 @@ jobs:
|
||||
submodules: 'recursive'
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
apt-get install -y build-essential debhelper ninja-build libgrpc++-dev libprotobuf-dev protobuf-compiler-grpc qtbase5-dev qttools5-dev cmake pkg-config
|
||||
apt-get install -y build-essential devscripts reprepro debhelper ninja-build libgrpc++-dev libprotobuf-dev protobuf-compiler-grpc qtbase5-dev qttools5-dev cmake pkg-config qtdeclarative5-dev
|
||||
- name: Build
|
||||
run: |
|
||||
dch -l${{ matrix.distro }} -m 'Build against ${{ matrix.distro }}' -D ${{ matrix.distro }}
|
||||
dpkg-buildpackage -us -uc -i -b
|
||||
- name: Copy binary
|
||||
run: |
|
||||
cp ../qv2ray_*.deb ./
|
||||
- name: Sleep
|
||||
if: github.event_name == 'release' && matrix.distro == 'unstable'
|
||||
run: |
|
||||
sleep 120
|
||||
- name: Setup Repository
|
||||
if: github.event_name == 'release' && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc') && !contains(github.ref, 'pre')
|
||||
run: |
|
||||
git clone https://github.com/Qv2ray/debian.git archive
|
||||
echo ${{ secrets.DEBIAN_REPO_KEY }} | base64 -d > private.key
|
||||
gpg --import private.key
|
||||
cd archive
|
||||
git config --local user.name "${{ github.actor }}"
|
||||
git config --local user.email "${{ github.actor }}@users.noreply.github.com"
|
||||
git remote set-url origin https://${{ github.actor }}:${{ secrets.DEBIAN_REPO_TOKEN }}@github.com/Qv2ray/debian.git
|
||||
reprepro includedeb ${{ matrix.distro }} ../*.deb
|
||||
git add -A
|
||||
git commit -am 'update'
|
||||
git push origin master
|
||||
- name: Get package name
|
||||
id: get_package
|
||||
run: echo ::set-output name=NAME::$(basename qv2ray_*.deb)
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: qv2ray_${{ matrix.distro }}
|
||||
name: ${{ steps.get_package.outputs.NAME }}
|
||||
path: ${{ steps.get_package.outputs.NAME }}
|
||||
- name: Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v1-release
|
||||
|
2
.github/workflows/nsis.yml
vendored
2
.github/workflows/nsis.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
||||
path: ../Qt
|
||||
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
|
||||
- name: Installing Qt - ${{ matrix.arch }}
|
||||
uses: jurplel/install-qt-action@v2.5.0
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ matrix.qt_version }}
|
||||
arch: ${{ matrix.qtarch }}
|
||||
|
16
.gitmodules
vendored
16
.gitmodules
vendored
@ -1,6 +1,3 @@
|
||||
[submodule "3rdparty/x2struct"]
|
||||
path = 3rdparty/x2struct
|
||||
url = https://github.com/xyz347/x2struct
|
||||
[submodule "3rdparty/SingleApplication"]
|
||||
path = 3rdparty/SingleApplication
|
||||
url = https://github.com/itay-grudev/SingleApplication
|
||||
@ -16,6 +13,15 @@
|
||||
[submodule "3rdparty/zxing-cpp"]
|
||||
path = 3rdparty/zxing-cpp
|
||||
url = https://github.com/nu-book/zxing-cpp
|
||||
[submodule "src/components/plugins/interface"]
|
||||
path = src/components/plugins/interface
|
||||
[submodule "src/plugin-interface"]
|
||||
path = src/plugin-interface
|
||||
url = https://github.com/Qv2ray/QvPlugin-Interface/
|
||||
[submodule "libs/QJsonStruct"]
|
||||
path = libs/QJsonStruct
|
||||
url = https://github.com/Qv2ray/QJsonStruct
|
||||
[submodule "3rdparty/uistyles"]
|
||||
path = 3rdparty/uistyles
|
||||
url = https://github.com/Qv2ray/QvUIStyles
|
||||
[submodule "3rdparty/backward-cpp"]
|
||||
path = 3rdparty/backward-cpp
|
||||
url = https://github.com/bombela/backward-cpp
|
||||
|
21
.travis.yml
21
.travis.yml
@ -2,27 +2,8 @@ language: shell
|
||||
os: linux
|
||||
dist: bionic
|
||||
|
||||
env:
|
||||
global:
|
||||
- LC_ALL: C.UTF-8
|
||||
- LANG: C.UTF-8
|
||||
|
||||
addons:
|
||||
snaps:
|
||||
- name: snapcraft
|
||||
channel: stable
|
||||
confinement: classic
|
||||
- name: lxd
|
||||
channel: stable
|
||||
|
||||
script:
|
||||
- sudo apt-get autoremove lxd --purge
|
||||
- sudo /snap/bin/lxd waitready
|
||||
- sudo /snap/bin/lxd init --auto
|
||||
- sudo snapcraft --use-lxd
|
||||
|
||||
after_failure:
|
||||
- sudo journalctl -u snapd
|
||||
- echo Refreshing launchpad repository
|
||||
|
||||
deploy:
|
||||
- provider: launchpad
|
||||
|
2
3rdparty/QNodeEditor
vendored
2
3rdparty/QNodeEditor
vendored
@ -1 +1 @@
|
||||
Subproject commit db07dd4ffcbfdd62431584d499928e45b5864f40
|
||||
Subproject commit 427b6fe13049aae62855b893b524f17278e8c06f
|
2
3rdparty/SingleApplication
vendored
2
3rdparty/SingleApplication
vendored
@ -1 +1 @@
|
||||
Subproject commit 4baf2e74f64c9a6ce36d456491bb41d0f2ae999e
|
||||
Subproject commit bae7c331ca7203a242e4533ba859c0c6016521ba
|
1
3rdparty/backward-cpp
vendored
Submodule
1
3rdparty/backward-cpp
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 29e4061494e1ac4e40b2b09fd3e35c310ca137fc
|
1
3rdparty/uistyles
vendored
Submodule
1
3rdparty/uistyles
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ccbc5a7ec83229e18804bf6b650b181f5279ca74
|
1
3rdparty/x2struct
vendored
1
3rdparty/x2struct
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 4539764671509655370b2ff4fae90bfd8a12df40
|
2
3rdparty/zxing-cpp
vendored
2
3rdparty/zxing-cpp
vendored
@ -1 +1 @@
|
||||
Subproject commit 66cc26b25633cb7f1e20f2bf7711960c321e3a7b
|
||||
Subproject commit 6d40262e7293666909f7325075d452637f2fca75
|
427
CMakeLists.txt
427
CMakeLists.txt
@ -5,9 +5,7 @@ file(STRINGS "${CMAKE_SOURCE_DIR}/makespec/BUILDVERSION" QV2RAY_BUILD_VERSION)
|
||||
file(STRINGS "${CMAKE_SOURCE_DIR}/makespec/VERSIONSUFFIX" QV2RAY_VERSION_SUFFIX)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
math(EXPR QV2RAY_BUILD_VERSION "1 + ${QV2RAY_BUILD_VERSION}")
|
||||
message("Increasing BUILDVERSION")
|
||||
file(WRITE "${CMAKE_SOURCE_DIR}/makespec/BUILDVERSION" ${QV2RAY_BUILD_VERSION})
|
||||
add_definitions(-DNODE_DEBUG_DRAWING)
|
||||
endif()
|
||||
|
||||
set(QV2RAY_VERSION_STRING "${QV2RAY_VERSION}${QV2RAY_VERSION_SUFFIX}")
|
||||
@ -28,12 +26,30 @@ add_definitions(-DQV2RAY_VERSION_BUGFIX=${CPACK_PACKAGE_VERSION_PATCH})
|
||||
add_definitions(-DQV2RAY_VERSION_BUILD=${QV2RAY_BUILD_VERSION})
|
||||
|
||||
add_definitions(-DQV2RAY_VERSION_STRING="${QV2RAY_VERSION_STRING}")
|
||||
add_definitions(-DXTOSTRUCT_QT)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
find_package(Qt5 5.11 COMPONENTS Core Gui Widgets Network REQUIRED)
|
||||
if(ANDROID)
|
||||
include(${ANDROID_SDK}/android_openssl/CMakeLists.txt)
|
||||
endif()
|
||||
|
||||
set(QV2RAY_ONLY_USE_QML OFF CACHE BOOL "Only use QML when building Qv2ray")
|
||||
|
||||
if(QV2RAY_ONLY_USE_QML)
|
||||
find_package(Qt5 5.11 COMPONENTS Core Gui Network Qml Quick REQUIRED)
|
||||
set(QV2RAY_QT_LIBS Qt5::Core Qt5::Network Qt5::Quick Qt5::Qml Qt5::Gui)
|
||||
add_definitions(-DQV2RAY_QML)
|
||||
else()
|
||||
find_package(Qt5 5.11 COMPONENTS Core Gui Widgets Network REQUIRED)
|
||||
set(QV2RAY_QT_LIBS Qt5::Core Qt5::Network Qt5::Widgets Qt5::Gui)
|
||||
add_definitions(-DQV2RAY_QWIDGETS)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
@ -65,7 +81,7 @@ message(" ")
|
||||
if(WIN32)
|
||||
add_compile_options("/std:c++17")
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
add_definitions(-D_HAS_STD_BYTE=0 -D_WIN32_WINNT=0x600 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_WIN32_WINNT=0x600 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
set(GUI_TYPE WIN32)
|
||||
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
if(CMAKE_CL_64)
|
||||
@ -76,19 +92,68 @@ if(WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# ==================================================================================
|
||||
# Qv2ray Build Arguments
|
||||
# ==================================================================================
|
||||
set(QV2RAY_QNODEEDITOR_PROVIDER "module" CACHE STRING "qnodeeditor provider")
|
||||
set(QV2RAY_ZXING_PROVIDER "module" CACHE STRING "zxing-cpp provider")
|
||||
if (ANDROID)
|
||||
else()
|
||||
set(QV2RAY_SINGLEAPPLICATION_PROVIDER "module" CACHE STRING "SingleApplication provider")
|
||||
endif()
|
||||
set(QV2RAY_DEFAULT_VASSETS_PATH "unset" CACHE STRING "v2ray assets path")
|
||||
set(QV2RAY_DEFAULT_VCORE_PATH "unset" CACHE STRING "v2ray core path")
|
||||
set(QV2RAY_TRANSLATION_PATH "unset" CACHE STRING "Qv2ray translations path")
|
||||
set(QV2RAY_DISABLE_AUTO_UPDATE OFF CACHE BOOL "Disable update checker")
|
||||
set(BUILD_TESTING OFF CACHE BOOL "Build test")
|
||||
set(EMBED_TRANSLATIONS OFF CACHE BOOL "Embed translations")
|
||||
set(QV2RAY_AUTO_DEPLOY ON CACHE BOOL "Automatically run deploy command after build")
|
||||
|
||||
if(QV2RAY_DEFAULT_VASSETS_PATH AND NOT QV2RAY_DEFAULT_VASSETS_PATH STREQUAL "unset")
|
||||
add_definitions(-DQV2RAY_DEFAULT_VASSETS_PATH="${QV2RAY_DEFAULT_VASSETS_PATH}")
|
||||
endif()
|
||||
|
||||
if(QV2RAY_DEFAULT_VCORE_PATH AND NOT QV2RAY_DEFAULT_VCORE_PATH STREQUAL "unset")
|
||||
add_definitions(-DQV2RAY_DEFAULT_VCORE_PATH="${QV2RAY_DEFAULT_VCORE_PATH}")
|
||||
endif()
|
||||
|
||||
if(QV2RAY_TRANSLATION_PATH AND NOT QV2RAY_TRANSLATION_PATH STREQUAL "unset")
|
||||
add_definitions(-DQV2RAY_TRANSLATION_PATH="${QV2RAY_TRANSLATION_PATH}")
|
||||
endif()
|
||||
|
||||
if(QV2RAY_DISABLE_AUTO_UPDATE)
|
||||
add_definitions(-DDISABLE_AUTO_UPDATE)
|
||||
endif()
|
||||
|
||||
if(FALL_BACK_TO_XDG_OPEN)
|
||||
add_definitions(-DFALL_BACK_TO_XDG_OPEN)
|
||||
endif()
|
||||
|
||||
if(EMBED_TRANSLATIONS)
|
||||
add_definitions(-DEMBED_TRANSLATIONS)
|
||||
configure_file(translations/translations.qrc ${CMAKE_BINARY_DIR} COPYONLY)
|
||||
set(QV2RAY_EMBED_TRANSLATION_QRC ${CMAKE_BINARY_DIR}/translations.qrc)
|
||||
endif()
|
||||
|
||||
|
||||
# ==================================================================================
|
||||
# 3rdparty Sources
|
||||
# ==================================================================================
|
||||
include(cmake/translations.cmake)
|
||||
include(cmake/qnodeeditor.cmake)
|
||||
include(cmake/singleapplication.cmake)
|
||||
include(cmake/protobuf.cmake)
|
||||
include(cmake/cpp-httplib.cmake)
|
||||
include(cmake/backend.cmake)
|
||||
if (ANDROID)
|
||||
else()
|
||||
include(cmake/singleapplication.cmake)
|
||||
include(cmake/protobuf.cmake)
|
||||
include(cmake/backend.cmake)
|
||||
endif()
|
||||
include(cmake/zxing-cpp.cmake)
|
||||
include(cmake/libsemver.cmake)
|
||||
|
||||
|
||||
# ==================================================================================
|
||||
# Qv2ray Build Info
|
||||
# ==================================================================================
|
||||
if(QV2RAY_BUILD_INFO)
|
||||
set(_QV2RAY_BUILD_INFO_STR_ "${QV2RAY_BUILD_INFO}")
|
||||
elseif(DEFINED ENV{_QV2RAY_BUILD_INFO_})
|
||||
@ -105,264 +170,130 @@ else()
|
||||
set(_QV2RAY_BUILD_EXTRA_INFO_STR_ "Qv2ray ${QV2RAY_VERSION_STRING}:${QV2RAY_BUILD_VERSION}")
|
||||
endif()
|
||||
|
||||
set(QV2RAY_BUILD_INFO ${_QV2RAY_BUILD_INFO_STR_} CACHE STRING "Qv2ray build info")
|
||||
set(QV2RAY_BUILD_EXTRA_INFO ${_QV2RAY_BUILD_EXTRA_INFO_STR_} CACHE STRING "Qv2ray build extra info")
|
||||
set(QV2RAY_BUILD_INFO ${_QV2RAY_BUILD_INFO_STR_})
|
||||
set(QV2RAY_BUILD_EXTRA_INFO ${_QV2RAY_BUILD_EXTRA_INFO_STR_})
|
||||
|
||||
add_definitions(-D_QV2RAY_BUILD_INFO_STR_="${_QV2RAY_BUILD_INFO_STR_}")
|
||||
add_definitions(-D_QV2RAY_BUILD_EXTRA_INFO_STR_="${_QV2RAY_BUILD_EXTRA_INFO_STR_}")
|
||||
message("Qv2ray build info: ${_QV2RAY_BUILD_INFO_STR_}")
|
||||
message("Qv2ray build info ex: ${_QV2RAY_BUILD_EXTRA_INFO_STR_}")
|
||||
|
||||
set(QV2RAY_DEFAULT_VASSETS_PATH "unset" CACHE STRING "v2ray assets path")
|
||||
set(QV2RAY_DEFAULT_VCORE_PATH "unset" CACHE STRING "v2ray core path")
|
||||
set(QV2RAY_TRANSLATION_PATH "unset" CACHE STRING "Qv2ray translations path")
|
||||
set(QV2RAY_DISABLE_AUTO_UPDATE OFF CACHE BOOL "Disable update checker")
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(QV2RAY_USE_BUILTIN_DARKTHEME OFF CACHE BOOL "Use built-in dark theme instead of followed by the system settings")
|
||||
else()
|
||||
set(QV2RAY_USE_BUILTIN_DARKTHEME ON CACHE BOOL "Use built-in dark theme instead of followed by the system settings")
|
||||
endif()
|
||||
set(EMBED_TRANSLATIONS OFF CACHE BOOL "Embed translations")
|
||||
|
||||
if(QV2RAY_DEFAULT_VASSETS_PATH AND NOT QV2RAY_DEFAULT_VASSETS_PATH STREQUAL "unset")
|
||||
add_definitions(-DQV2RAY_DEFAULT_VASSETS_PATH="${QV2RAY_DEFAULT_VASSETS_PATH}")
|
||||
endif()
|
||||
# ==================================================================================
|
||||
# Plugin Interface Headers
|
||||
# ==================================================================================
|
||||
set(QVPLUGIN_INTERFACE_INCLUDE_DIR "src/plugin-interface")
|
||||
include(src/plugin-interface/QvPluginInterface.cmake)
|
||||
|
||||
if(QV2RAY_DEFAULT_VCORE_PATH AND NOT QV2RAY_DEFAULT_VCORE_PATH STREQUAL "unset")
|
||||
add_definitions(-DQV2RAY_DEFAULT_VCORE_PATH="${QV2RAY_DEFAULT_VCORE_PATH}")
|
||||
endif()
|
||||
|
||||
if(QV2RAY_TRANSLATION_PATH AND NOT QV2RAY_TRANSLATION_PATH STREQUAL "unset")
|
||||
add_definitions(-DQV2RAY_TRANSLATION_PATH="${QV2RAY_TRANSLATION_PATH}")
|
||||
endif()
|
||||
# ==================================================================================
|
||||
# Qv2ray Sources and Headers
|
||||
# ==================================================================================
|
||||
include(cmake/components/qv2ray-lib.cmake)
|
||||
include(cmake/components/qv2ray-ui.cmake)
|
||||
include(3rdparty/uistyles/uistyles.cmake)
|
||||
|
||||
if(QV2RAY_USE_BUILTIN_DARKTHEME)
|
||||
add_definitions(-DQV2RAY_USE_BUILTIN_DARKTHEME=true)
|
||||
endif()
|
||||
set(QRC_RESOURCES
|
||||
${UISTYLE_QRCS}
|
||||
${CMAKE_SOURCE_DIR}/resources.qrc)
|
||||
|
||||
if(QV2RAY_DISABLE_AUTO_UPDATE)
|
||||
add_definitions(-DDISABLE_AUTO_UPDATE)
|
||||
endif()
|
||||
|
||||
set(QVPLUGIN_INTERFACE_INCLUDE_DIR "src/components/plugins/interface")
|
||||
include(src/components/plugins/interface/QvPluginInterface.cmake)
|
||||
|
||||
set(QV2RAY_SOURCES
|
||||
# Qv2ray baselib
|
||||
add_library(qv2ray-baselib STATIC
|
||||
${QV2RAY_BASE_HEADERS}
|
||||
${QV2RAY_LIB_SOURCES}
|
||||
${QVPLUGIN_INTERFACE_HEADERS}
|
||||
3rdparty/libsemver/version.cpp
|
||||
src/base/Qv2rayLog.cpp
|
||||
src/common/CommandArgs.cpp
|
||||
src/common/HTTPRequestHelper.cpp
|
||||
src/common/LogHighlighter.cpp
|
||||
src/common/JsonHighlighter.cpp
|
||||
src/common/QJsonModel.cpp
|
||||
src/common/QvHelpers.cpp
|
||||
src/common/QvTranslator.cpp
|
||||
src/common/QRCodeHelper.cpp
|
||||
src/components/autolaunch/QvAutoLaunch.cpp
|
||||
src/components/geosite/QvGeositeReader.cpp
|
||||
src/components/latency/win/ICMPPinger.cpp
|
||||
src/components/latency/QvTCPing.cpp
|
||||
src/components/plugins/toolbar/QvToolbar.cpp
|
||||
src/components/plugins/toolbar/QvToolbar_linux.cpp
|
||||
src/components/plugins/toolbar/QvToolbar_win.cpp
|
||||
src/components/plugins/QvPluginHost.cpp
|
||||
src/components/proxy/QvProxyConfigurator.cpp
|
||||
src/components/route/RouteSchemeIO.cpp
|
||||
src/components/speedchart/speedplotview.cpp
|
||||
src/components/speedchart/speedwidget.cpp
|
||||
src/components/darkmode/DarkmodeDetector.cpp
|
||||
src/components/update/UpdateChecker.cpp
|
||||
src/core/connection/ConnectionIO.cpp
|
||||
src/core/connection/Generation.cpp
|
||||
src/core/connection/Serialization.cpp
|
||||
src/core/connection/Serialization_ss.cpp
|
||||
src/core/connection/Serialization_ssd.cpp
|
||||
src/core/connection/Serialization_vmess.cpp
|
||||
src/core/CoreUtils.cpp
|
||||
src/core/handler/ConfigHandler.cpp
|
||||
src/core/handler/KernelInstanceHandler.cpp
|
||||
src/core/kernel/APIBackend.cpp
|
||||
src/core/kernel/V2rayKernelInteractions.cpp
|
||||
src/core/kernel/PluginKernelInteractions.cpp
|
||||
src/core/kernel/QvKernelABIChecker.cpp
|
||||
src/core/settings/SettingsBackend.cpp
|
||||
src/core/settings/SettingsUpgrade.cpp
|
||||
src/main.cpp
|
||||
src/ui/editors/w_InboundEditor.cpp
|
||||
src/ui/editors/w_JsonEditor.cpp
|
||||
src/ui/editors/w_OutboundEditor.cpp
|
||||
src/ui/editors/w_RoutesEditor.cpp
|
||||
src/ui/editors/w_RoutesEditor_extra.cpp
|
||||
src/ui/messaging/QvMessageBus.cpp
|
||||
src/ui/models/InboundNodeModel.cpp
|
||||
src/ui/models/OutboundNodeModel.cpp
|
||||
src/ui/models/RuleNodeModel.cpp
|
||||
src/ui/widgets/ConnectionInfoWidget.cpp
|
||||
src/ui/widgets/ConnectionItemWidget.cpp
|
||||
src/ui/widgets/QvAutoCompleteTextEdit.cpp
|
||||
src/ui/widgets/StreamSettingsWidget.cpp
|
||||
src/ui/widgets/RouteSettingsMatrix.cpp
|
||||
src/ui/w_ImportConfig.cpp
|
||||
src/ui/w_MainWindow.cpp
|
||||
src/ui/w_MainWindow_extra.cpp
|
||||
src/ui/w_PreferencesWindow.cpp
|
||||
src/ui/w_PluginManager.cpp
|
||||
src/ui/w_ScreenShot_Core.cpp
|
||||
src/ui/w_SubscriptionManager.cpp
|
||||
# ui files
|
||||
src/ui/w_SubscriptionManager.ui
|
||||
src/ui/editors/w_OutboundEditor.ui
|
||||
src/ui/editors/w_InboundEditor.ui
|
||||
src/ui/editors/w_JsonEditor.ui
|
||||
src/ui/editors/w_RoutesEditor.ui
|
||||
src/ui/w_ImportConfig.ui
|
||||
src/ui/widgets/StreamSettingsWidget.ui
|
||||
src/ui/widgets/ConnectionInfoWidget.ui
|
||||
src/ui/widgets/ConnectionItemWidget.ui
|
||||
src/ui/widgets/RouteSettingsMatrix.ui
|
||||
src/ui/w_MainWindow.ui
|
||||
src/ui/w_PreferencesWindow.ui
|
||||
src/ui/w_PluginManager.ui
|
||||
src/ui/w_ScreenShot_Core.ui
|
||||
# headers
|
||||
3rdparty/libsemver/version.hpp
|
||||
src/base/JsonHelpers.hpp
|
||||
src/base/models/CoreObjectModels.hpp
|
||||
src/base/models/QvConfigIdentifier.hpp
|
||||
src/base/models/QvRuntimeConfig.hpp
|
||||
src/base/models/QvSafeType.hpp
|
||||
src/base/models/QvSettingsObject.hpp
|
||||
src/base/models/QvStartupConfig.hpp
|
||||
src/base/Qv2rayBase.hpp
|
||||
src/base/Qv2rayFeatures.hpp
|
||||
src/base/Qv2rayLog.hpp
|
||||
src/common/CommandArgs.hpp
|
||||
src/common/HTTPRequestHelper.hpp
|
||||
src/common/JsonHighlighter.hpp
|
||||
src/common/LogHighlighter.hpp
|
||||
src/common/QJsonModel.hpp
|
||||
src/common/QvHelpers.hpp
|
||||
src/common/QvTranslator.hpp
|
||||
src/common/QRCodeHelper.hpp
|
||||
src/components/autolaunch/QvAutoLaunch.hpp
|
||||
src/components/darkmode/DarkmodeDetector.hpp
|
||||
src/components/geosite/QvGeositeReader.hpp
|
||||
src/components/latency/win/ICMPPinger.hpp
|
||||
src/components/latency/QvTCPing.hpp
|
||||
src/components/plugins/toolbar/QvToolbar.hpp
|
||||
src/components/plugins/QvPluginHost.hpp
|
||||
src/components/proxy/QvProxyConfigurator.hpp
|
||||
src/components/route/RouteSchemeIO.hpp
|
||||
src/components/route/presets/RouteScheme_V2rayN.hpp
|
||||
src/components/speedchart/speedplotview.hpp
|
||||
src/components/speedchart/speedwidget.hpp
|
||||
src/components/update/UpdateChecker.hpp
|
||||
src/core/connection/ConnectionIO.hpp
|
||||
src/core/connection/Generation.hpp
|
||||
src/core/connection/Serialization.hpp
|
||||
src/core/CoreSafeTypes.hpp
|
||||
src/core/CoreUtils.hpp
|
||||
src/core/handler/ConfigHandler.hpp
|
||||
src/core/handler/KernelInstanceHandler.hpp
|
||||
src/core/kernel/APIBackend.hpp
|
||||
src/core/kernel/V2rayKernelInteractions.hpp
|
||||
src/core/kernel/PluginKernelInteractions.hpp
|
||||
src/core/kernel/QvKernelABIChecker.hpp
|
||||
src/core/settings/SettingsBackend.hpp
|
||||
src/ui/editors/w_InboundEditor.hpp
|
||||
src/ui/editors/w_JsonEditor.hpp
|
||||
src/ui/editors/w_OutboundEditor.hpp
|
||||
src/ui/editors/w_RoutesEditor.hpp
|
||||
src/ui/messaging/QvMessageBus.hpp
|
||||
src/ui/models/InboundNodeModel.hpp
|
||||
src/ui/models/NodeModelsBase.hpp
|
||||
src/ui/models/OutboundNodeModel.hpp
|
||||
src/ui/models/RuleNodeModel.hpp
|
||||
src/ui/widgets/ConnectionInfoWidget.hpp
|
||||
src/ui/widgets/ConnectionItemWidget.hpp
|
||||
src/ui/widgets/QvAutoCompleteTextEdit.hpp
|
||||
src/ui/widgets/StreamSettingsWidget.hpp
|
||||
src/ui/widgets/RouteSettingsMatrix.hpp
|
||||
src/ui/w_ImportConfig.hpp
|
||||
src/ui/w_MainWindow.hpp
|
||||
src/ui/w_PreferencesWindow.hpp
|
||||
src/ui/w_PluginManager.hpp
|
||||
src/ui/w_ScreenShot_Core.hpp
|
||||
src/ui/w_SubscriptionManager.hpp
|
||||
assets/qv2ray.rc
|
||||
)
|
||||
|
||||
if(EMBED_TRANSLATIONS)
|
||||
add_definitions(-DEMBED_TRANSLATIONS)
|
||||
configure_file(translations/translations.qrc ${CMAKE_BINARY_DIR} COPYONLY)
|
||||
list(APPEND QV2RAY_SOURCES ${CMAKE_BINARY_DIR}/translations.qrc)
|
||||
endif()
|
||||
|
||||
add_custom_target(lupdate
|
||||
COMMAND lupdate ${QV2RAY_SOURCES} -ts ${TRANSLATIONS_TS} -locations none
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
|
||||
set_target_properties(lupdate PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
set(QRC_RESOURCES ${CMAKE_SOURCE_DIR}/resources.qrc)
|
||||
|
||||
set(QT_LIBRARY
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
${GUI_TYPE}
|
||||
${QV2RAY_SOURCES}
|
||||
${QNODEEDITOR_SOURCES}
|
||||
${QNODEEDITOR_QRC_RESOURCES}
|
||||
${SINGLEAPPLICATION_SOURCES}
|
||||
${ZXING_SOURCES}
|
||||
${LIBSEMVER_SOURCES}
|
||||
${PROTO_SRCS}
|
||||
${PROTO_HDRS}
|
||||
${API_GRPC_SRCS}
|
||||
${API_PROTO_SRCS}
|
||||
${QRC_RESOURCES}
|
||||
${QM_FILES}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
${QT_LIBRARY}
|
||||
set(QV2RAY_FULL_SOURCES
|
||||
src/main.cpp
|
||||
assets/qv2ray.rc
|
||||
${QV2RAY_UI_FORMS}
|
||||
${QV2RAY_UI_SOURCES}
|
||||
${SINGLEAPPLICATION_SOURCES}
|
||||
${QNODEEDITOR_QRC_RESOURCES}
|
||||
${QV2RAY_EMBED_TRANSLATION_QRC}
|
||||
${QRC_RESOURCES}
|
||||
${QM_FILES})
|
||||
|
||||
if(ANDROID)
|
||||
add_library(qv2ray SHARED ${QV2RAY_FULL_SOURCES})
|
||||
target_link_libraries(qv2ray -llog -landroid)
|
||||
else()
|
||||
if (WIN32)
|
||||
add_executable(qv2ray ${GUI_TYPE} ${QV2RAY_FULL_SOURCES})
|
||||
else()
|
||||
include(cmake/backward-cpp.cmake)
|
||||
add_executable(qv2ray ${GUI_TYPE} ${QV2RAY_FULL_SOURCES})
|
||||
add_backward(qv2ray)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
target_link_libraries(qv2ray-baselib
|
||||
${QV2RAY_PROTOBUF_LIBRARY}
|
||||
${QV2RAY_BACKEND_LIBRARIES}
|
||||
${QNODEEDITOR_LIBRARY}
|
||||
${ZXING_LIBRARY}
|
||||
Threads::Threads
|
||||
${QV2RAY_QT_LIBS}
|
||||
)
|
||||
|
||||
target_link_libraries(qv2ray
|
||||
qv2ray-baselib
|
||||
${QNODEEDITOR_LIBRARY}
|
||||
${SINGLEAPPLICATION_LIBRARY}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
target_include_directories(qv2ray PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_BINARY_DIR}
|
||||
${QHTTPSERVER_DIR}
|
||||
${QNODEEDITOR_INCLUDE_PATH}
|
||||
${ZXING_INCLUDE_PATH}
|
||||
${SINGLEAPPLICATION_DIR}
|
||||
${Protobuf_INCLUDE_DIRS}
|
||||
${cpp-httplib_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_include_directories(qv2ray-baselib PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${ZXING_INCLUDE_PATH}
|
||||
${Protobuf_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Qt language translations
|
||||
add_custom_target(lupdate
|
||||
COMMAND lupdate ${QV2RAY_BASE_HEADERS}
|
||||
${QV2RAY_LIB_SOURCES}
|
||||
${QVPLUGIN_INTERFACE_HEADERS}
|
||||
${QV2RAY_UI_SOURCES}
|
||||
${QV2RAY_UI_FORMS}
|
||||
${QNODEEDITOR_QRC_RESOURCES}
|
||||
${SINGLEAPPLICATION_SOURCES} -ts ${TRANSLATIONS_TS} -locations none -noobsolete
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
set_target_properties(lupdate PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
if(APPLE)
|
||||
find_package(Iconv REQUIRED)
|
||||
find_library(CARBON NAMES Carbon)
|
||||
find_library(COCOA NAMES Cocoa)
|
||||
find_library(SECURITY NAMES Security)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
target_link_libraries(qv2ray
|
||||
Iconv::Iconv
|
||||
${CARBON}
|
||||
${COCOA}
|
||||
${SECURITY}
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
target_include_directories(qv2ray PRIVATE
|
||||
${Iconv_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
@ -373,11 +304,11 @@ if(APPLE)
|
||||
MACOSX_PACKAGE_LOCATION Resources/lang
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
target_sources(qv2ray PRIVATE
|
||||
${MACOSX_ICON}
|
||||
)
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
set_target_properties(qv2ray
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_PLIST ${MACOSX_PLIST}
|
||||
@ -394,20 +325,22 @@ if(APPLE)
|
||||
)
|
||||
|
||||
# Destination paths below are relative to ${CMAKE_INSTALL_PREFIX}
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
|
||||
install(TARGETS qv2ray
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
RUNTIME DESTINATION bin COMPONENT Runtime
|
||||
)
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND macdeployqt ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app
|
||||
)
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app")
|
||||
if(QV2RAY_AUTO_DEPLOY)
|
||||
add_custom_command(TARGET qv2ray POST_BUILD
|
||||
COMMAND ${Qt5_DIR}/../../../bin/macdeployqt ${CMAKE_BINARY_DIR}/qv2ray.app
|
||||
)
|
||||
endif()
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/qv2ray.app")
|
||||
include(cmake/deployment.cmake)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT WIN32)
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
|
||||
install(TARGETS qv2ray RUNTIME DESTINATION bin)
|
||||
install(FILES assets/qv2ray.metainfo.xml DESTINATION share/metainfo)
|
||||
install(FILES assets/qv2ray.desktop DESTINATION share/applications)
|
||||
install(FILES assets/icons/qv2ray.png DESTINATION share/icons/hicolor/256x256/apps)
|
||||
@ -417,24 +350,18 @@ if(UNIX AND NOT APPLE AND NOT WIN32)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} wininet wsock32 ws2_32 user32)
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION .)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(qv2ray-baselib wininet wsock32 ws2_32 user32 Iphlpapi OpenSSL::SSL OpenSSL::Crypto Dbghelp)
|
||||
install(TARGETS qv2ray RUNTIME DESTINATION .)
|
||||
if(NOT EMBED_TRANSLATIONS)
|
||||
install(FILES ${QM_FILES} DESTINATION lang)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CL_64)
|
||||
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libssl-1_1-x64.dll DESTINATION .)
|
||||
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libcrypto-1_1-x64.dll DESTINATION .)
|
||||
else()
|
||||
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libssl-1_1.dll DESTINATION .)
|
||||
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libcrypto-1_1.dll DESTINATION .)
|
||||
if(QV2RAY_AUTO_DEPLOY)
|
||||
add_custom_command(TARGET qv2ray POST_BUILD
|
||||
COMMAND ${Qt5_DIR}/../../../bin/windeployqt ${CMAKE_BINARY_DIR}/qv2ray.exe --compiler-runtime --verbose 2 --dir ${CMAKE_BINARY_DIR}/winqt/
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND windeployqt ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.exe --compiler-runtime --verbose 2 --dir ${CMAKE_BINARY_DIR}/winqt/
|
||||
)
|
||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/winqt/ DESTINATION .)
|
||||
set(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.exe")
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/qv2ray.exe")
|
||||
include(cmake/deployment.cmake)
|
||||
endif()
|
||||
|
@ -5,7 +5,7 @@ AlignAfterOpenBracket: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
@ -42,7 +42,7 @@ SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpacesInParentheses: false
|
||||
Standard: Cpp11
|
||||
Standard: c++17
|
||||
StatementMacros: [ Q_UNUSED LOG DEBUG ]
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
@ -34,5 +34,20 @@
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>True</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>Icon</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.qv2ray.qv2ray</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>qv2ray</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
20
assets/ProtocolSchemes.txt
Normal file
20
assets/ProtocolSchemes.txt
Normal file
@ -0,0 +1,20 @@
|
||||
qv2ray://open/preference/general
|
||||
qv2ray://open/preference/kernel
|
||||
qv2ray://open/preference/inbound
|
||||
qv2ray://open/preference/connection
|
||||
qv2ray://open/preference/route
|
||||
qv2ray://open/preference/about
|
||||
|
||||
qv2ray://open/group/connection
|
||||
qv2ray://open/group/subscription
|
||||
qv2ray://open/group/dns
|
||||
qv2ray://open/group/route
|
||||
|
||||
qv2ray://open/import/link?name=
|
||||
qv2ray://open/import/qr?name=
|
||||
qv2ray://open/import/manual?name=
|
||||
qv2ray://open/import/advanced?name=
|
||||
|
||||
qv2ray://open/plugin/plugindir
|
||||
qv2ray://open/plugin/metadata
|
||||
qv2ray://open/plugin/settings
|
@ -1,21 +1,32 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'WenQuanYi Micro Hei'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; font-weight:600; color:#d68952;">This program comes with ABSOLUTELY NO WARRANTY.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; font-weight:600; color:#d68952;">This is free software, and you are welcome to redistribute it under certain conditions.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2019-2020 Qv2ray Development Group.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Noto Sans'; color:#d68952;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; font-weight:600; color:#d68952;">Libraries that have been used in Qv2ray are listed below (Sorted by date added):</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 xyz347 (xyz347): X2Struct (Apache)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 Itay Grudev (@itay-grudev): SingleApplication (MIT)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 paceholder (@paceholder): nodeeditor (Qv2ray group modified version) (BSD-3-Clause)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2019 TheWanderingCoel (@TheWanderingCoel): ShadowClash (launchatlogin) (GPLv3)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 DuckSoft (@DuckSoft): QvRPCBridge (WTFPL)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 Diffusions Nu-book Inc. (nu-book): zxing-cpp (Apache)</span></p>
|
||||
</body></html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="qrichtext" content="1" />
|
||||
<style type="text/css">
|
||||
p,
|
||||
li {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style=" font-family:'WenQuanYi Micro Hei'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; font-weight:600; color:#d68952;">This program comes with ABSOLUTELY NO WARRANTY.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; font-weight:600; color:#d68952;">This is free software, and you are welcome to redistribute it under certain conditions.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2019-2020 Qv2ray Development Group.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Noto Sans'; color:#d68952;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; font-weight:600; color:#d68952;">Libraries that have been used in Qv2ray are listed below (Sorted by date added):</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 Itay Grudev (@itay-grudev): SingleApplication (MIT)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 paceholder (@paceholder): nodeeditor (Qv2ray group modified version) (BSD-3-Clause)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2019 TheWanderingCoel (@TheWanderingCoel): ShadowClash (launchatlogin) (GPLv3)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 DuckSoft (@DuckSoft): QvRPCBridge (WTFPL)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 Diffusions Nu-book Inc. (nu-book): zxing-cpp (Apache)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MonoSpace'; color:#d68952;">Copyright (c) 2020 feiyangqingyun: QWidgetDemo (Mulan PSL v1)</span></p>
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
assets/icons/Applogo_bird_b.png
Normal file
BIN
assets/icons/Applogo_bird_b.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 256 KiB |
BIN
assets/icons/Applogo_bird_colorful.png
Normal file
BIN
assets/icons/Applogo_bird_colorful.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 278 KiB |
BIN
assets/icons/Applogo_bird_g.png
Normal file
BIN
assets/icons/Applogo_bird_g.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 246 KiB |
237
assets/icons/designs/Applogo_Bird_b.svg
Normal file
237
assets/icons/designs/Applogo_Bird_b.svg
Normal file
@ -0,0 +1,237 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:export-ydpi="512"
|
||||
inkscape:export-xdpi="512"
|
||||
sodipodi:docname="Applogo_Bird_b.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 12.699999 12.7"
|
||||
height="48"
|
||||
width="48">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient908"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop904"
|
||||
offset="0"
|
||||
style="stop-color:#6e7678;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop906"
|
||||
offset="1"
|
||||
style="stop-color:#2e3235;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient847"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop843"
|
||||
offset="0"
|
||||
style="stop-color:#00e0ff;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop845"
|
||||
offset="1"
|
||||
style="stop-color:#1ba7f9;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5057"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop5053"
|
||||
offset="0"
|
||||
style="stop-color:#3c3c3c;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop5055"
|
||||
offset="1"
|
||||
style="stop-color:#282728;stop-opacity:0.6574803" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4759"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop4755"
|
||||
offset="0"
|
||||
style="stop-color:#00b7ff;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4757"
|
||||
offset="1"
|
||||
style="stop-color:#1c90ff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4713">
|
||||
<stop
|
||||
style="stop-color:#3de256;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4709" />
|
||||
<stop
|
||||
style="stop-color:#2fbeba;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4711" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(38.574145,1.3181723)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="39.934193"
|
||||
x2="108.00179"
|
||||
y1="19.458199"
|
||||
x1="89.965836"
|
||||
id="linearGradient4707"
|
||||
xlink:href="#linearGradient4713"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="94.022179"
|
||||
x2="140.26065"
|
||||
y1="48.940449"
|
||||
x1="92.227142"
|
||||
id="linearGradient5059"
|
||||
xlink:href="#linearGradient5057"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="35.515835"
|
||||
x2="113.08728"
|
||||
y1="28.293249"
|
||||
x1="85.229973"
|
||||
gradientTransform="matrix(0.34597512,0.06144722,-0.06655638,0.31941658,-25.1488,274.41205)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient953"
|
||||
xlink:href="#linearGradient4759"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="208.23155"
|
||||
x2="72.363083"
|
||||
y1="196.65211"
|
||||
x1="39.630962"
|
||||
gradientTransform="matrix(0.15666471,0,0,0.15666471,-5.1793298,256.3406)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient955"
|
||||
xlink:href="#linearGradient847"
|
||||
inkscape:collect="always" />
|
||||
<clipPath
|
||||
id="clipPath922"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<rect
|
||||
ry="1.0638391"
|
||||
y="284.56458"
|
||||
x="9.5367426e-08"
|
||||
height="12.170834"
|
||||
width="12.7"
|
||||
id="rect924"
|
||||
style="fill:none;fill-opacity:1;stroke:#23d829;stroke-width:0.044;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.72265625" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.87500008,0,0,0.87505491,0.81442048,36.315602)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="297"
|
||||
x2="12.7"
|
||||
y1="284.29999"
|
||||
x1="12.7"
|
||||
id="linearGradient910"
|
||||
xlink:href="#linearGradient908"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="false"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:snap-text-baseline="false"
|
||||
inkscape:snap-center="false"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:snap-intersection-paths="false"
|
||||
inkscape:object-paths="false"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:snap-nodes="false"
|
||||
units="px"
|
||||
inkscape:snap-midpoints="false"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:guide-bbox="true"
|
||||
showguides="true"
|
||||
inkscape:snap-smooth-nodes="false"
|
||||
inkscape:snap-object-midpoints="false"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-width="1920"
|
||||
showgrid="false"
|
||||
inkscape:current-layer="g44"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="21.316088"
|
||||
inkscape:cx="23.875406"
|
||||
inkscape:zoom="22.599304"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base">
|
||||
<inkscape:grid
|
||||
id="grid885"
|
||||
type="xygrid" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-284.29999)"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(0.77674917,0,0,0.77993751,1.4662318,64.012038)"
|
||||
id="g889">
|
||||
<g
|
||||
transform="matrix(1.1963196,0,0,1.1963196,-1.3111729,-57.928707)"
|
||||
id="g44">
|
||||
<path
|
||||
style="fill:#2782bd;fill-opacity:1;stroke:none;stroke-width:0.02480469px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 4.8977933,290.46043 c 0,0 -0.3822449,0.7135 -0.5365115,0.93777 -0.154295,0.22431 -0.5217135,0.4236 -0.5217135,0.4236 l 0.6747961,-0.0816 1.7063455,-0.35106 c 0,0 -0.7913874,-1.07043 -1.3229166,-0.92869 z"
|
||||
id="path879-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cscccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4715-0"
|
||||
d="m 4.1456075,290.71139 c 0,0 1.1173813,-2.75102 3.3019109,-0.59828 2.1845208,2.15274 3.6949266,5.47345 3.6949266,5.47345 0,0 -2.9944646,-4.26031 -6.9968375,-4.87517 z"
|
||||
style="fill:#008dff;fill-opacity:1;stroke:none;stroke-width:0.08956835px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4715-6-93"
|
||||
d="m 2.2137987,290.23705 c 0,0 -0.1508518,-2.94653 2.7747518,-1.81527 2.9256022,1.13127 6.6242245,4.28351 6.6242245,4.28351 0,0 -4.81123,-3.07932 -9.3989763,-2.46824 z"
|
||||
style="fill:url(#linearGradient953);fill-opacity:1;stroke:none;stroke-width:0.08956835px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4715-6-9-6"
|
||||
d="m 1.2940265,289.53029 c 0,0 -1.32291659,-2.64583 1.9849644,-2.35592 3.1595803,0.27691 7.8046181,2.09134 7.8046181,2.09134 0,0 -5.6043094,-1.52438 -9.7895825,0.26458 z"
|
||||
style="fill:url(#linearGradient955);fill-opacity:1;stroke:none;stroke-width:0.08956835px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.0 KiB |
237
assets/icons/designs/Applogo_Bird_colorful.svg
Normal file
237
assets/icons/designs/Applogo_Bird_colorful.svg
Normal file
@ -0,0 +1,237 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:export-ydpi="512"
|
||||
inkscape:export-xdpi="512"
|
||||
sodipodi:docname="Applogo_Bird_colorful.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 12.699999 12.7"
|
||||
height="48"
|
||||
width="48">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient908"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop904"
|
||||
offset="0"
|
||||
style="stop-color:#6e7678;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop906"
|
||||
offset="1"
|
||||
style="stop-color:#2e3235;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient847"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop843"
|
||||
offset="0"
|
||||
style="stop-color:#ffacad;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop845"
|
||||
offset="1"
|
||||
style="stop-color:#ff5c5b;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5057"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop5053"
|
||||
offset="0"
|
||||
style="stop-color:#3c3c3c;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop5055"
|
||||
offset="1"
|
||||
style="stop-color:#282728;stop-opacity:0.6574803" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4759"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop4755"
|
||||
offset="0"
|
||||
style="stop-color:#ef3cff;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4757"
|
||||
offset="1"
|
||||
style="stop-color:#1c90ff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4713">
|
||||
<stop
|
||||
style="stop-color:#3de256;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4709" />
|
||||
<stop
|
||||
style="stop-color:#2fbeba;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4711" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(38.574145,1.3181723)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="39.934193"
|
||||
x2="108.00179"
|
||||
y1="19.458199"
|
||||
x1="89.965836"
|
||||
id="linearGradient4707"
|
||||
xlink:href="#linearGradient4713"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="94.022179"
|
||||
x2="140.26065"
|
||||
y1="48.940449"
|
||||
x1="92.227142"
|
||||
id="linearGradient5059"
|
||||
xlink:href="#linearGradient5057"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="35.515835"
|
||||
x2="113.08728"
|
||||
y1="28.293249"
|
||||
x1="85.229973"
|
||||
gradientTransform="matrix(0.34597512,0.06144722,-0.06655638,0.31941658,-25.1488,274.41205)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient953"
|
||||
xlink:href="#linearGradient4759"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="208.23155"
|
||||
x2="72.363083"
|
||||
y1="196.65211"
|
||||
x1="39.630962"
|
||||
gradientTransform="matrix(0.15666471,0,0,0.15666471,-5.1793298,256.3406)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient955"
|
||||
xlink:href="#linearGradient847"
|
||||
inkscape:collect="always" />
|
||||
<clipPath
|
||||
id="clipPath922"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<rect
|
||||
ry="1.0638391"
|
||||
y="284.56458"
|
||||
x="9.5367426e-08"
|
||||
height="12.170834"
|
||||
width="12.7"
|
||||
id="rect924"
|
||||
style="fill:none;fill-opacity:1;stroke:#23d829;stroke-width:0.044;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.72265625" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.87500008,0,0,0.87505491,0.81442048,36.315602)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="297"
|
||||
x2="12.7"
|
||||
y1="284.29999"
|
||||
x1="12.7"
|
||||
id="linearGradient910"
|
||||
xlink:href="#linearGradient908"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="false"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:snap-text-baseline="false"
|
||||
inkscape:snap-center="false"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:snap-intersection-paths="false"
|
||||
inkscape:object-paths="false"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:snap-nodes="false"
|
||||
units="px"
|
||||
inkscape:snap-midpoints="false"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:guide-bbox="true"
|
||||
showguides="true"
|
||||
inkscape:snap-smooth-nodes="false"
|
||||
inkscape:snap-object-midpoints="false"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-width="1920"
|
||||
showgrid="false"
|
||||
inkscape:current-layer="g44"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="25.276329"
|
||||
inkscape:cx="27.278388"
|
||||
inkscape:zoom="15.980121"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base">
|
||||
<inkscape:grid
|
||||
id="grid885"
|
||||
type="xygrid" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-284.29999)"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(0.77674917,0,0,0.77993751,1.4662318,64.012038)"
|
||||
id="g889">
|
||||
<g
|
||||
transform="matrix(1.1963196,0,0,1.1963196,-1.3111729,-57.928707)"
|
||||
id="g44">
|
||||
<path
|
||||
style="fill:#275bbd;fill-opacity:1;stroke:none;stroke-width:0.02480469px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 4.8977933,290.46043 c 0,0 -0.3822449,0.7135 -0.5365115,0.93777 -0.154295,0.22431 -0.5217135,0.4236 -0.5217135,0.4236 l 0.6747961,-0.0816 1.7063455,-0.35106 c 0,0 -0.7913874,-1.07043 -1.3229166,-0.92869 z"
|
||||
id="path879-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cscccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4715-0"
|
||||
d="m 4.1456075,290.71139 c 0,0 1.1173813,-2.75102 3.3019109,-0.59828 2.1845208,2.15274 3.6949266,5.47345 3.6949266,5.47345 0,0 -2.9944646,-4.26031 -6.9968375,-4.87517 z"
|
||||
style="fill:#008dff;fill-opacity:1;stroke:none;stroke-width:0.08956835px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4715-6-93"
|
||||
d="m 2.2137987,290.23705 c 0,0 -0.1508518,-2.94653 2.7747518,-1.81527 2.9256022,1.13127 6.6242245,4.28351 6.6242245,4.28351 0,0 -4.81123,-3.07932 -9.3989763,-2.46824 z"
|
||||
style="fill:url(#linearGradient953);fill-opacity:1;stroke:none;stroke-width:0.08956835px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4715-6-9-6"
|
||||
d="m 1.2940265,289.53029 c 0,0 -1.32291659,-2.64583 1.9849644,-2.35592 3.1595803,0.27691 7.8046181,2.09134 7.8046181,2.09134 0,0 -5.6043094,-1.52438 -9.7895825,0.26458 z"
|
||||
style="fill:url(#linearGradient955);fill-opacity:1;stroke:none;stroke-width:0.08956835px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.0 KiB |
@ -11,7 +11,7 @@
|
||||
}
|
||||
},
|
||||
"contents": [
|
||||
{ "x": 130, "y": 205, "type": "file", "path": "@CMAKE_BINARY_DIR@/qv2ray.app" },
|
||||
{ "x": 130, "y": 205, "type": "file", "path": "@CMAKE_INSTALL_PREFIX@/qv2ray.app" },
|
||||
{ "x": 375, "y": 205, "type": "link", "path": "/Applications" }
|
||||
]
|
||||
}
|
||||
|
@ -2,25 +2,42 @@
|
||||
Version=1.0
|
||||
Name=Qv2ray
|
||||
Type=Application
|
||||
GenericName=V2ray Graphical Frontend
|
||||
GenericName[zh_CN]=V2ray 图形前端
|
||||
Comment=A Cross-platform v2ray Qt GUI Client
|
||||
Comment[zh_CN]=跨平台的 v2ray Qt 客户端
|
||||
GenericName=V2Ray Graphical Frontend
|
||||
GenericName[zh_CN]=V2Ray 图形前端
|
||||
GenericName[ja]=V2Rayグラフィックフロントエンド
|
||||
Comment=A Cross-Platform V2Ray Qt GUI Client
|
||||
Comment[zh_CN]=跨平台的 V2Ray Qt 图形客户端
|
||||
Comment[ja]=とあるクロスプラットフォームV2Rayグラフィックフロントエンド
|
||||
Keywords=Internet;VPN;Proxy;v2ray;Qt;qv;
|
||||
Keywords[zh_CN]=Internet;VPN;Proxy;v2ray;Qt;qv;代理;翻墙;梯子;
|
||||
Keywords[zh_CN]=Internet;VPN;Proxy;v2ray;Qt;qv;代理;
|
||||
Keywords[ja]=インターネット;VPN;プロキシ;Qt;v2ray;qv;
|
||||
Categories=Network;Qt;
|
||||
Terminal=false
|
||||
Icon=qv2ray
|
||||
Exec=qv2ray
|
||||
Actions=noAPI;withToolbarPlugin;
|
||||
Exec=qv2ray %u
|
||||
MimeType=x-scheme-handler/qv2ray;
|
||||
Actions=debug;noPlugin;noScaleFactor;noAPI;
|
||||
|
||||
[Desktop Action debug]
|
||||
Name=Start with Debug Mode
|
||||
Name[zh_CN]=以调试模式运行
|
||||
Name[ja]=デバッグモードで起動
|
||||
Exec=qv2ray --debug
|
||||
|
||||
[Desktop Action noPlugin]
|
||||
Name=Start without Plugins
|
||||
Name[zh_CN]=不使用插件启动
|
||||
Name[ja]=プラグイン使用せずに起動
|
||||
Exec=qv2ray --noPlugin
|
||||
|
||||
[Desktop Action noScaleFactor]
|
||||
Name=Start without Scaling Factor
|
||||
Name[zh_CN]=禁用界面缩放启动
|
||||
Name[ja]=インターフェーススケーリング使用せずに起動
|
||||
Exec=qv2ray --noScaleFactor
|
||||
|
||||
[Desktop Action noAPI]
|
||||
Name=Start without gRPC API
|
||||
Name[zh_CN]=不使用 gRPC API 启动
|
||||
Name[ja]=gRPC使用せずに起動
|
||||
Exec=qv2ray --noAPI
|
||||
|
||||
[Desktop Action withToolbarPlugin]
|
||||
Name=Start with Toolbar Plugin
|
||||
Name[zh_CN]=使用工具栏插件启动
|
||||
Exec=qv2ray --withToolbarPlugin
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>com.github.Qv2ray</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0</project_license>
|
||||
<metadata_license>GPL-3.0+</metadata_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<name>Qv2ray</name>
|
||||
<summary>Qv2ray is a cross-platform v2ray graphical frontend written in Qt.</summary>
|
||||
|
||||
|
@ -31,7 +31,7 @@ VS_VERSION_INFO VERSIONINFO
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Qv2ray Workgroup\0"
|
||||
VALUE "FileDescription", "Qv2ray, a cross-platform v2ray GUI client.\0"
|
||||
VALUE "FileDescription", "Qv2ray\0"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "LegalCopyright", "Qv2ray is being distributed under GPLv3\0"
|
||||
VALUE "OriginalFilename", "qv2ray.exe\0"
|
||||
|
@ -15,21 +15,25 @@ pool:
|
||||
steps:
|
||||
- checkout: self
|
||||
submodules: recursive
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '12.x'
|
||||
- script: |
|
||||
brew install protobuf grpc ninja qt5
|
||||
sudo xcode-select -s /Applications/Xcode_10.3.app
|
||||
brew install protobuf grpc ninja qt5 pkg-config
|
||||
npm install -g appdmg
|
||||
displayName: Prepare dependencies
|
||||
- script: |
|
||||
PATH=/usr/local/opt/qt5/bin:$PATH
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.14
|
||||
sudo cmake --build . --target package --parallel $(sysctl -n hw.logicalcpu)
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13
|
||||
cmake --build .
|
||||
sudo cmake --install .
|
||||
appdmg ../assets/package_dmg.json ../qv2ray-legacy.dmg
|
||||
displayName: Build Qv2ray
|
||||
env:
|
||||
Qt5_DIR: /usr/local/opt/qt5/lib/cmake/Qt5
|
||||
- script: |
|
||||
cp build/qv2ray-*.dmg ./qv2ray-legacy.dmg
|
||||
displayName: Copy binary
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
PathtoPublish: 'qv2ray-legacy.dmg'
|
||||
|
@ -11,13 +11,14 @@ if(NOT USE_LIBQVB)
|
||||
set(QV2RAY_BACKEND_LIBRARIES ${GRPC_LIBRARIES})
|
||||
else()
|
||||
find_library(UPB_LIBRARY NAMES upb)
|
||||
find_library(ADDRESS_SORTING NAMES address_sorting)
|
||||
pkg_check_modules(GRPC REQUIRED grpc++ grpc gpr)
|
||||
set(QV2RAY_BACKEND_LIBRARIES ${GRPC_LINK_LIBRARIES} ${UPB_LIBRARY})
|
||||
set(QV2RAY_BACKEND_LIBRARIES ${GRPC_LINK_LIBRARIES} ${UPB_LIBRARY} ${ADDRESS_SORTING})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(API_PROTO "${CMAKE_SOURCE_DIR}/tools/v2ray_api.proto")
|
||||
set(API_PROTO_PATH "${CMAKE_SOURCE_DIR}/tools")
|
||||
set(API_PROTO "${CMAKE_SOURCE_DIR}/assets/v2ray_api.proto")
|
||||
set(API_PROTO_PATH "${CMAKE_SOURCE_DIR}/assets")
|
||||
set(API_PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.pb.cc")
|
||||
set(API_PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.pb.h")
|
||||
set(API_GRPC_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.grpc.pb.cc")
|
||||
@ -26,12 +27,12 @@ if(NOT USE_LIBQVB)
|
||||
OUTPUT "${API_GRPC_SRCS}" "${API_GRPC_HDRS}" "${API_PROTO_HDRS}" "${API_PROTO_SRCS}"
|
||||
COMMAND ${Protobuf_PROTOC_EXECUTABLE}
|
||||
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
-I "${API_PROTO_PATH}"
|
||||
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
|
||||
"${API_PROTO}"
|
||||
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
-I "${API_PROTO_PATH}"
|
||||
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
|
||||
"${API_PROTO}"
|
||||
DEPENDS "${API_PROTO}"
|
||||
)
|
||||
)
|
||||
else()
|
||||
add_definitions(-DBACKEND_LIBQVB)
|
||||
if(UNIX AND NOT APPLE)
|
||||
|
46
cmake/backward-cpp.cmake
Normal file
46
cmake/backward-cpp.cmake
Normal file
@ -0,0 +1,46 @@
|
||||
include(${CMAKE_SOURCE_DIR}/3rdparty/backward-cpp/BackwardConfig.cmake)
|
||||
|
||||
# check if compiler is nvcc or nvcc_wrapper
|
||||
set(COMPILER_IS_NVCC false)
|
||||
get_filename_component(COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME)
|
||||
if (COMPILER_NAME MATCHES "^nvcc")
|
||||
set(COMPILER_IS_NVCC true)
|
||||
endif()
|
||||
|
||||
if (DEFINED ENV{OMPI_CXX} OR DEFINED ENV{MPICH_CXX})
|
||||
if ( ($ENV{OMPI_CXX} MATCHES "nvcc") OR ($ENV{MPICH_CXX} MATCHES "nvcc") )
|
||||
set(COMPILER_IS_NVCC true)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# set CXX standard
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
if (${COMPILER_IS_NVCC})
|
||||
# GNU CXX extensions are not supported by nvcc
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
# COMPILER FLAGS
|
||||
###############################################################################
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -g")
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
# BACKWARD OBJECT
|
||||
###############################################################################
|
||||
|
||||
add_library(backward_object OBJECT ${CMAKE_SOURCE_DIR}/3rdparty/backward-cpp/backward.cpp)
|
||||
target_compile_definitions(backward_object PRIVATE ${BACKWARD_DEFINITIONS})
|
||||
target_include_directories(backward_object PRIVATE ${BACKWARD_INCLUDE_DIRS})
|
||||
set(BACKWARD_ENABLE $<TARGET_OBJECTS:backward_object> CACHE STRING
|
||||
"Link with this object to setup backward automatically")
|
||||
|
||||
###############################################################################
|
||||
# BACKWARD LIBRARY (Includes backward.cpp)
|
||||
###############################################################################
|
||||
add_library(backward ${CMAKE_SOURCE_DIR}/3rdparty/backward-cpp/backward.cpp)
|
||||
target_compile_definitions(backward PUBLIC ${BACKWARD_DEFINITIONS})
|
||||
target_include_directories(backward PUBLIC ${BACKWARD_INCLUDE_DIRS})
|
109
cmake/components/qv2ray-lib.cmake
Normal file
109
cmake/components/qv2ray-lib.cmake
Normal file
@ -0,0 +1,109 @@
|
||||
set(QV2RAY_BASE_HEADERS
|
||||
${CMAKE_SOURCE_DIR}/src/base/JsonHelpers.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/CoreObjectModels.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/QvConfigIdentifier.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/QvRuntimeConfig.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/QvSafeType.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/QvCoreSettings.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/QvSettingsObject.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/models/QvStartupConfig.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/Qv2rayBase.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/Qv2rayFeatures.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/base/Qv2rayLog.hpp
|
||||
)
|
||||
|
||||
set(QV2RAY_LIB_SOURCES
|
||||
# headers
|
||||
${CMAKE_SOURCE_DIR}/src/base/Qv2rayLog.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/HTTPRequestHelper.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/HTTPRequestHelper.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/QJsonModel.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/QJsonModel.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/QvHelpers.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/QvHelpers.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/QvTranslator.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/common/QvTranslator.hpp
|
||||
# Components
|
||||
${CMAKE_SOURCE_DIR}/src/components/autolaunch/QvAutoLaunch.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/autolaunch/QvAutoLaunch.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/geosite/QvGeositeReader.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/geosite/QvGeositeReader.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/LatencyTest.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/LatencyTest.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/LatencyTestThread.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/LatencyTestThread.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/TCPing.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/TCPing.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/win/ICMPPing.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/win/ICMPPing.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/unix/ICMPPing.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/latency/unix/ICMPPing.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/ntp/QvNTPClient.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/ntp/QvNTPClient.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/plugins/QvPluginHost.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/plugins/QvPluginHost.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/port/QvPortDetector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/port/QvPortDetector.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/proxy/QvProxyConfigurator.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/proxy/QvProxyConfigurator.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/route/presets/RouteScheme_V2rayN.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/route/RouteSchemeIO.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/route/RouteSchemeIO.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/update/UpdateChecker.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/update/UpdateChecker.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/darkmode/DarkmodeDetector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/darkmode/DarkmodeDetector.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/components/speedchart/speedplotview.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/speedchart/speedplotview.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/speedchart/speedwidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/components/speedchart/speedwidget.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/ConnectionIO.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/ConnectionIO.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/Generation.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/generation/final.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/generation/inbounds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/generation/outbounds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/generation/filters.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/generation/routing.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/generation/misc.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/Serialization.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/Serialization.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/serialization/ss.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/serialization/ssd.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/serialization/vmess.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/connection/serialization/vmess_new.cpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/core/CoreUtils.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/CoreUtils.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/core/handler/ConfigHandler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/handler/ConfigHandler.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/handler/KernelInstanceHandler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/handler/KernelInstanceHandler.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/handler/RouteHandler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/handler/RouteHandler.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/APIBackend.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/APIBackend.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/PluginKernelInteractions.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/PluginKernelInteractions.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/QvKernelABIChecker.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/QvKernelABIChecker.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/V2rayKernelInteractions.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/kernel/V2rayKernelInteractions.hpp
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/core/settings/SettingsBackend.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/settings/SettingsBackend.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/core/settings/SettingsUpgrade.cpp
|
||||
)
|
93
cmake/components/qv2ray-ui.cmake
Normal file
93
cmake/components/qv2ray-ui.cmake
Normal file
@ -0,0 +1,93 @@
|
||||
set(QV2RAY_UI_FORMS
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_OutboundEditor.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_InboundEditor.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_JsonEditor.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_RoutesEditor.ui
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/StreamSettingsWidget.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionInfoWidget.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionItemWidget.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/RouteSettingsMatrix.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/InboundSettingsWidget.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionSettingsWidget.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/DnsSettingsWidget.ui
|
||||
#
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_GroupManager.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_ImportConfig.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_MainWindow.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_PreferencesWindow.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_PluginManager.ui
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_ScreenShot_Core.ui
|
||||
)
|
||||
|
||||
set(QV2RAY_UI_SOURCES
|
||||
# Qv2ray Application
|
||||
${CMAKE_SOURCE_DIR}/src/StackTraceHelper.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/StackTraceHelper.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/Qv2rayApplication.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/Qv2rayApplication.hpp
|
||||
# Common Utils
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/QvDialog.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/QRCodeHelper.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/QRCodeHelper.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/UIBase.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/JsonHighlighter.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/JsonHighlighter.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/LogHighlighter.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/common/LogHighlighter.cpp
|
||||
# Message bus
|
||||
${CMAKE_SOURCE_DIR}/src/ui/messaging/QvMessageBus.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/messaging/QvMessageBus.cpp
|
||||
# NodeEditor Models
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/NodeModelsBase.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/InboundNodeModel.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/InboundNodeModel.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/OutboundNodeModel.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/OutboundNodeModel.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/RuleNodeModel.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/models/RuleNodeModel.cpp
|
||||
# Style Manager
|
||||
${CMAKE_SOURCE_DIR}/src/ui/styles/StyleManager.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/styles/StyleManager.hpp
|
||||
# UI Widgets
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionInfoWidget.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionInfoWidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/QvAutoCompleteTextEdit.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/QvAutoCompleteTextEdit.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/RouteSettingsMatrix.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/RouteSettingsMatrix.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionSettingsWidget.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionSettingsWidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionItemWidget.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/ConnectionItemWidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/StreamSettingsWidget.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/StreamSettingsWidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/InboundSettingsWidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/InboundSettingsWidget.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/DnsSettingsWidget.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets/DnsSettingsWidget.hpp
|
||||
# Editors
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_InboundEditor.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_InboundEditor.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_JsonEditor.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_JsonEditor.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_OutboundEditor.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_OutboundEditor.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_RoutesEditor.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_RoutesEditor.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/editors/w_RoutesEditor_extra.cpp
|
||||
# Windows
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_ImportConfig.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_ImportConfig.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_MainWindow.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_MainWindow.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_MainWindow_extra.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_PreferencesWindow.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_PreferencesWindow.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_PluginManager.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_PluginManager.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_ScreenShot_Core.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_ScreenShot_Core.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_GroupManager.hpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/windows/w_GroupManager.cpp
|
||||
)
|
@ -1 +0,0 @@
|
||||
set(cpp-httplib_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/3rdparty/cpp-httplib)
|
@ -1,33 +1,3 @@
|
||||
# Directories to look for dependencies
|
||||
set(DIRS "${CMAKE_BINARY_DIR}")
|
||||
|
||||
# Path used for searching by FIND_XXX(), with appropriate suffixes added
|
||||
if(CMAKE_PREFIX_PATH)
|
||||
foreach(dir ${CMAKE_PREFIX_PATH})
|
||||
list(APPEND DIRS "${dir}/bin" "${dir}/lib")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Append Qt's lib folder which is two levels above Qt5Widgets_DIR
|
||||
list(APPEND DIRS "${Qt5Widgets_DIR}/../..")
|
||||
list(APPEND DIRS "/usr/local/lib")
|
||||
list(APPEND DIRS "/usr/lib")
|
||||
|
||||
if(MSVC)
|
||||
if(NOT BUILD_NSIS)
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
message(STATUS "APPS: ${APPS}")
|
||||
message(STATUS "QT_PLUGINS: ${QT_PLUGINS}")
|
||||
message(STATUS "DIRS: ${DIRS}")
|
||||
|
||||
install(CODE "include(BundleUtilities)
|
||||
fixup_bundle(\"${APPS}\" \"${QT_PLUGINS}\" \"${DIRS}\")")
|
||||
|
||||
# Packaging
|
||||
set(CPACK_PACKAGE_VENDOR "Qv2ray Development Group")
|
||||
set(CPACK_PACKAGE_VERSION ${QV2RAY_VERSION_STRING})
|
||||
@ -45,6 +15,11 @@ if(MSVC)
|
||||
set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/assets/icons/qv2ray.ico")
|
||||
set(CPACK_NSIS_DISPLAY_NAME "Qv2ray")
|
||||
set(CPACK_NSIS_PACKAGE_NAME "Qv2ray")
|
||||
set(CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS "
|
||||
ExecWait \\\"taskkill /f /im qv2ray.exe\\\"
|
||||
ExecWait \\\"taskkill /f /im v2ray.exe\\\"
|
||||
ExecWait \\\"taskkill /f /im wv2ray.exe\\\"
|
||||
")
|
||||
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "
|
||||
CreateShortCut \\\"$DESKTOP\\\\Qv2ray.lnk\\\" \\\"$INSTDIR\\\\qv2ray.exe\\\"
|
||||
CreateDirectory \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\"
|
||||
@ -56,6 +31,7 @@ if(MSVC)
|
||||
WriteRegStr HKLM \\\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\qv2ray\\\" \\\"URLInfoAbout\\\" \\\"https://github.com/Qv2ray/Qv2ray\\\"
|
||||
")
|
||||
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "
|
||||
ExecWait \\\"taskkill /f /im qv2ray.exe\\\"
|
||||
Delete \\\"$DESKTOP\\\\Qv2ray.lnk\\\"
|
||||
Delete \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\\Qv2ray.lnk\\\"
|
||||
RMDir \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\"
|
||||
@ -78,3 +54,33 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
|
||||
# Directories to look for dependencies
|
||||
set(DIRS "${CMAKE_BINARY_DIR}")
|
||||
|
||||
# Path used for searching by FIND_XXX(), with appropriate suffixes added
|
||||
if(CMAKE_PREFIX_PATH)
|
||||
foreach(dir ${CMAKE_PREFIX_PATH})
|
||||
list(APPEND DIRS "${dir}/bin" "${dir}/lib")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Append Qt's lib folder which is two levels above Qt5Widgets_DIR
|
||||
list(APPEND DIRS "${Qt5Widgets_DIR}/../..")
|
||||
list(APPEND DIRS "/usr/local/lib")
|
||||
list(APPEND DIRS "/usr/lib")
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .)
|
||||
endif()
|
||||
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
message(STATUS "APPS: ${APPS}")
|
||||
message(STATUS "QT_PLUGINS: ${QT_PLUGINS}")
|
||||
message(STATUS "DIRS: ${DIRS}")
|
||||
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
|
||||
" COMPONENT Runtime)
|
||||
|
4
cmake/libsemver.cmake
Normal file
4
cmake/libsemver.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
set(LIBSEMVER_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/3rdparty/libsemver/version.cpp
|
||||
${CMAKE_SOURCE_DIR}/3rdparty/libsemver/version.hpp
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
find_package(Protobuf REQUIRED)
|
||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/tools/v2ray_geosite.proto)
|
||||
set(QV2RAY_PROTOBUF_LIBRARY
|
||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/assets/v2ray_geosite.proto)
|
||||
set(QV2RAY_PROTOBUF_LIBRARY
|
||||
protobuf::libprotobuf
|
||||
)
|
||||
)
|
||||
|
@ -23,14 +23,16 @@ if(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "module")
|
||||
${QNODEEDITOR_DIR}/src/NodeStyle.cpp
|
||||
${QNODEEDITOR_DIR}/src/Properties.cpp
|
||||
${QNODEEDITOR_DIR}/src/StyleCollection.cpp
|
||||
)
|
||||
set(QNODEEDITOR_INCLUDE_PATH
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal
|
||||
)
|
||||
)
|
||||
|
||||
set(HEADERS_TO_MOC
|
||||
set(QNODEEDITOR_INCLUDE_PATH
|
||||
${QNODEEDITOR_DIR}/include
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal
|
||||
)
|
||||
|
||||
set(QNODEEDITOR_HEADERS
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/Compiler.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/Connection.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/Connection.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionGeometry.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionGraphicsObject.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionState.hpp
|
||||
@ -56,17 +58,29 @@ if(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "module")
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/Serializable.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/Style.hpp
|
||||
${QNODEEDITOR_DIR}/include/nodes/internal/TypeConverter.hpp
|
||||
)
|
||||
|
||||
qt5_wrap_cpp(QNODEEDITOR_SOURCES
|
||||
${HEADERS_TO_MOC}
|
||||
TARGET qv2ray
|
||||
OPTIONS --no-notes # Don't display a note for the headers which don't produce a moc_*.cpp
|
||||
)
|
||||
)
|
||||
|
||||
# qt5_wrap_cpp(QNODEEDITOR_SOURCES
|
||||
# ${HEADERS_TO_MOC}
|
||||
# TARGET qv2ray
|
||||
# OPTIONS --no-notes # Don't display a note for the headers which don't produce a moc_*.cpp
|
||||
# )
|
||||
set(QNODEEDITOR_LIBRARY qv2ray-nodeeditor)
|
||||
add_library(${QNODEEDITOR_LIBRARY} STATIC
|
||||
${QNODEEDITOR_SOURCES}
|
||||
${QNODEEDITOR_HEADERS}
|
||||
)
|
||||
target_include_directories(${QNODEEDITOR_LIBRARY} PUBLIC
|
||||
${QNODEEDITOR_INCLUDE_PATH}
|
||||
)
|
||||
target_link_libraries(${QNODEEDITOR_LIBRARY}
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
Qt5::Gui
|
||||
)
|
||||
set(QNODEEDITOR_QRC_RESOURCES ${QNODEEDITOR_DIR}/resources/resources.qrc)
|
||||
elseif(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "package")
|
||||
find_package(NodeEditor REQUIRED CONFIG)
|
||||
find_path(QNODEEDITOR_INCLUDE_PATH NAMES Node.hpp PATH_SUFFIXES nodes/internal)
|
||||
set(QNODEEDITOR_LIBRARY NodeEditor::nodes)
|
||||
find_path(QNODEEDITOR_INCLUDE_PATH Node.hpp PATH_SUFFIXES nodes/internal)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -1,6 +1,11 @@
|
||||
add_definitions(-DQAPPLICATION_CLASS=QApplication)
|
||||
set(SINGLEAPPLICATION_DIR ${CMAKE_SOURCE_DIR}/3rdparty/SingleApplication)
|
||||
set(SINGLEAPPLICATION_SOURCES
|
||||
${SINGLEAPPLICATION_DIR}/singleapplication.cpp
|
||||
${SINGLEAPPLICATION_DIR}/singleapplication_p.cpp
|
||||
)
|
||||
if(QV2RAY_SINGLEAPPLICATION_PROVIDER STREQUAL "module")
|
||||
set(SINGLEAPPLICATION_DIR ${CMAKE_SOURCE_DIR}/3rdparty/SingleApplication)
|
||||
set(SINGLEAPPLICATION_SOURCES
|
||||
${SINGLEAPPLICATION_DIR}/singleapplication.cpp
|
||||
${SINGLEAPPLICATION_DIR}/singleapplication_p.cpp
|
||||
)
|
||||
elseif(QV2RAY_SINGLEAPPLICATION_PROVIDER STREQUAL "package")
|
||||
find_library(SINGLEAPPLICATION_LIBRARY NAMES SingleApplication)
|
||||
find_path(SINGLEAPPLICATION_DIR NAMES singleapplication.h PATH_SUFFIXES singleapplication)
|
||||
endif()
|
||||
|
@ -125,7 +125,7 @@ if(QV2RAY_ZXING_PROVIDER STREQUAL "module")
|
||||
${ZXING_DIR}/src/pdf417/PDFScanningDecoder.cpp
|
||||
${ZXING_DIR}/src/pdf417/PDFHighLevelEncoder.cpp
|
||||
${ZXING_DIR}/src/pdf417/PDFModulusPoly.cpp
|
||||
)
|
||||
)
|
||||
set(ZXING_INCLUDE_PATH
|
||||
${ZXING_DIR}/src
|
||||
${ZXING_DIR}/src/aztec
|
||||
@ -136,10 +136,17 @@ if(QV2RAY_ZXING_PROVIDER STREQUAL "module")
|
||||
${ZXING_DIR}/src/pdf417
|
||||
${ZXING_DIR}/src/qrcode
|
||||
${ZXING_DIR}/src/textcodec
|
||||
)
|
||||
)
|
||||
set(ZXING_LIBRARY qv2ray-zxing)
|
||||
add_library(${ZXING_LIBRARY} STATIC
|
||||
${ZXING_SOURCES}
|
||||
)
|
||||
target_include_directories(${ZXING_LIBRARY} PUBLIC
|
||||
${ZXING_INCLUDE_PATH}
|
||||
)
|
||||
elseif(QV2RAY_ZXING_PROVIDER STREQUAL "package")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(ZXING REQUIRED zxing)
|
||||
set(ZXING_LIBRARY ${ZXING_LIBRARIES})
|
||||
set(ZXING_INCLUDE_PATH ${ZXING_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
44
debian/changelog
vendored
44
debian/changelog
vendored
@ -1,3 +1,47 @@
|
||||
qv2ray (2.6.0~rc4-1) unstable; urgency=medium
|
||||
|
||||
* fix: fixed ssd:// order issue, fixed #635
|
||||
* add: remove connections via delete key
|
||||
* add: added qv2ray://
|
||||
* add: use env QV2RAY_CONFIG_PATH to specify config path, make darkmode theme cross-platform, refactor
|
||||
* add: introducing Qv2rayApplication
|
||||
|
||||
-- Guobang Bi <ymshenyu@gmail.com> Thu, 18 Jun 2020 16:10:05 +0800
|
||||
|
||||
qv2ray (2.6.0~rc3-1) unstable; urgency=medium
|
||||
|
||||
* add: added DNS Settings and GroupRouteManager
|
||||
* fix: bgcolor can't switch to default when swiching to flatwhite/psblack and then back to breeze or other
|
||||
* refactor: change include structure
|
||||
* fix: sort groups by displayName
|
||||
* fix: improve GroupManager performance by 5000%
|
||||
* fix: fixed Recent Connections jumplist
|
||||
* fix: fixed EMBED_TRANSLATIONS option
|
||||
* fix: prevent reading geosite/geoip every time
|
||||
* add: added ICMP as latency tester
|
||||
|
||||
-- Guobang Bi <ymshenyu@gmail.com> Wed, 27 May 2020 18:17:03 +0800
|
||||
|
||||
qv2ray (2.6.0~rc2-1) unstable; urgency=medium
|
||||
|
||||
* fix: fixed tcping message
|
||||
* refactor: refactored auto update algorithm
|
||||
* fix: fixed Windows non-block TCPing
|
||||
* fix: UI tweak, prevent connection list taking too much space
|
||||
|
||||
-- Guobang Bi <ymshenyu@gmail.com> Mon, 18 May 2020 12:01:50 +0800
|
||||
|
||||
qv2ray (2.6.0~rc1-1) unstable; urgency=medium
|
||||
|
||||
* NTP Check
|
||||
* Port Detection
|
||||
* Introduce unit test
|
||||
* Introduce group editor/manager
|
||||
* added vmess v1 upgrader (close #609)
|
||||
* Refactor system proxy
|
||||
|
||||
-- Guobang Bi <ymshenyu@gmail.com> Sun, 17 May 2020 20:23:35 +0800
|
||||
|
||||
qv2ray (2.5.0-1) unstable; urgency=medium
|
||||
|
||||
* updating translations
|
||||
|
6
debian/control
vendored
6
debian/control
vendored
@ -11,6 +11,7 @@ Build-Depends: debhelper (>= 11),
|
||||
protobuf-compiler (>= 3.6.1.3-1~),
|
||||
protobuf-compiler-grpc (>= 1.16.1-1~),
|
||||
qtbase5-dev (>= 5.11.3-1~),
|
||||
qtdeclarative5-dev (>= 5.11.3-1~),
|
||||
qttools5-dev (>= 5.11.3-1~)
|
||||
Standards-Version: 4.5.0
|
||||
Homepage: https://github.com/Qv2ray/Qv2ray
|
||||
@ -21,4 +22,7 @@ Package: qv2ray
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Recommends: v2ray
|
||||
Description: Qv2ray, A Qt frontend for v2ray. Written in c++.
|
||||
Description: Qt frontend for v2ray
|
||||
Project Qv2ray is a flexable cross platform Qt GUI client for V2ray.
|
||||
It makes everything easier by using GUI editors. It also supports
|
||||
ShadowsicksR, Trojan and NaiveProxy by making them plugins.
|
||||
|
4
debian/rules
vendored
4
debian/rules
vendored
@ -16,6 +16,4 @@ export QT_SELECT := 5
|
||||
dh $@ --buildsystem=cmake+ninja
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- -DEMBED_TRANSLATIONS=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
override_dh_auto_test:
|
||||
dh_auto_configure -- -DEMBED_TRANSLATIONS=ON -DBUILD_TESTING=ON
|
||||
|
12
hooks/pre-commit
Executable file
12
hooks/pre-commit
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
STAGE_FILES=$(git diff --cached --name-only --diff-filter=ACM -- 'makespec/BUILDVERSION')
|
||||
#echo $STAGE_FILES
|
||||
if test ${#STAGE_FILES} -gt 0
|
||||
then
|
||||
echo 'BUILDVERSION already changed, not touching'
|
||||
else
|
||||
echo 'Increasing BUILDVERSION'
|
||||
expr $(cat ./makespec/BUILDVERSION) + 1 > ./makespec/BUILDVERSION
|
||||
cat ./makespec/BUILDVERSION
|
||||
git add ./makespec/BUILDVERSION
|
||||
fi
|
1
libs/QJsonStruct
Submodule
1
libs/QJsonStruct
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 91c3ca1c3279448052b6be19dc8157517c35a7ca
|
@ -1 +1 @@
|
||||
5335
|
||||
5697
|
||||
|
@ -1 +1 @@
|
||||
2.5.0
|
||||
2.6.0
|
||||
|
@ -1 +1 @@
|
||||
|
||||
-rc4
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: qv2ray
|
||||
base: core18
|
||||
base: core20
|
||||
adopt-info: qv2ray
|
||||
icon: assets/icons/qv2ray.png
|
||||
|
||||
@ -44,6 +44,15 @@ apps:
|
||||
desktop: "usr/share/applications/qv2ray.desktop"
|
||||
|
||||
parts:
|
||||
ppa:
|
||||
plugin: nil
|
||||
build-packages:
|
||||
- software-properties-common
|
||||
override-pull: |
|
||||
sudo add-apt-repository ppa:ymshenyu/libuv
|
||||
sudo apt-get update
|
||||
sudo apt-get -y dist-upgrade
|
||||
|
||||
qv2ray:
|
||||
plugin: cmake
|
||||
source-type: git
|
||||
@ -51,14 +60,13 @@ parts:
|
||||
parse-info: [usr/share/metainfo/qv2ray.metainfo.xml]
|
||||
build-packages:
|
||||
- build-essential
|
||||
- qttools5-dev-tools
|
||||
- qttools5-dev
|
||||
- qt5-default
|
||||
- libgrpc++-dev
|
||||
- libprotobuf-dev
|
||||
- protobuf-compiler-grpc
|
||||
- ninja-build
|
||||
- pkg-config
|
||||
- libzxingcore-dev
|
||||
stage-packages:
|
||||
- libgcc1
|
||||
- libstdc++6
|
||||
@ -70,11 +78,13 @@ parts:
|
||||
- libqt5network5
|
||||
- libqt5widgets5
|
||||
- libglib2.0-bin
|
||||
configflags:
|
||||
- libzxingcore1
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -GNinja
|
||||
- -DEMBED_TRANSLATIONS=ON
|
||||
- -DFALL_BACK_TO_XDG_OPEN=ON
|
||||
- -DQV2RAY_ZXING_PROVIDER=package
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
build_number=$(cat makespec/BUILDVERSION)
|
||||
@ -84,7 +94,6 @@ parts:
|
||||
sed -i 's|^Icon=.*|Icon=/usr/share/icons/hicolor/256x256/apps/qv2ray.png|g' assets/qv2ray.desktop
|
||||
after:
|
||||
- desktop-qt5
|
||||
- ppa
|
||||
|
||||
desktop-qt5:
|
||||
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
|
||||
@ -110,21 +119,70 @@ parts:
|
||||
- locales-all
|
||||
- xdg-user-dirs
|
||||
- fcitx-frontend-qt5
|
||||
after:
|
||||
- ppa
|
||||
|
||||
qt5-gtk-platform:
|
||||
plugin: nil
|
||||
stage-packages:
|
||||
- qt5-gtk-platformtheme
|
||||
after:
|
||||
- ppa
|
||||
|
||||
ppa:
|
||||
plugin: nil
|
||||
qv2ray-ssr-plugin:
|
||||
plugin: cmake
|
||||
source-type: git
|
||||
source: https://github.com/Qv2ray/QvPlugin-SSR.git
|
||||
source-branch: dev
|
||||
build-packages:
|
||||
- software-properties-common
|
||||
- dirmngr
|
||||
override-build: |
|
||||
sudo add-apt-repository -y ppa:ymshenyu/qv2ray-deps
|
||||
sudo apt-get dist-upgrade -y
|
||||
- build-essential
|
||||
- libsodium-dev
|
||||
- libuv1-dev
|
||||
- libssl-dev
|
||||
- qttools5-dev
|
||||
- qt5-default
|
||||
stage-packages:
|
||||
- libgcc1
|
||||
- libstdc++6
|
||||
- libssl1.1
|
||||
- libqt5core5a
|
||||
- libqt5gui5
|
||||
- libqt5network5
|
||||
- libqt5widgets5
|
||||
- libuv1
|
||||
- libsodium23
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DSSR_UVW_WITH_QT=ON
|
||||
- -DUSE_SYSTEM_SODIUM=ON
|
||||
- -DUSE_SYSTEM_LIBUV=ON
|
||||
- -DSTATIC_LINK_LIBUV=OFF
|
||||
- -DSTATIC_LINK_SODIUM=OFF
|
||||
after:
|
||||
- desktop-qt5
|
||||
|
||||
qv2ray-trojan-plugin:
|
||||
plugin: cmake
|
||||
source-type: git
|
||||
source: https://github.com/Qv2ray/QvPlugin-Trojan.git
|
||||
source-branch: dev
|
||||
build-packages:
|
||||
- build-essential
|
||||
- libboost-system-dev
|
||||
- libboost-program-options-dev
|
||||
- libssl-dev
|
||||
- qttools5-dev
|
||||
- qt5-default
|
||||
stage-packages:
|
||||
- libgcc1
|
||||
- libstdc++6
|
||||
- libssl1.1
|
||||
- libqt5core5a
|
||||
- libqt5gui5
|
||||
- libqt5network5
|
||||
- libqt5widgets5
|
||||
- libboost-program-options1.71.0
|
||||
- libboost-system1.71.0
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DFORCE_TCP_FASTOPEN=ON
|
||||
after:
|
||||
- desktop-qt5
|
541
src/Qv2rayApplication.cpp
Normal file
541
src/Qv2rayApplication.cpp
Normal file
@ -0,0 +1,541 @@
|
||||
#include "Qv2rayApplication.hpp"
|
||||
|
||||
#include "3rdparty/libsemver/version.hpp"
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
#include "common/QvTranslator.hpp"
|
||||
#include "core/handler/ConfigHandler.hpp"
|
||||
#include "core/handler/RouteHandler.hpp"
|
||||
#include "core/settings/SettingsBackend.hpp"
|
||||
#include "ui/styles/StyleManager.hpp"
|
||||
#include "ui/windows/w_MainWindow.hpp"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Winbase.h>
|
||||
#endif
|
||||
|
||||
namespace Qv2ray
|
||||
{
|
||||
constexpr auto QV2RAY_CONFIG_PATH_ENV_NAME = "QV2RAY_CONFIG_PATH";
|
||||
|
||||
Qv2rayApplication::Qv2rayApplication(int &argc, char *argv[])
|
||||
#ifdef Q_OS_ANDROID
|
||||
: QApplication(argc, argv)
|
||||
#else
|
||||
: SingleApplication(argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion)
|
||||
#endif
|
||||
{
|
||||
LOG(MODULE_INIT, "Qv2ray " QV2RAY_VERSION_STRING " on " + QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture())
|
||||
DEBUG(MODULE_INIT, "Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay()))
|
||||
DEBUG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO)
|
||||
DEBUG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
|
||||
DEBUG("QV2RAY_BUILD_NUMBER", QSTRN(QV2RAY_VERSION_BUILD))
|
||||
hTray = new QSystemTrayIcon();
|
||||
}
|
||||
|
||||
void Qv2rayApplication::QuitApplication(int retCode)
|
||||
{
|
||||
isExiting = true;
|
||||
QCoreApplication::exit(retCode);
|
||||
}
|
||||
|
||||
Qv2rayApplication::Qv2raySetupStatus Qv2rayApplication::SetupQv2ray()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
SetCurrentDirectory(applicationDirPath().toStdWString().c_str());
|
||||
#endif
|
||||
// Install a default translater. From the OS/DE
|
||||
Qv2rayTranslator = std::make_unique<QvTranslator>();
|
||||
Qv2rayTranslator->InstallTranslation(QLocale::system().name());
|
||||
//
|
||||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
connect(this, &SingleApplication::receivedMessage, this, &Qv2rayApplication::onMessageReceived);
|
||||
connect(this, &SingleApplication::aboutToQuit, this, &Qv2rayApplication::aboutToQuitSlot);
|
||||
if (isSecondary())
|
||||
{
|
||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::NORMAL;
|
||||
sendMessage(JsonToString(Qv2rayProcessArgument.toJson(), QJsonDocument::Compact).toUtf8());
|
||||
return SINGLE_APPLICATION;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// Set special font in Windows
|
||||
QFont font;
|
||||
font.setPointSize(9);
|
||||
font.setFamily("Microsoft YaHei");
|
||||
setFont(font);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
setFallbackSessionManagementEnabled(false);
|
||||
connect(this, &QGuiApplication::commitDataRequest, [] {
|
||||
ConnectionManager->SaveConnectionConfig();
|
||||
LOG(MODULE_INIT, "Quit triggered by session manager.")
|
||||
});
|
||||
#endif
|
||||
return NORMAL;
|
||||
}
|
||||
|
||||
void Qv2rayApplication::aboutToQuitSlot()
|
||||
{
|
||||
delete mainWindow;
|
||||
delete hTray;
|
||||
delete ConnectionManager;
|
||||
delete RouteManager;
|
||||
delete PluginHost;
|
||||
delete StyleManager;
|
||||
}
|
||||
|
||||
void Qv2rayApplication::onMessageReceived(quint32 clientId, QByteArray _msg)
|
||||
{
|
||||
// Sometimes SingleApplication will send message with clientId == 0, ignore them.
|
||||
if (clientId == instanceId())
|
||||
return;
|
||||
const auto msg = Qv2rayProcessArguments::fromJson(JsonFromString(_msg));
|
||||
LOG(MODULE_INIT, "Client ID: " + QSTRN(clientId) + ", message received, version: " + msg.version)
|
||||
DEBUG(MODULE_INIT, _msg)
|
||||
//
|
||||
const auto currentVersion = semver::version::from_string(QV2RAY_VERSION_STRING);
|
||||
const auto newVersionString = msg.version.isEmpty() ? "0.0.0" : msg.version.toStdString();
|
||||
const auto newVersion = semver::version::from_string(newVersionString);
|
||||
//
|
||||
if (newVersion > currentVersion)
|
||||
{
|
||||
QTimer::singleShot(0, [=]() {
|
||||
const auto newPath = msg.fullArgs.first();
|
||||
QString message;
|
||||
message += tr("A new version of Qv2ray is attemping to start:") + NEWLINE;
|
||||
message += NEWLINE;
|
||||
message += tr("New version information: ") + NEWLINE;
|
||||
message += tr("Qv2ray version: %1").arg(msg.version) + NEWLINE;
|
||||
message += tr("Qv2ray path: %1").arg(newPath) + NEWLINE;
|
||||
message += NEWLINE;
|
||||
message += tr("Do you want to exit and launch that new version?");
|
||||
|
||||
const auto result = QvMessageBoxAsk(nullptr, tr("New version detected"), message);
|
||||
if (result == QMessageBox::Yes)
|
||||
{
|
||||
Qv2rayProcessArgument._qvNewVersionPath = newPath;
|
||||
QuitApplication(QV2RAY_NEW_VERSION);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const auto &argument : msg.arguments)
|
||||
{
|
||||
switch (argument)
|
||||
{
|
||||
case Qv2rayProcessArguments::EXIT:
|
||||
{
|
||||
QuitApplication();
|
||||
break;
|
||||
}
|
||||
case Qv2rayProcessArguments::NORMAL:
|
||||
{
|
||||
mainWindow->show();
|
||||
mainWindow->raise();
|
||||
mainWindow->activateWindow();
|
||||
break;
|
||||
}
|
||||
case Qv2rayProcessArguments::RECONNECT:
|
||||
{
|
||||
ConnectionManager->RestartConnection();
|
||||
break;
|
||||
}
|
||||
case Qv2rayProcessArguments::DISCONNECT:
|
||||
{
|
||||
ConnectionManager->StopConnection();
|
||||
break;
|
||||
}
|
||||
case Qv2rayProcessArguments::QV2RAY_LINK:
|
||||
{
|
||||
for (const auto &link : msg.links)
|
||||
{
|
||||
const auto url = QUrl::fromUserInput(link);
|
||||
const auto command = url.host();
|
||||
auto subcommands = url.path().split("/");
|
||||
subcommands.removeAll("");
|
||||
QMap<QString, QString> args;
|
||||
for (const auto &kvp : QUrlQuery(url).queryItems())
|
||||
{
|
||||
args.insert(kvp.first, kvp.second);
|
||||
}
|
||||
if (command == "open")
|
||||
{
|
||||
emit mainWindow->ProcessCommand(command, subcommands, args);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Qv2rayExitCode Qv2rayApplication::RunQv2ray()
|
||||
{
|
||||
// Show MainWindow
|
||||
mainWindow = new MainWindow();
|
||||
return Qv2rayExitCode(exec());
|
||||
}
|
||||
|
||||
bool Qv2rayApplication::FindAndCreateInitialConfiguration()
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
LOG(MODULE_INIT, "Qv2ray has already been initialized!")
|
||||
return false;
|
||||
}
|
||||
LOG(MODULE_INIT, "Application exec path: " + applicationDirPath())
|
||||
// Non-standard paths needs special handing for "_debug"
|
||||
const auto currentPathConfig = applicationDirPath() + "/config" QV2RAY_CONFIG_DIR_SUFFIX;
|
||||
const auto homeQv2ray = QDir::homePath() + "/.qv2ray" QV2RAY_CONFIG_DIR_SUFFIX;
|
||||
//
|
||||
// Standard paths already handles the "_debug" suffix for us.
|
||||
const auto configQv2ray = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
//
|
||||
//
|
||||
// Some built-in search paths for Qv2ray to find configs. (load the first one if possible).
|
||||
QStringList configFilePaths;
|
||||
const auto useManualConfigPath = qEnvironmentVariableIsSet(QV2RAY_CONFIG_PATH_ENV_NAME);
|
||||
const auto manualConfigPath = qEnvironmentVariable(QV2RAY_CONFIG_PATH_ENV_NAME);
|
||||
if (useManualConfigPath)
|
||||
{
|
||||
LOG(MODULE_INIT, "Using config path from env: " + manualConfigPath)
|
||||
configFilePaths << manualConfigPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
configFilePaths << currentPathConfig;
|
||||
configFilePaths << configQv2ray;
|
||||
configFilePaths << homeQv2ray;
|
||||
}
|
||||
QString configPath = "";
|
||||
bool hasExistingConfig = false;
|
||||
|
||||
for (const 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 existence as
|
||||
// well. ----------------------------------------------|HERE|
|
||||
bool isValidConfigPath = CheckSettingsPathAvailability(path, true);
|
||||
|
||||
// If we already found a valid config file. just simply load it...
|
||||
if (hasExistingConfig)
|
||||
break;
|
||||
|
||||
if (isValidConfigPath)
|
||||
{
|
||||
DEBUG(MODULE_INIT, "Path: " + path + " is valid.")
|
||||
configPath = path;
|
||||
hasExistingConfig = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(MODULE_INIT, "Path: " + path + " does not contain a valid config file.")
|
||||
}
|
||||
}
|
||||
|
||||
if (hasExistingConfig)
|
||||
{
|
||||
// Use the config path found by the checks above
|
||||
SetConfigDirPath(configPath);
|
||||
LOG(MODULE_INIT, "Using " + QV2RAY_CONFIG_DIR + " as the config path.")
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's no existing config.
|
||||
//
|
||||
// Create new config at these dirs, these are default values for each platform.
|
||||
if (useManualConfigPath)
|
||||
{
|
||||
configPath = manualConfigPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(Q_OS_WIN) && !defined(QV2RAY_NO_ASIDECONFIG)
|
||||
configPath = currentPathConfig;
|
||||
#else
|
||||
configPath = configQv2ray;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool hasPossibleNewLocation = QDir().mkpath(configPath) && CheckSettingsPathAvailability(configPath, false);
|
||||
// Check if the dirs are write-able
|
||||
if (!hasPossibleNewLocation)
|
||||
{
|
||||
// None of the path above can be used as a dir for storing config.
|
||||
// Even the last folder failed to pass the check.
|
||||
LOG(MODULE_INIT, "FATAL")
|
||||
LOG(MODULE_INIT, " ---> CANNOT find a proper place to store Qv2ray config files.")
|
||||
QvMessageBoxWarn(nullptr, tr("Cannot Start Qv2ray"),
|
||||
tr("Cannot find a place to store config files.") + NEWLINE + //
|
||||
tr("Qv2ray has searched these paths below:") + NEWLINE + NEWLINE + //
|
||||
configFilePaths.join(NEWLINE) + NEWLINE + //
|
||||
tr("It usually means you don't have the write permission to all of those locations.") + NEWLINE + //
|
||||
tr("Qv2ray will now exit.")); //
|
||||
return false;
|
||||
}
|
||||
|
||||
// Found a valid config dir, with write permission, but assume no config is located in it.
|
||||
LOG(MODULE_INIT, "Set " + configPath + " as the config path.")
|
||||
SetConfigDirPath(configPath);
|
||||
|
||||
if (QFile::exists(QV2RAY_CONFIG_FILE))
|
||||
{
|
||||
// As we already tried to load config from every possible dir.
|
||||
//
|
||||
// This condition branch (!hasExistingConfig check) holds the fact that current config dir,
|
||||
// should NOT contain any valid file (at least in the same name)
|
||||
//
|
||||
// It usually means that QV2RAY_CONFIG_FILE here has a corrupted JSON format.
|
||||
//
|
||||
// Otherwise Qv2ray would have loaded this config already instead of notifying to create a new config in this folder.
|
||||
//
|
||||
LOG(MODULE_INIT, "This should not occur: Qv2ray config exists but failed to load.")
|
||||
QvMessageBoxWarn(nullptr, tr("Failed to initialise Qv2ray"),
|
||||
tr("Failed to determine the location of config file:") + NEWLINE + //
|
||||
tr("Qv2ray has found a config file, but it failed to be loaded due to some errors.") + NEWLINE + //
|
||||
tr("A workaround is to remove the this file and restart Qv2ray:") + NEWLINE + //
|
||||
QV2RAY_CONFIG_FILE + NEWLINE + //
|
||||
tr("Qv2ray will now exit.") + NEWLINE + //
|
||||
tr("Please report if you think it's a bug.")); //
|
||||
return false;
|
||||
}
|
||||
|
||||
Qv2rayConfigObject conf;
|
||||
conf.kernelConfig.KernelPath(QString(QV2RAY_DEFAULT_VCORE_PATH));
|
||||
conf.kernelConfig.AssetsPath(QString(QV2RAY_DEFAULT_VASSETS_PATH));
|
||||
conf.logLevel = 3;
|
||||
conf.uiConfig.language = QLocale::system().name();
|
||||
conf.defaultRouteConfig.dnsConfig.servers << QvConfig_DNS::DNSServerObject{ "1.1.1.1" } //
|
||||
<< QvConfig_DNS::DNSServerObject{ "8.8.8.8" } //
|
||||
<< QvConfig_DNS::DNSServerObject{ "8.8.4.4" };
|
||||
|
||||
// Save initial config.
|
||||
SaveGlobalSettings(conf);
|
||||
LOG(MODULE_INIT, "Created initial config file.")
|
||||
}
|
||||
|
||||
if (!QDir(QV2RAY_GENERATED_DIR).exists())
|
||||
{
|
||||
// The dir used to generate final config file, for V2ray interaction.
|
||||
QDir().mkdir(QV2RAY_GENERATED_DIR);
|
||||
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Qv2rayApplication::LoadConfiguration()
|
||||
{
|
||||
// Load the config for upgrade, but do not parse it to the struct.
|
||||
auto conf = JsonFromString(StringFromFile(QV2RAY_CONFIG_FILE));
|
||||
const auto configVersion = conf["config_version"].toInt();
|
||||
|
||||
if (configVersion > QV2RAY_CONFIG_VERSION)
|
||||
{
|
||||
// Config version is larger than the current version...
|
||||
// This is rare but it may happen....
|
||||
QvMessageBoxWarn(nullptr, tr("Qv2ray Cannot Continue"), //
|
||||
tr("You are running a lower version of Qv2ray compared to the current config file.") + NEWLINE + //
|
||||
tr("Please check if there's an issue explaining about it.") + NEWLINE + //
|
||||
tr("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE + //
|
||||
tr("Qv2ray will now exit."));
|
||||
return false;
|
||||
}
|
||||
else if (configVersion < QV2RAY_CONFIG_VERSION)
|
||||
{
|
||||
// That is the config file needs to be upgraded.
|
||||
conf = Qv2ray::UpgradeSettingsVersion(configVersion, QV2RAY_CONFIG_VERSION, conf);
|
||||
}
|
||||
|
||||
// Load config object from upgraded config QJsonObject
|
||||
auto confObject = Qv2rayConfigObject::fromJson(conf);
|
||||
|
||||
if (!Qv2rayTranslator->GetAvailableLanguages().contains(confObject.uiConfig.language))
|
||||
{
|
||||
// Prevent empty.
|
||||
LOG(MODULE_UI, "Setting default UI language to system locale.")
|
||||
confObject.uiConfig.language = QLocale::system().name();
|
||||
}
|
||||
|
||||
if (!Qv2rayTranslator->InstallTranslation(confObject.uiConfig.language))
|
||||
{
|
||||
QvMessageBoxWarn(nullptr, "Translation Failed",
|
||||
"Cannot load translation for " + confObject.uiConfig.language + NEWLINE + //
|
||||
"English is now used." + NEWLINE + NEWLINE + //
|
||||
"Please go to Preferences Window to change language or open an Issue");
|
||||
}
|
||||
|
||||
// Let's save the config.
|
||||
SaveGlobalSettings(confObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Qv2rayApplication::InitializeGlobalVariables()
|
||||
{
|
||||
StyleManager = new QvStyleManager();
|
||||
PluginHost = new QvPluginHost();
|
||||
RouteManager = new RouteHandler();
|
||||
ConnectionManager = new QvConfigHandler();
|
||||
StyleManager->ApplyStyle(GlobalConfig.uiConfig.theme);
|
||||
}
|
||||
|
||||
bool Qv2rayApplication::PreInitialize(int argc, char **argv)
|
||||
{
|
||||
QString errorMessage;
|
||||
|
||||
{
|
||||
QCoreApplication coreApp(argc, argv);
|
||||
const auto &args = coreApp.arguments();
|
||||
Qv2rayProcessArgument.version = QV2RAY_VERSION_STRING;
|
||||
Qv2rayProcessArgument.fullArgs = args;
|
||||
switch (ParseCommandLine(&errorMessage, args))
|
||||
{
|
||||
case QV2RAY_QUIT: return false;
|
||||
case QV2RAY_ERROR: LOG(MODULE_INIT, errorMessage) return false;
|
||||
default: break;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
const auto urlScheme = coreApp.applicationName();
|
||||
const auto appPath = QDir::toNativeSeparators(coreApp.applicationFilePath());
|
||||
const auto regPath = "HKEY_CURRENT_USER\\Software\\Classes\\" + urlScheme;
|
||||
|
||||
QSettings reg(regPath, QSettings::NativeFormat);
|
||||
|
||||
reg.setValue("Default", "Qv2ray");
|
||||
reg.setValue("URL Protocol", "");
|
||||
|
||||
reg.beginGroup("DefaultIcon");
|
||||
reg.setValue("Default", QString("%1,1").arg(appPath));
|
||||
reg.endGroup();
|
||||
|
||||
reg.beginGroup("shell");
|
||||
reg.beginGroup("open");
|
||||
reg.beginGroup("command");
|
||||
reg.setValue("Default", appPath + " %1");
|
||||
#endif
|
||||
}
|
||||
|
||||
// noScaleFactors = disable HiDPI
|
||||
if (StartupOption.noScaleFactor)
|
||||
{
|
||||
LOG(MODULE_INIT, "Force set QT_SCALE_FACTOR to 1.")
|
||||
DEBUG(MODULE_UI, "Original QT_SCALE_FACTOR was: " + qEnvironmentVariable("QT_SCALE_FACTOR"))
|
||||
qputenv("QT_SCALE_FACTOR", "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(MODULE_INIT, "High DPI scaling is enabled.")
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Qv2rayApplication::commandline_status Qv2rayApplication::ParseCommandLine(QString *errorMessage, const QStringList &args)
|
||||
{
|
||||
QCommandLineParser parser;
|
||||
//
|
||||
QCommandLineOption noAPIOption("noAPI", tr("Disable gRPC API subsystem"));
|
||||
QCommandLineOption noPluginsOption("noPlugin", tr("Disable plugins feature"));
|
||||
QCommandLineOption noScaleFactorOption("noScaleFactor", tr("Disable Qt UI scale factor"));
|
||||
QCommandLineOption debugOption("debug", tr("Enable debug output"));
|
||||
QCommandLineOption disconnectOption("disconnect", tr("Stop current connection"));
|
||||
QCommandLineOption reconnectOption("reconnect", tr("Reconnect last connection"));
|
||||
QCommandLineOption exitOption("exit", tr("Exit Qv2ray"));
|
||||
//
|
||||
parser.setApplicationDescription(tr("Qv2ray - A cross-platform Qt frontend for V2ray."));
|
||||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||
//
|
||||
parser.addOption(noAPIOption);
|
||||
parser.addOption(noPluginsOption);
|
||||
parser.addOption(noScaleFactorOption);
|
||||
parser.addOption(debugOption);
|
||||
parser.addOption(disconnectOption);
|
||||
parser.addOption(reconnectOption);
|
||||
parser.addOption(exitOption);
|
||||
//
|
||||
auto helpOption = parser.addHelpOption();
|
||||
auto versionOption = parser.addVersionOption();
|
||||
|
||||
if (!parser.parse(args))
|
||||
{
|
||||
*errorMessage = parser.errorText();
|
||||
return QV2RAY_ERROR;
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption))
|
||||
{
|
||||
parser.showVersion();
|
||||
return QV2RAY_QUIT;
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption))
|
||||
{
|
||||
parser.showHelp();
|
||||
return QV2RAY_QUIT;
|
||||
}
|
||||
|
||||
for (const auto &arg : parser.positionalArguments())
|
||||
{
|
||||
if (arg.startsWith("qv2ray://"))
|
||||
{
|
||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::QV2RAY_LINK;
|
||||
Qv2rayProcessArgument.links << arg;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet(exitOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "disconnectOption is set.")
|
||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::EXIT;
|
||||
}
|
||||
|
||||
if (parser.isSet(disconnectOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "disconnectOption is set.")
|
||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::DISCONNECT;
|
||||
}
|
||||
|
||||
if (parser.isSet(reconnectOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "reconnectOption is set.")
|
||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::RECONNECT;
|
||||
}
|
||||
|
||||
if (parser.isSet(noAPIOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "noAPIOption is set.")
|
||||
StartupOption.noAPI = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(debugOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "debugOption is set.")
|
||||
StartupOption.debugLog = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(noScaleFactorOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "noScaleFactorOption is set.")
|
||||
StartupOption.noScaleFactor = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(noPluginsOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "noPluginOption is set.")
|
||||
StartupOption.noPlugins = true;
|
||||
}
|
||||
|
||||
return QV2RAY_CONTINUE;
|
||||
}
|
||||
|
||||
} // namespace Qv2ray
|
108
src/Qv2rayApplication.hpp
Normal file
108
src/Qv2rayApplication.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "libs/QJsonStruct/QJsonStruct.hpp"
|
||||
|
||||
#include <QSystemTrayIcon>
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QApplication>
|
||||
#else
|
||||
#include <SingleApplication>
|
||||
#endif
|
||||
class MainWindow;
|
||||
|
||||
namespace Qv2ray
|
||||
{
|
||||
enum Qv2rayExitCode
|
||||
{
|
||||
QV2RAY_NORMAL = 0,
|
||||
QV2RAY_SECONDARY_INSTANCE = 0,
|
||||
QV2RAY_PRE_INITIALIZE_FAIL = -1,
|
||||
QV2RAY_EARLY_SETUP_FAIL = -2,
|
||||
QV2RAY_CONFIG_PATH_FAIL = -3,
|
||||
QV2RAY_CONFIG_FILE_FAIL = -4,
|
||||
QV2RAY_SSL_FAIL = -5,
|
||||
QV2RAY_NEW_VERSION = -6
|
||||
};
|
||||
struct Qv2rayProcessArguments
|
||||
{
|
||||
enum Argument
|
||||
{
|
||||
NORMAL = 0,
|
||||
QV2RAY_LINK = 1,
|
||||
EXIT = 2,
|
||||
RECONNECT = 3,
|
||||
DISCONNECT = 4
|
||||
};
|
||||
QList<Argument> arguments;
|
||||
QString version;
|
||||
QString data;
|
||||
QList<QString> links;
|
||||
QList<QString> fullArgs;
|
||||
//
|
||||
QString _qvNewVersionPath;
|
||||
JSONSTRUCT_REGISTER(Qv2rayProcessArguments, F(arguments, version, data, links, fullArgs))
|
||||
};
|
||||
|
||||
inline Qv2rayProcessArguments Qv2rayProcessArgument;
|
||||
#ifdef Q_OS_ANDROID
|
||||
class Qv2rayApplication : public QApplication
|
||||
#else
|
||||
class Qv2rayApplication : public SingleApplication
|
||||
#endif
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
enum commandline_status
|
||||
{
|
||||
QV2RAY_ERROR,
|
||||
QV2RAY_QUIT,
|
||||
QV2RAY_CONTINUE
|
||||
};
|
||||
|
||||
public:
|
||||
enum Qv2raySetupStatus
|
||||
{
|
||||
NORMAL,
|
||||
SINGLE_APPLICATION,
|
||||
FAILED
|
||||
};
|
||||
//
|
||||
void QuitApplication(int retCode = 0);
|
||||
static bool PreInitialize(int argc, char **argv);
|
||||
explicit Qv2rayApplication(int &argc, char *argv[]);
|
||||
Qv2raySetupStatus SetupQv2ray();
|
||||
bool FindAndCreateInitialConfiguration();
|
||||
bool LoadConfiguration();
|
||||
void InitializeGlobalVariables();
|
||||
Qv2rayExitCode RunQv2ray();
|
||||
|
||||
public:
|
||||
QSystemTrayIcon **GetTrayIcon()
|
||||
{
|
||||
return &hTray;
|
||||
}
|
||||
void showMessage(const QString &m, const QIcon &icon, int msecs = 10000)
|
||||
{
|
||||
hTray->showMessage("Qv2ray", m, icon, msecs);
|
||||
}
|
||||
void showMessage(const QString &m, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000)
|
||||
{
|
||||
hTray->showMessage("Qv2ray", m, icon, msecs);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void aboutToQuitSlot();
|
||||
void onMessageReceived(quint32 clientID, QByteArray msg);
|
||||
|
||||
private:
|
||||
QSystemTrayIcon *hTray;
|
||||
MainWindow *mainWindow;
|
||||
static commandline_status ParseCommandLine(QString *errorMessage, const QStringList &args);
|
||||
bool initialized = false;
|
||||
};
|
||||
} // namespace Qv2ray
|
||||
|
||||
using namespace Qv2ray;
|
||||
|
||||
#define qvApp (dynamic_cast<Qv2ray::Qv2rayApplication *>(QCoreApplication::instance()))
|
||||
#define qvAppTrayIcon (*qvApp->GetTrayIcon())
|
91
src/StackTraceHelper.cpp
Normal file
91
src/StackTraceHelper.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "StackTraceHelper.hpp"
|
||||
namespace Qv2ray
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
QString StackTraceHelper::GetStackTraceImpl_Unix()
|
||||
{
|
||||
backward::StackTrace st;
|
||||
backward::TraceResolver resolver;
|
||||
st.load_here();
|
||||
resolver.load_stacktrace(st);
|
||||
//
|
||||
#ifdef QV2RAY_PRINT_FULL_BACKTRACE
|
||||
backward::Printer p;
|
||||
std::stringstream o;
|
||||
p.print(st, o);
|
||||
QString msg;
|
||||
msg += QString::fromStdString(o.str());
|
||||
return msg;
|
||||
#else
|
||||
QString msg;
|
||||
for (size_t i = 0; i < st.size(); i++)
|
||||
{
|
||||
/*
|
||||
* It works because in real life, most signals are not around failures of the memory allocator (ie: malloc) itself.
|
||||
* As long as you can allocate memory, you are pretty ok.
|
||||
* Now, here is an example where backward will deadlock:
|
||||
*
|
||||
* you buffer overflow inside your allocator data structure
|
||||
* you ask your allocator to free or allocate something
|
||||
* allocator acquires some locks
|
||||
* allocator shit itself because its datastructures are corrupted
|
||||
* signal is raised, backward-cpp kicks in
|
||||
* while walking the stack, backward-cpp tries to allocate memory, calling your allocator...
|
||||
* allocator tries to acquires some locks...
|
||||
*
|
||||
* oops, deadlock.
|
||||
*/
|
||||
auto trace = resolver.resolve(st[i]);
|
||||
QString sourceFile;
|
||||
if (!trace.source.filename.empty())
|
||||
sourceFile = QString("%0:[%1:%2]").arg(trace.source.filename.c_str()).arg(trace.source.line).arg(trace.source.col);
|
||||
else
|
||||
sourceFile = "[N/A]";
|
||||
|
||||
// #Index: [ADDRESS] Function File Line:Col
|
||||
msg += QString("#%1: [%2] %3 in %4 --> %5\r\n")
|
||||
.arg(i)
|
||||
.arg(reinterpret_cast<size_t>(trace.addr))
|
||||
.arg(trace.object_function.c_str())
|
||||
.arg(trace.object_filename.c_str())
|
||||
.arg(sourceFile);
|
||||
}
|
||||
return msg;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString StackTraceHelper::GetStackTraceImpl_Windows()
|
||||
{
|
||||
void *stack[1024];
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
SymSetOptions(SYMOPT_LOAD_ANYTHING);
|
||||
WORD numberOfFrames = CaptureStackBackTrace(0, 1024, stack, NULL);
|
||||
SYMBOL_INFO *symbol = (SYMBOL_INFO *) malloc(sizeof(SYMBOL_INFO) + (512 - 1) * sizeof(TCHAR));
|
||||
symbol->MaxNameLen = 512;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
DWORD displacement;
|
||||
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *) malloc(sizeof(IMAGEHLP_LINE64));
|
||||
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
//
|
||||
QString msg;
|
||||
//
|
||||
for (int i = 0; i < numberOfFrames; i++)
|
||||
{
|
||||
const auto address = (DWORD64) stack[i];
|
||||
SymFromAddr(process, address, NULL, symbol);
|
||||
if (SymGetLineFromAddr64(process, address, &displacement, line))
|
||||
{
|
||||
msg += QString("[%1]: %2 (%3:%4)\r\n").arg(symbol->Address).arg(symbol->Name).arg(line->FileName).arg(line->LineNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg += QString("[%1]: %2 SymGetLineFromAddr64[%3]\r\n").arg(symbol->Address).arg(symbol->Name).arg(GetLastError());
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
#endif
|
||||
} // namespace Qv2ray
|
36
src/StackTraceHelper.hpp
Normal file
36
src/StackTraceHelper.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#ifdef Q_OS_UNIX
|
||||
#include "backward.hpp"
|
||||
|
||||
#include <vector>
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
//
|
||||
#include <DbgHelp.h>
|
||||
#endif
|
||||
|
||||
namespace Qv2ray
|
||||
{
|
||||
class StackTraceHelper
|
||||
{
|
||||
public:
|
||||
static QString GetStackTrace()
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
return GetStackTraceImpl_Unix();
|
||||
#elif defined(Q_OS_WIN)
|
||||
return GetStackTraceImpl_Windows();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef Q_OS_UNIX
|
||||
static QString GetStackTraceImpl_Unix();
|
||||
#elif defined(Q_OS_WIN)
|
||||
static QString GetStackTraceImpl_Windows();
|
||||
#endif
|
||||
};
|
||||
} // namespace Qv2ray
|
@ -7,42 +7,13 @@
|
||||
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
|
||||
#define CONCATENATE2(arg1, arg2) arg1##arg2
|
||||
|
||||
#define EXPAND(x) x
|
||||
#define FOR_EACH_1(what, x, ...) what(x)
|
||||
|
||||
#define FOR_EACH_2(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
|
||||
#define FOR_EACH_3(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
|
||||
#define FOR_EACH_4(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
|
||||
#define FOR_EACH_5(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
|
||||
#define FOR_EACH_6(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
|
||||
#define FOR_EACH_7(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
|
||||
#define FOR_EACH_8(what, x, ...) \
|
||||
what(x); \
|
||||
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
|
||||
|
||||
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
|
||||
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
|
||||
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
|
||||
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define CONCATENATE(x, y) x##y
|
||||
#define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__))
|
||||
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
|
||||
#define JADDEx_(jsonObj, field) jsonObj.insert(#field, field);
|
||||
#define JADDEx(field) JADDEx_(root, field)
|
||||
|
||||
// Add key value pair into JSON named 'root'
|
||||
#define JADDEx(field) root.insert(#field, field);
|
||||
#define JADD(...) FOR_EACH(JADDEx, __VA_ARGS__)
|
||||
|
||||
#define RROOT return root;
|
||||
#define JAUTOREMOVE(jObj, key) \
|
||||
{ \
|
||||
if ((jObj[key].isArray() && jObj[key].toArray().isEmpty()) || (jObj[key].isObject() && jObj[key].toObject().isEmpty()) || \
|
||||
(jObj[key].isString() && jObj[key].toString().isEmpty())) \
|
||||
jObj.remove(key); \
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
//
|
||||
#include <QApplication>
|
||||
#include <QMap>
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
@ -21,8 +19,6 @@
|
||||
#include "base/models/QvSettingsObject.hpp"
|
||||
#include "base/models/QvStartupConfig.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace Qv2ray;
|
||||
using namespace Qv2ray::base;
|
||||
using namespace Qv2ray::base::safetype;
|
||||
@ -31,6 +27,18 @@ using namespace Qv2ray::base::objects;
|
||||
using namespace Qv2ray::base::objects::protocol;
|
||||
using namespace Qv2ray::base::objects::transfer;
|
||||
|
||||
class _qv2ray_global_config_impl_details
|
||||
{
|
||||
public:
|
||||
static Qv2rayConfigObject _GlobalConfig;
|
||||
static bool _isExiting;
|
||||
static QString _Qv2rayConfigPath;
|
||||
};
|
||||
|
||||
#define GlobalConfig (_qv2ray_global_config_impl_details::_GlobalConfig)
|
||||
#define isExiting (_qv2ray_global_config_impl_details::_isExiting)
|
||||
#define Qv2rayConfigPath (_qv2ray_global_config_impl_details::_Qv2rayConfigPath)
|
||||
|
||||
#define QV2RAY_BUILD_INFO QString(_QV2RAY_BUILD_INFO_STR_)
|
||||
#define QV2RAY_BUILD_EXTRA_INFO QString(_QV2RAY_BUILD_EXTRA_INFO_STR_)
|
||||
|
||||
@ -42,17 +50,14 @@ using namespace Qv2ray::base::objects::transfer;
|
||||
#endif
|
||||
|
||||
// Get Configured Config Dir Path
|
||||
#define QV2RAY_CONFIG_DIR (Qv2ray::Qv2rayConfigPath)
|
||||
#define QV2RAY_CONFIG_DIR (Qv2rayConfigPath)
|
||||
#define QV2RAY_CONFIG_FILE (QV2RAY_CONFIG_DIR + "Qv2ray.conf")
|
||||
//
|
||||
#define QV2RAY_ROUTING_DIR (QV2RAY_CONFIG_DIR + "rounting/")
|
||||
#define QV2RAY_CONNECTIONS_DIR (QV2RAY_CONFIG_DIR + "connections/")
|
||||
#define QV2RAY_SUBSCRIPTION_DIR (QV2RAY_CONFIG_DIR + "subscriptions/")
|
||||
//
|
||||
#define QV2RAY_PLUGIN_SETTINGS_DIR (QV2RAY_CONFIG_DIR + "plugin_settings/")
|
||||
|
||||
// Get GFWList and PAC file path.
|
||||
#define QV2RAY_RULES_DIR (QV2RAY_CONFIG_DIR + "rules/")
|
||||
#define QV2RAY_RULES_GFWLIST_PATH (QV2RAY_RULES_DIR + "gfwList.txt")
|
||||
#define QV2RAY_RULES_PAC_PATH (QV2RAY_RULES_DIR + "pac.txt")
|
||||
|
||||
//
|
||||
#define QV2RAY_CONFIG_FILE_EXTENSION ".qv2ray.json"
|
||||
#define QV2RAY_GENERATED_DIR (QV2RAY_CONFIG_DIR + "generated/")
|
||||
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
|
||||
@ -85,9 +90,11 @@ using namespace Qv2ray::base::objects::transfer;
|
||||
|
||||
// GUI TOOLS
|
||||
#define RED(obj) \
|
||||
auto _temp = obj->palette(); \
|
||||
_temp.setColor(QPalette::Text, Qt::red); \
|
||||
obj->setPalette(_temp);
|
||||
{ \
|
||||
auto _temp = obj->palette(); \
|
||||
_temp.setColor(QPalette::Text, Qt::red); \
|
||||
obj->setPalette(_temp); \
|
||||
}
|
||||
|
||||
#define BLACK(obj) obj->setPalette(QWidget::palette());
|
||||
|
||||
@ -97,11 +104,11 @@ using namespace Qv2ray::base::objects::transfer;
|
||||
#define ACCESS_OPTIONAL_VALUE(obj) (obj.value())
|
||||
#endif
|
||||
|
||||
#define Q_TRAYICON(name) (QIcon(GlobalConfig.uiConfig.useDarkTrayIcon ? ":/assets/icons/ui_dark/" name : ":/assets/icons/ui_light/" name))
|
||||
#define QV2RAY_COLORSCHEME_ROOT_X(flag) ((flag) ? QStringLiteral(":/assets/icons/ui_dark/") : QStringLiteral(":/assets/icons/ui_light/"))
|
||||
#define QV2RAY_COLORSCHEME_ROOT QV2RAY_COLORSCHEME_ROOT_X(GlobalConfig.uiConfig.useDarkTheme)
|
||||
|
||||
#define QV2RAY_COLORSCHEME_ROOT \
|
||||
((GlobalConfig.uiConfig.useDarkTheme) ? QStringLiteral(":/assets/icons/ui_dark/") : QStringLiteral(":/assets/icons/ui_light/"))
|
||||
#define QICON_R(file) QIcon(QV2RAY_COLORSCHEME_ROOT + file)
|
||||
#define Q_TRAYICON(name) (QIcon(QV2RAY_COLORSCHEME_ROOT_X(GlobalConfig.uiConfig.useDarkTrayIcon) + name))
|
||||
|
||||
#define QSTRN(num) QString::number(num)
|
||||
|
||||
@ -115,48 +122,40 @@ using namespace Qv2ray::base::objects::transfer;
|
||||
|
||||
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
|
||||
|
||||
#define JSON_ROOT_TRY_REMOVE(obj) \
|
||||
if (root.contains(obj)) \
|
||||
{ \
|
||||
root.remove(obj); \
|
||||
}
|
||||
|
||||
namespace Qv2ray
|
||||
{
|
||||
// Extra header for QvConfigUpgrade.cpp
|
||||
QJsonObject UpgradeSettingsVersion(int fromVersion, int toVersion, QJsonObject root);
|
||||
|
||||
// Qv2ray runtime config
|
||||
inline bool isExiting = false;
|
||||
inline QString Qv2rayConfigPath = "";
|
||||
inline base::config::Qv2rayConfig GlobalConfig = base::config::Qv2rayConfig();
|
||||
//
|
||||
inline void ExitQv2ray()
|
||||
{
|
||||
isExiting = true;
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
inline QStringList Qv2rayAssetsPaths(const QString &dirName)
|
||||
{
|
||||
// Configuration Path
|
||||
QStringList list;
|
||||
list << QV2RAY_CONFIG_DIR + dirName;
|
||||
list << ":/" + dirName;
|
||||
//
|
||||
#ifdef Q_OS_LINUX
|
||||
// Linux platform directories.
|
||||
list << QString("/lib/qv2ray/" + dirName);
|
||||
list << QString("/usr/lib/qv2ray/" + dirName);
|
||||
list << QString("/usr/local/lib/qv2ray/" + dirName);
|
||||
//
|
||||
list << QString("/usr/share/qv2ray/" + dirName);
|
||||
list << QString("/usr/local/share/qv2ray/" + dirName);
|
||||
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, QStandardPaths::LocateDirectory);
|
||||
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, QStandardPaths::LocateDirectory);
|
||||
// For AppImage?
|
||||
list << QString(QDir(QCoreApplication::applicationDirPath() + "/../share/qv2ray/" + dirName).absolutePath());
|
||||
// For Snap
|
||||
if (qEnvironmentVariableIsSet("SNAP"))
|
||||
{
|
||||
list << QString(qEnvironmentVariable("SNAP") + "/usr/share/qv2ray/" + dirName);
|
||||
}
|
||||
#elif defined(Q_OS_MAC)
|
||||
// macOS platform directories.
|
||||
list << QDir(QApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath();
|
||||
list << QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath();
|
||||
#endif
|
||||
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, QStandardPaths::LocateDirectory);
|
||||
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, QStandardPaths::LocateDirectory);
|
||||
// This is the default behavior on Windows
|
||||
list << QApplication::applicationDirPath() + "/" + dirName;
|
||||
list << QCoreApplication::applicationDirPath() + "/" + dirName;
|
||||
list.removeDuplicates();
|
||||
return list;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Qv2ray
|
||||
|
@ -1,9 +1,22 @@
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
// Qv2ray build features.
|
||||
//
|
||||
// Always use libgRPC++ on windows platform.
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#define CanHasLibQvb 1
|
||||
#define NativeDarkmode 0
|
||||
#elif defined(Q_OS_MAC)
|
||||
#define CanHasLibQvb 1
|
||||
#define NativeDarkmode 0
|
||||
#elif defined(Q_OS_WIN)
|
||||
#define CanHasLibQvb 0
|
||||
#define NativeDarkmode 1
|
||||
#endif
|
||||
|
||||
#ifdef BACKEND_LIBQVB
|
||||
#ifdef _WIN32
|
||||
#error "libQvb is not supported on Windows Platform"
|
||||
#if !QvHasFeature(CanHasLibQvb)
|
||||
#error Qv2ray API backend libQvb is not supported on this platform
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define QvHasFeature(feat) ((feat / 1) == 1)
|
||||
|
@ -4,6 +4,14 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
Qv2rayConfigObject _qv2ray_global_config_impl_details::_GlobalConfig;
|
||||
bool _qv2ray_global_config_impl_details::_isExiting;
|
||||
QString _qv2ray_global_config_impl_details::_Qv2rayConfigPath;
|
||||
|
||||
namespace Qv2ray::base
|
||||
{
|
||||
// Forwarded from QvTinyLog
|
||||
@ -15,7 +23,7 @@ namespace Qv2ray::base
|
||||
void __QV2RAY_LOG_FUNC__(int type, const std::string &func, int line, const QString &module, const QString &log)
|
||||
{
|
||||
auto logString = QString("[" % module % "]: " % log);
|
||||
auto funcPrepend = QString::fromStdString(func + ":" + to_string(line) + " ");
|
||||
auto funcPrepend = QString::fromStdString(func + ":" + std::to_string(line) + " ");
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
// Debug build version, we only print info for DEBUG logs and print
|
||||
@ -40,7 +48,11 @@ namespace Qv2ray::base
|
||||
}
|
||||
}
|
||||
#endif
|
||||
cout << logString.toStdString() << endl;
|
||||
#ifdef Q_OS_ANDROID
|
||||
__android_log_write(ANDROID_LOG_INFO, "Qv2ray", logString.toStdString().c_str());
|
||||
#else
|
||||
std::cout << logString.toStdString() << std::endl;
|
||||
#endif
|
||||
{
|
||||
QMutexLocker _(&__loggerMutex);
|
||||
__loggerBuffer->append(logString + NEWLINE);
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Tiny log module.
|
||||
@ -18,7 +17,7 @@ namespace Qv2ray::base
|
||||
#define QV2RAY_LOG_NORMAL 0
|
||||
#define QV2RAY_LOG_DEBUG 1
|
||||
|
||||
#define __LOG_IMPL(LEVEL, MODULE, MSG) __QV2RAY_LOG_FUNC__(LEVEL, Q_FUNC_INFO, __LINE__, MODULE, MSG);
|
||||
#define __LOG_IMPL(LEVEL, MODULE, MSG) ::Qv2ray::base::__QV2RAY_LOG_FUNC__(LEVEL, Q_FUNC_INFO, __LINE__, MODULE, MSG);
|
||||
|
||||
#define LOG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_NORMAL, (MODULE), (MSG));
|
||||
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "3rdparty/x2struct/x2struct.hpp"
|
||||
#include "libs/QJsonStruct/QJsonIO.hpp"
|
||||
#include "libs/QJsonStruct/QJsonStruct.hpp"
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
@ -7,13 +8,49 @@
|
||||
|
||||
namespace Qv2ray::base::objects
|
||||
{
|
||||
struct DNSObject
|
||||
{
|
||||
struct DNSServerObject
|
||||
{
|
||||
bool QV2RAY_DNS_IS_COMPLEX_DNS;
|
||||
QString address;
|
||||
int port;
|
||||
QList<QString> domains;
|
||||
QList<QString> expectIPs;
|
||||
DNSServerObject() : QV2RAY_DNS_IS_COMPLEX_DNS(false), port(53){};
|
||||
DNSServerObject(const QString &_address) : DNSServerObject()
|
||||
{
|
||||
address = _address;
|
||||
};
|
||||
|
||||
friend bool operator==(const DNSServerObject &left, const DNSServerObject &right)
|
||||
{
|
||||
return left.QV2RAY_DNS_IS_COMPLEX_DNS == right.QV2RAY_DNS_IS_COMPLEX_DNS && //
|
||||
left.address == right.address && //
|
||||
left.port == right.port && //
|
||||
left.domains == right.domains && //
|
||||
left.expectIPs == right.expectIPs;
|
||||
}
|
||||
JSONSTRUCT_REGISTER(DNSServerObject, F(QV2RAY_DNS_IS_COMPLEX_DNS, address, port, domains, expectIPs))
|
||||
};
|
||||
QMap<QString, QString> hosts;
|
||||
QList<DNSServerObject> servers;
|
||||
QString clientIp;
|
||||
QString tag;
|
||||
friend bool operator==(const DNSObject &left, const DNSObject &right)
|
||||
{
|
||||
return left.hosts == right.hosts && left.servers == right.servers && left.clientIp == right.clientIp && left.tag == right.tag;
|
||||
}
|
||||
JSONSTRUCT_REGISTER(DNSObject, F(hosts, servers, clientIp, tag))
|
||||
};
|
||||
//
|
||||
// Used in config generation
|
||||
struct AccountObject
|
||||
{
|
||||
QString user;
|
||||
QString pass;
|
||||
XTOSTRUCT(O(user, pass))
|
||||
AccountObject() : user(), pass(){};
|
||||
JSONSTRUCT_REGISTER(AccountObject, F(user, pass))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -21,10 +58,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
QString tag;
|
||||
QList<QString> services;
|
||||
ApiObject() : tag("api"), services()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(tag, services))
|
||||
ApiObject() : tag("api"), services(){};
|
||||
JSONSTRUCT_REGISTER(ApiObject, F(tag, services))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -32,10 +67,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
bool statsInboundUplink;
|
||||
bool statsInboundDownlink;
|
||||
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(statsInboundUplink, statsInboundDownlink))
|
||||
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink(){};
|
||||
JSONSTRUCT_REGISTER(SystemPolicyObject, F(statsInboundUplink, statsInboundDownlink))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -48,10 +81,8 @@ namespace Qv2ray::base::objects
|
||||
bool statsUserUplink;
|
||||
bool statsUserDownlink;
|
||||
int bufferSize;
|
||||
LevelPolicyObject() : handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize))
|
||||
LevelPolicyObject() : handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize(){};
|
||||
JSONSTRUCT_REGISTER(LevelPolicyObject, F(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -59,10 +90,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
QMap<QString, LevelPolicyObject> level;
|
||||
QList<SystemPolicyObject> system;
|
||||
PolicyObject() : level(), system()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(level, system))
|
||||
PolicyObject() : level(), system(){};
|
||||
JSONSTRUCT_REGISTER(PolicyObject, F(level, system))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -87,11 +116,9 @@ namespace Qv2ray::base::objects
|
||||
QString balancerTag;
|
||||
RuleObject()
|
||||
: QV2RAY_RULE_ENABLED(true), QV2RAY_RULE_USE_BALANCER(false), QV2RAY_RULE_TAG("new rule"), type("field"), domain(), ip(),
|
||||
port("1-65535"), network(""), source(), user(), inboundTag(), protocol(), attrs(), outboundTag(""), balancerTag("")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(QV2RAY_RULE_ENABLED, QV2RAY_RULE_USE_BALANCER, QV2RAY_RULE_TAG, type, domain, ip, port, network, source, user, inboundTag,
|
||||
protocol, attrs, outboundTag, balancerTag))
|
||||
port("1-65535"), network(""), source(), user(), inboundTag(), protocol(), attrs(), outboundTag(""), balancerTag(""){};
|
||||
JSONSTRUCT_REGISTER(RuleObject, F(QV2RAY_RULE_ENABLED, QV2RAY_RULE_USE_BALANCER, QV2RAY_RULE_TAG, type, domain, ip, port, network,
|
||||
source, user, inboundTag, protocol, attrs, outboundTag, balancerTag))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -99,10 +126,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
QString tag;
|
||||
QList<QString> selector;
|
||||
BalancerObject() : tag(), selector()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(tag, selector))
|
||||
BalancerObject() : tag(), selector(){};
|
||||
JSONSTRUCT_REGISTER(BalancerObject, F(tag, selector))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -114,10 +139,8 @@ namespace Qv2ray::base::objects
|
||||
QString method;
|
||||
QList<QString> path;
|
||||
QMap<QString, QList<QString>> headers;
|
||||
HTTPRequestObject() : version("1.1"), method("GET"), path(), headers()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(version, method, path, headers))
|
||||
HTTPRequestObject() : version("1.1"), method("GET"), path(), headers(){};
|
||||
JSONSTRUCT_REGISTER(HTTPRequestObject, F(version, method, path, headers))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -127,10 +150,8 @@ namespace Qv2ray::base::objects
|
||||
QString status;
|
||||
QString reason;
|
||||
QMap<QString, QList<QString>> headers;
|
||||
HTTPResponseObject() : version("1.1"), status("200"), reason("OK"), headers()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(version, status, reason, headers))
|
||||
HTTPResponseObject() : version("1.1"), status("200"), reason("OK"), headers(){};
|
||||
JSONSTRUCT_REGISTER(HTTPResponseObject, F(version, status, reason, headers))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -139,30 +160,24 @@ namespace Qv2ray::base::objects
|
||||
QString type;
|
||||
HTTPRequestObject request;
|
||||
HTTPResponseObject response;
|
||||
TCPHeader_M_Object() : type("none"), request(), response()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(type, request, response))
|
||||
TCPHeader_M_Object() : type("none"), request(), response(){};
|
||||
JSONSTRUCT_REGISTER(TCPHeader_M_Object, F(type, request, response))
|
||||
};
|
||||
//
|
||||
//
|
||||
struct HeaderObject
|
||||
{
|
||||
QString type;
|
||||
HeaderObject() : type("none")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(type))
|
||||
HeaderObject() : type("none"){};
|
||||
JSONSTRUCT_REGISTER(HeaderObject, F(type))
|
||||
};
|
||||
//
|
||||
//
|
||||
struct TCPObject
|
||||
{
|
||||
TCPHeader_M_Object header;
|
||||
TCPObject() : header()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(header))
|
||||
TCPObject() : header(){};
|
||||
JSONSTRUCT_REGISTER(TCPObject, F(header))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -175,11 +190,11 @@ namespace Qv2ray::base::objects
|
||||
bool congestion = false;
|
||||
int readBufferSize = 1;
|
||||
int writeBufferSize = 1;
|
||||
QString seed;
|
||||
HeaderObject header;
|
||||
KCPObject() : header()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header))
|
||||
KCPObject() : header(){};
|
||||
JSONSTRUCT_REGISTER(KCPObject,
|
||||
F(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header, seed))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -187,10 +202,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
QString path;
|
||||
QMap<QString, QString> headers;
|
||||
WebSocketObject() : path("/"), headers()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(path, headers))
|
||||
WebSocketObject() : path("/"), headers(){};
|
||||
JSONSTRUCT_REGISTER(WebSocketObject, F(path, headers))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -198,20 +211,16 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
QList<QString> host;
|
||||
QString path;
|
||||
HttpObject() : host(), path("/")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(host, path))
|
||||
HttpObject() : host(), path("/"){};
|
||||
JSONSTRUCT_REGISTER(HttpObject, F(host, path))
|
||||
};
|
||||
//
|
||||
//
|
||||
struct DomainSocketObject
|
||||
{
|
||||
QString path;
|
||||
DomainSocketObject() : path("/")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(path))
|
||||
DomainSocketObject() : path("/"){};
|
||||
JSONSTRUCT_REGISTER(DomainSocketObject, F(path))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -220,10 +229,8 @@ namespace Qv2ray::base::objects
|
||||
QString security;
|
||||
QString key;
|
||||
HeaderObject header;
|
||||
QuicObject() : security(""), key(""), header()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(security, key, header))
|
||||
QuicObject() : security(""), key(""), header(){};
|
||||
JSONSTRUCT_REGISTER(QuicObject, F(security, key, header))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -232,10 +239,8 @@ namespace Qv2ray::base::objects
|
||||
int mark;
|
||||
bool tcpFastOpen;
|
||||
QString tproxy;
|
||||
SockoptObject() : mark(0), tcpFastOpen(false), tproxy("off")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(mark, tcpFastOpen, tproxy))
|
||||
SockoptObject() : mark(0), tcpFastOpen(false), tproxy("off"){};
|
||||
JSONSTRUCT_REGISTER(SockoptObject, F(mark, tcpFastOpen, tproxy))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -246,10 +251,8 @@ namespace Qv2ray::base::objects
|
||||
QString keyFile;
|
||||
QList<QString> certificate;
|
||||
QList<QString> key;
|
||||
CertificateObject() : usage(), certificateFile(), keyFile(), certificate(), key()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(usage, certificateFile, keyFile, certificate, key))
|
||||
CertificateObject() : usage(), certificateFile(), keyFile(), certificate(), key(){};
|
||||
JSONSTRUCT_REGISTER(CertificateObject, F(usage, certificateFile, keyFile, certificate, key))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -258,13 +261,14 @@ namespace Qv2ray::base::objects
|
||||
QString serverName;
|
||||
bool allowInsecure;
|
||||
bool allowInsecureCiphers;
|
||||
bool disableSessionResumption;
|
||||
QList<QString> alpn;
|
||||
QList<CertificateObject> certificates;
|
||||
bool disableSystemRoot;
|
||||
TLSObject() : serverName(), allowInsecure(), allowInsecureCiphers(), certificates(), disableSystemRoot()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(serverName, allowInsecure, allowInsecureCiphers, alpn, certificates, disableSystemRoot))
|
||||
TLSObject()
|
||||
: serverName(), allowInsecure(), allowInsecureCiphers(), disableSessionResumption(true), certificates(), disableSystemRoot(){};
|
||||
JSONSTRUCT_REGISTER(TLSObject, F(serverName, allowInsecure, allowInsecureCiphers, disableSessionResumption, alpn, certificates,
|
||||
disableSystemRoot))
|
||||
};
|
||||
} // namespace transfer
|
||||
//
|
||||
@ -273,10 +277,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
bool enabled = false;
|
||||
QList<QString> destOverride;
|
||||
SniffingObject() : enabled(), destOverride()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(enabled, destOverride))
|
||||
SniffingObject() : enabled(), destOverride(){};
|
||||
JSONSTRUCT_REGISTER(SniffingObject, F(enabled, destOverride))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -294,10 +296,9 @@ namespace Qv2ray::base::objects
|
||||
transfer::QuicObject 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))
|
||||
dsSettings(), quicSettings(){};
|
||||
JSONSTRUCT_REGISTER(StreamSettingsObject, F(network, security, sockopt, tcpSettings, tlsSettings, kcpSettings, wsSettings, httpSettings,
|
||||
dsSettings, quicSettings))
|
||||
};
|
||||
//
|
||||
//
|
||||
@ -305,10 +306,8 @@ namespace Qv2ray::base::objects
|
||||
{
|
||||
bool enabled;
|
||||
int concurrency;
|
||||
MuxObject() : enabled(), concurrency()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(enabled, concurrency))
|
||||
MuxObject() : enabled(), concurrency(){};
|
||||
JSONSTRUCT_REGISTER(MuxObject, F(enabled, concurrency))
|
||||
};
|
||||
//
|
||||
// Some protocols from: https://v2ray.com/chapter_02/02_protocols.html
|
||||
@ -320,10 +319,8 @@ namespace Qv2ray::base::objects
|
||||
QString network;
|
||||
QString address;
|
||||
int port;
|
||||
DNSOut() : network(""), address("0.0.0.0"), port(0)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(network, address, port))
|
||||
DNSOut() : network(""), address("0.0.0.0"), port(0){};
|
||||
JSONSTRUCT_REGISTER(DNSOut, F(network, address, port))
|
||||
};
|
||||
//
|
||||
// MTProto, InBound || OutBound
|
||||
@ -334,13 +331,11 @@ namespace Qv2ray::base::objects
|
||||
QString email;
|
||||
int level;
|
||||
QString secret;
|
||||
UserObject() : email("user@domain.com"), level(0), secret("")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(email, level, secret))
|
||||
UserObject() : email("user@domain.com"), level(0), secret(""){};
|
||||
JSONSTRUCT_REGISTER(UserObject, F(email, level, secret))
|
||||
};
|
||||
QList<UserObject> users;
|
||||
XTOSTRUCT(O(users))
|
||||
JSONSTRUCT_REGISTER(MTProtoIn, F(users))
|
||||
};
|
||||
//
|
||||
// Socks, OutBound
|
||||
@ -351,19 +346,14 @@ namespace Qv2ray::base::objects
|
||||
QString user;
|
||||
QString pass;
|
||||
int level;
|
||||
UserObject() : user(), pass(), level(0)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(user, pass, level))
|
||||
UserObject() : user(), pass(), level(0){};
|
||||
JSONSTRUCT_REGISTER(UserObject, F(user, pass, level))
|
||||
};
|
||||
|
||||
QString address;
|
||||
int port;
|
||||
QList<UserObject> users;
|
||||
SocksServerObject() : address("0.0.0.0"), port(0), users()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(address, port, users))
|
||||
SocksServerObject() : address("0.0.0.0"), port(0), users(){};
|
||||
JSONSTRUCT_REGISTER(SocksServerObject, F(address, port, users))
|
||||
};
|
||||
//
|
||||
// VMess Server
|
||||
@ -375,19 +365,16 @@ namespace Qv2ray::base::objects
|
||||
int alterId;
|
||||
QString security;
|
||||
int level;
|
||||
UserObject() : id(""), alterId(64), security("auto"), level(0)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(id, alterId, security, level))
|
||||
QString testsEnabled;
|
||||
UserObject() : id(), alterId(64), security("auto"), level(0), testsEnabled("none"){};
|
||||
JSONSTRUCT_REGISTER(UserObject, F(id, alterId, security, level, testsEnabled))
|
||||
};
|
||||
|
||||
QString address;
|
||||
int port;
|
||||
QList<UserObject> users;
|
||||
VMessServerObject() : address(""), port(0), users()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(address, port, users))
|
||||
VMessServerObject() : address(""), port(0), users(){};
|
||||
JSONSTRUCT_REGISTER(VMessServerObject, F(address, port, users))
|
||||
};
|
||||
//
|
||||
// ShadowSocks Server
|
||||
@ -401,10 +388,8 @@ namespace Qv2ray::base::objects
|
||||
int level;
|
||||
int port;
|
||||
ShadowSocksServerObject()
|
||||
: email("user@domain.com"), address("0.0.0.0"), method("aes-256-cfb"), password(""), ota(false), level(0), port(0)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(email, address, port, method, password, ota, level))
|
||||
: email("user@domain.com"), address("0.0.0.0"), method("aes-256-cfb"), password(""), ota(false), level(0), port(0){};
|
||||
JSONSTRUCT_REGISTER(ShadowSocksServerObject, F(email, address, port, method, password, ota, level))
|
||||
};
|
||||
} // namespace protocol
|
||||
} // namespace Qv2ray::base::objects
|
||||
|
@ -1,52 +1,180 @@
|
||||
#pragma once
|
||||
#include "3rdparty/x2struct/x2struct.hpp"
|
||||
#include "QvCoreSettings.hpp"
|
||||
#include "libs/QJsonStruct/QJsonStruct.hpp"
|
||||
|
||||
#include <QHash>
|
||||
#include <QHashFunctions>
|
||||
#include <QString>
|
||||
#include <QtCore>
|
||||
|
||||
namespace Qv2ray::base
|
||||
{
|
||||
constexpr unsigned int QVTCPING_VALUE_ERROR = 99999;
|
||||
constexpr unsigned int QVTCPING_VALUE_NODATA = QVTCPING_VALUE_ERROR - 1;
|
||||
template<typename T>
|
||||
class IDType
|
||||
{
|
||||
public:
|
||||
explicit IDType() : m_id("null"){};
|
||||
explicit IDType(const QString &id) : m_id(id){};
|
||||
friend bool operator==(const IDType<T> &lhs, const IDType<T> &rhs)
|
||||
{
|
||||
return lhs.m_id == rhs.m_id;
|
||||
}
|
||||
friend bool operator!=(const IDType<T> &lhs, const IDType<T> &rhs)
|
||||
{
|
||||
return lhs.m_id != rhs.m_id;
|
||||
}
|
||||
const QString toString() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
void loadJson(const QJsonValue &d)
|
||||
{
|
||||
m_id = d.toString("null");
|
||||
}
|
||||
QJsonValue toJson() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_id;
|
||||
};
|
||||
|
||||
// Define several safetypes to prevent misuse of QString.
|
||||
class __QvGroup;
|
||||
class __QvConnection;
|
||||
class __QvRoute;
|
||||
typedef IDType<__QvGroup> GroupId;
|
||||
typedef IDType<__QvConnection> ConnectionId;
|
||||
typedef IDType<__QvRoute> GroupRoutingId;
|
||||
//
|
||||
inline const static auto NullConnectionId = ConnectionId("null");
|
||||
inline const static auto NullGroupId = GroupId("null");
|
||||
inline const static auto NullRoutingId = GroupRoutingId("null");
|
||||
//
|
||||
class ConnectionGroupPair
|
||||
{
|
||||
public:
|
||||
ConnectionId connectionId = NullConnectionId;
|
||||
GroupId groupId = NullGroupId;
|
||||
ConnectionGroupPair() : connectionId(NullConnectionId), groupId(NullGroupId){};
|
||||
ConnectionGroupPair(const ConnectionId &conn, const GroupId &group) : connectionId(conn), groupId(group){};
|
||||
void clear()
|
||||
{
|
||||
connectionId = NullConnectionId;
|
||||
groupId = NullGroupId;
|
||||
}
|
||||
bool isEmpty() const
|
||||
{
|
||||
return groupId == NullGroupId || connectionId == NullConnectionId;
|
||||
}
|
||||
friend bool operator==(const ConnectionGroupPair &lhs, const ConnectionGroupPair &rhs)
|
||||
{
|
||||
return lhs.groupId == rhs.groupId && lhs.connectionId == rhs.connectionId;
|
||||
}
|
||||
JSONSTRUCT_REGISTER(ConnectionGroupPair, F(connectionId, groupId))
|
||||
};
|
||||
//
|
||||
constexpr unsigned int LATENCY_TEST_VALUE_ERROR = 99999;
|
||||
constexpr unsigned int LATENCY_TEST_VALUE_NODATA = LATENCY_TEST_VALUE_ERROR - 1;
|
||||
using namespace std::chrono;
|
||||
// Common struct for Groups and Subscriptions
|
||||
struct GroupObject_Config
|
||||
|
||||
struct __Qv2rayConfigObjectBase
|
||||
{
|
||||
QString displayName;
|
||||
QList<QString> connections;
|
||||
int64_t importDate;
|
||||
GroupObject_Config() : displayName(), connections(), importDate()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(displayName, connections, importDate))
|
||||
qint64 creationDate;
|
||||
qint64 lastUpdatedDate;
|
||||
__Qv2rayConfigObjectBase()
|
||||
: displayName(), creationDate(system_clock::to_time_t(system_clock::now())), //
|
||||
lastUpdatedDate(system_clock::to_time_t(system_clock::now())){}; //
|
||||
JSONSTRUCT_REGISTER(__Qv2rayConfigObjectBase, F(displayName, creationDate, lastUpdatedDate))
|
||||
};
|
||||
|
||||
struct SubscriptionObject_Config : GroupObject_Config
|
||||
struct GroupRoutingConfig : __Qv2rayConfigObjectBase
|
||||
{
|
||||
bool overrideDNS;
|
||||
config::QvConfig_DNS dnsConfig;
|
||||
//
|
||||
QString address;
|
||||
int64_t lastUpdated;
|
||||
float updateInterval;
|
||||
SubscriptionObject_Config() : address(""), lastUpdated(system_clock::to_time_t(system_clock::now())), updateInterval(10)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(lastUpdated, updateInterval, address, connections, displayName, importDate))
|
||||
bool overrideRoute;
|
||||
config::QvConfig_Route routeConfig;
|
||||
//
|
||||
bool overrideConnectionConfig;
|
||||
config::QvConfig_Connection connectionConfig;
|
||||
//
|
||||
bool overrideForwardProxyConfig;
|
||||
config::QvConfig_ForwardProxy forwardProxyConfig;
|
||||
//
|
||||
GroupRoutingConfig()
|
||||
: overrideDNS(false), //
|
||||
overrideRoute(false), //
|
||||
overrideConnectionConfig(false), //
|
||||
overrideForwardProxyConfig(false) //
|
||||
{};
|
||||
JSONSTRUCT_REGISTER(GroupRoutingConfig, //
|
||||
F(overrideRoute, routeConfig), //
|
||||
F(overrideDNS, dnsConfig), //
|
||||
F(overrideConnectionConfig, connectionConfig), //
|
||||
F(overrideForwardProxyConfig, forwardProxyConfig))
|
||||
};
|
||||
|
||||
struct ConnectionObject_Config
|
||||
enum SubscriptionFilterRelation
|
||||
{
|
||||
QString displayName;
|
||||
int64_t importDate;
|
||||
int64_t lastConnected;
|
||||
int64_t latency;
|
||||
int64_t upLinkData;
|
||||
int64_t downLinkData;
|
||||
ConnectionObject_Config()
|
||||
: displayName(), importDate(system_clock::to_time_t(system_clock::now())), lastConnected(), latency(QVTCPING_VALUE_NODATA),
|
||||
upLinkData(0), downLinkData(0)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(displayName, importDate, lastConnected, latency, upLinkData, downLinkData))
|
||||
RELATION_AND = 0,
|
||||
RELATION_OR = 1
|
||||
};
|
||||
|
||||
struct SubscriptionConfigObject
|
||||
{
|
||||
QString address;
|
||||
float updateInterval;
|
||||
SubscriptionFilterRelation IncludeRelation;
|
||||
SubscriptionFilterRelation ExcludeRelation;
|
||||
QList<QString> IncludeKeywords;
|
||||
QList<QString> ExcludeKeywords;
|
||||
SubscriptionConfigObject()
|
||||
: address(""), updateInterval(10), //
|
||||
IncludeRelation(RELATION_OR), ExcludeRelation(RELATION_AND), //
|
||||
IncludeKeywords(), ExcludeKeywords(){};
|
||||
JSONSTRUCT_REGISTER(SubscriptionConfigObject,
|
||||
F(updateInterval, address, IncludeRelation, ExcludeRelation, IncludeKeywords, ExcludeKeywords))
|
||||
};
|
||||
|
||||
struct GroupObject : __Qv2rayConfigObjectBase
|
||||
{
|
||||
QList<ConnectionId> connections;
|
||||
bool isSubscription;
|
||||
GroupRoutingId routeConfigId;
|
||||
SubscriptionConfigObject subscriptionOption;
|
||||
GroupObject() : __Qv2rayConfigObjectBase(), connections(), isSubscription(false), subscriptionOption(){};
|
||||
JSONSTRUCT_REGISTER(GroupObject, F(connections, isSubscription, routeConfigId, subscriptionOption), B(__Qv2rayConfigObjectBase))
|
||||
};
|
||||
|
||||
struct ConnectionObject : __Qv2rayConfigObjectBase
|
||||
{
|
||||
qint64 lastConnected;
|
||||
qint64 latency;
|
||||
qint64 upLinkData;
|
||||
qint64 downLinkData;
|
||||
//
|
||||
int __qvConnectionRefCount;
|
||||
//
|
||||
ConnectionObject() : lastConnected(), latency(LATENCY_TEST_VALUE_NODATA), upLinkData(0), downLinkData(0), __qvConnectionRefCount(0){};
|
||||
JSONSTRUCT_REGISTER(ConnectionObject, F(lastConnected, latency, upLinkData, downLinkData), B(__Qv2rayConfigObjectBase))
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline uint qHash(IDType<T> key)
|
||||
{
|
||||
return ::qHash(key.toString());
|
||||
}
|
||||
inline uint qHash(const Qv2ray::base::ConnectionGroupPair &pair)
|
||||
{
|
||||
return ::qHash(pair.connectionId.toString() + pair.groupId.toString());
|
||||
}
|
||||
} // namespace Qv2ray::base
|
||||
|
||||
using namespace Qv2ray::base;
|
||||
Q_DECLARE_METATYPE(ConnectionGroupPair)
|
||||
Q_DECLARE_METATYPE(ConnectionId)
|
||||
Q_DECLARE_METATYPE(GroupId)
|
||||
Q_DECLARE_METATYPE(GroupRoutingId)
|
||||
|
142
src/base/models/QvCoreSettings.hpp
Normal file
142
src/base/models/QvCoreSettings.hpp
Normal file
@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
#include "base/models/CoreObjectModels.hpp"
|
||||
#include "libs/QJsonStruct/QJsonStruct.hpp"
|
||||
namespace Qv2ray::base::config
|
||||
{
|
||||
struct QvConfig_Route
|
||||
{
|
||||
struct QvRouteConfig_Impl
|
||||
{
|
||||
QList<QString> direct;
|
||||
QList<QString> block;
|
||||
QList<QString> proxy;
|
||||
QvRouteConfig_Impl(){};
|
||||
friend bool operator==(const QvRouteConfig_Impl &left, const QvRouteConfig_Impl &right)
|
||||
{
|
||||
return left.direct == right.direct && left.block == right.block && left.proxy == right.proxy;
|
||||
}
|
||||
QvRouteConfig_Impl(const QList<QString> &_direct, const QList<QString> &_block, const QList<QString> &_proxy)
|
||||
: direct(_direct), //
|
||||
block(_block), //
|
||||
proxy(_proxy){};
|
||||
JSONSTRUCT_REGISTER(QvRouteConfig_Impl, F(proxy, block, direct))
|
||||
};
|
||||
QString domainStrategy;
|
||||
QvRouteConfig_Impl domains;
|
||||
QvRouteConfig_Impl ips;
|
||||
friend bool operator==(const QvConfig_Route &left, const QvConfig_Route &right)
|
||||
{
|
||||
return left.domainStrategy == right.domainStrategy && left.domains == right.domains && left.ips == right.ips;
|
||||
}
|
||||
QvConfig_Route(){};
|
||||
QvConfig_Route(const QvRouteConfig_Impl &_domains, const QvRouteConfig_Impl &_ips, const QString &ds)
|
||||
: domainStrategy(ds), //
|
||||
domains(_domains), //
|
||||
ips(_ips){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_Route, F(domainStrategy, domains, ips))
|
||||
};
|
||||
|
||||
using QvConfig_DNS = objects::DNSObject;
|
||||
|
||||
struct QvConfig_Outbounds
|
||||
{
|
||||
int mark;
|
||||
QvConfig_Outbounds() : mark(255){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_Outbounds, F(mark))
|
||||
};
|
||||
|
||||
struct QvConfig_ForwardProxy
|
||||
{
|
||||
bool enableForwardProxy;
|
||||
QString type;
|
||||
QString serverAddress;
|
||||
int port;
|
||||
bool useAuth;
|
||||
QString username;
|
||||
QString password;
|
||||
QvConfig_ForwardProxy()
|
||||
: enableForwardProxy(false), type("http"), serverAddress("127.0.0.1"), port(8008), useAuth(false), username(), password(){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_ForwardProxy, F(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
|
||||
};
|
||||
|
||||
struct QvConfig_Connection
|
||||
{
|
||||
bool enableProxy;
|
||||
bool bypassCN;
|
||||
bool bypassBT;
|
||||
bool v2rayFreedomDNS;
|
||||
bool withLocalDNS;
|
||||
QvConfig_Connection() : enableProxy(true), bypassCN(true), bypassBT(false), v2rayFreedomDNS(false), withLocalDNS(false){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_Connection, F(bypassCN, bypassBT, enableProxy, v2rayFreedomDNS, withLocalDNS))
|
||||
};
|
||||
|
||||
struct QvConfig_SystemProxy
|
||||
{
|
||||
bool setSystemProxy;
|
||||
QvConfig_SystemProxy() : setSystemProxy(true){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_SystemProxy, F(setSystemProxy))
|
||||
};
|
||||
|
||||
struct __Qv2rayConfig_ProtocolInboundBase
|
||||
{
|
||||
int port;
|
||||
bool useAuth;
|
||||
bool sniffing;
|
||||
objects::AccountObject account;
|
||||
__Qv2rayConfig_ProtocolInboundBase(int _port = 0) : port(_port), useAuth(false), sniffing(false), account(){};
|
||||
JSONSTRUCT_REGISTER(__Qv2rayConfig_ProtocolInboundBase, F(port, useAuth, sniffing, account))
|
||||
};
|
||||
|
||||
struct QvConfig_SocksInbound : __Qv2rayConfig_ProtocolInboundBase
|
||||
{
|
||||
bool enableUDP;
|
||||
QString localIP;
|
||||
QvConfig_SocksInbound() : __Qv2rayConfig_ProtocolInboundBase(1089), enableUDP(true), localIP("127.0.0.1"){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_SocksInbound, B(__Qv2rayConfig_ProtocolInboundBase), F(enableUDP, localIP))
|
||||
};
|
||||
|
||||
struct QvConfig_HttpInbound : __Qv2rayConfig_ProtocolInboundBase
|
||||
{
|
||||
QvConfig_HttpInbound() : __Qv2rayConfig_ProtocolInboundBase(8889){};
|
||||
JSONSTRUCT_REGISTER(QvConfig_HttpInbound, B(__Qv2rayConfig_ProtocolInboundBase))
|
||||
};
|
||||
|
||||
struct QvConfig_TProxy
|
||||
{
|
||||
QString tProxyIP;
|
||||
QString tProxyV6IP;
|
||||
int port;
|
||||
bool hasTCP;
|
||||
bool hasUDP;
|
||||
QString mode;
|
||||
bool dnsIntercept;
|
||||
QvConfig_TProxy()
|
||||
: tProxyIP("127.0.0.1"), //
|
||||
tProxyV6IP(""), //
|
||||
port(12345), //
|
||||
hasTCP(true), //
|
||||
hasUDP(false), //
|
||||
mode("tproxy"), //
|
||||
dnsIntercept(true) //
|
||||
{};
|
||||
JSONSTRUCT_REGISTER(QvConfig_TProxy, F(tProxyIP, tProxyV6IP, port, hasTCP, hasUDP, mode, dnsIntercept))
|
||||
};
|
||||
|
||||
struct QvConfig_Inbounds
|
||||
{
|
||||
QString listenip;
|
||||
bool useSocks;
|
||||
bool useHTTP;
|
||||
bool useTPROXY;
|
||||
//
|
||||
QvConfig_TProxy tProxySettings;
|
||||
QvConfig_HttpInbound httpSettings;
|
||||
QvConfig_SocksInbound socksSettings;
|
||||
QvConfig_SystemProxy systemProxySettings;
|
||||
QvConfig_Inbounds() : listenip("127.0.0.1"), useSocks(true), useHTTP(true), useTPROXY(false){};
|
||||
|
||||
JSONSTRUCT_REGISTER(QvConfig_Inbounds, //
|
||||
F(listenip, useSocks, useHTTP, useTPROXY), //
|
||||
F(tProxySettings, httpSettings, socksSettings, systemProxySettings))
|
||||
};
|
||||
} // namespace Qv2ray::base::config
|
@ -8,6 +8,7 @@ namespace Qv2ray::base
|
||||
struct Qv2rayRuntimeConfig
|
||||
{
|
||||
bool screenShotHideQv2ray = false;
|
||||
bool deepinHorribleProxyHint = false;
|
||||
};
|
||||
inline base::Qv2rayRuntimeConfig RuntimeConfig = base::Qv2rayRuntimeConfig();
|
||||
} // namespace Qv2ray::base
|
||||
|
@ -21,7 +21,6 @@
|
||||
#define nothing
|
||||
#define SAFE_TYPEDEF(Base, name) SAFE_TYPEDEF_EXTRA(Base, name, nothing)
|
||||
|
||||
using namespace std;
|
||||
namespace Qv2ray::base::safetype
|
||||
{
|
||||
// To prevent anonying QJsonObject misuse
|
||||
|
@ -1,210 +1,54 @@
|
||||
#pragma once
|
||||
#include "3rdparty/x2struct/x2struct.hpp"
|
||||
#include "base/models/CoreObjectModels.hpp"
|
||||
#include "base/models/QvConfigIdentifier.hpp"
|
||||
#include "base/models/QvCoreSettings.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
const int QV2RAY_CONFIG_VERSION = 11;
|
||||
constexpr int QV2RAY_CONFIG_VERSION = 14;
|
||||
|
||||
namespace Qv2ray::base::config
|
||||
{
|
||||
struct QvBarLine
|
||||
{
|
||||
QString Family;
|
||||
bool Bold, Italic;
|
||||
int ColorA, ColorR, ColorG, ColorB;
|
||||
int ContentType;
|
||||
double Size;
|
||||
QString Message;
|
||||
QvBarLine()
|
||||
: Family("Consolas"), Bold(true), Italic(false), ColorA(255), ColorR(255), ColorG(255), ColorB(255), ContentType(0), Size(9),
|
||||
Message("")
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
|
||||
};
|
||||
|
||||
struct QvBarPage
|
||||
{
|
||||
int OffsetYpx;
|
||||
QList<QvBarLine> Lines;
|
||||
QvBarPage() : OffsetYpx(5)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(OffsetYpx, Lines))
|
||||
};
|
||||
|
||||
struct Qv2rayToolBarConfig
|
||||
{
|
||||
QList<QvBarPage> Pages;
|
||||
XTOSTRUCT(O(Pages))
|
||||
};
|
||||
|
||||
struct Qv2rayForwardProxyConfig
|
||||
{
|
||||
bool enableForwardProxy;
|
||||
QString type;
|
||||
QString serverAddress;
|
||||
int port;
|
||||
bool useAuth;
|
||||
QString username;
|
||||
QString password;
|
||||
Qv2rayForwardProxyConfig()
|
||||
: enableForwardProxy(false), type("http"), serverAddress("127.0.0.1"), port(8008), useAuth(false), username(), password()
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
|
||||
};
|
||||
|
||||
struct Qv2rayInboundsConfig
|
||||
{
|
||||
QString listenip;
|
||||
bool setSystemProxy;
|
||||
|
||||
// SOCKS
|
||||
bool useSocks;
|
||||
int socks_port;
|
||||
bool socks_useAuth;
|
||||
bool socksUDP;
|
||||
QString socksLocalIP;
|
||||
objects::AccountObject socksAccount;
|
||||
// HTTP
|
||||
bool useHTTP;
|
||||
int http_port;
|
||||
bool http_useAuth;
|
||||
objects::AccountObject httpAccount;
|
||||
|
||||
// dokodemo-door transparent proxy
|
||||
bool useTPROXY;
|
||||
QString tproxy_ip;
|
||||
int tproxy_port;
|
||||
bool tproxy_use_tcp;
|
||||
bool tproxy_use_udp;
|
||||
bool tproxy_followRedirect;
|
||||
/*redirect or tproxy way, and tproxy need cap_net_admin*/
|
||||
QString tproxy_mode;
|
||||
bool dnsIntercept;
|
||||
|
||||
Qv2rayInboundsConfig()
|
||||
: listenip("127.0.0.1"), setSystemProxy(true), useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true),
|
||||
socksLocalIP("127.0.0.1"), socksAccount(), useHTTP(true), http_port(8888), http_useAuth(false), httpAccount(), useTPROXY(false),
|
||||
tproxy_ip("127.0.0.1"), tproxy_port(12345), tproxy_use_tcp(true), tproxy_use_udp(false), tproxy_followRedirect(true),
|
||||
tproxy_mode("tproxy"), dnsIntercept(true)
|
||||
{
|
||||
}
|
||||
|
||||
XTOSTRUCT(O(setSystemProxy, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP, http_port,
|
||||
http_useAuth, httpAccount, useTPROXY, tproxy_ip, tproxy_port, tproxy_use_tcp, tproxy_use_udp, tproxy_followRedirect,
|
||||
tproxy_mode, dnsIntercept))
|
||||
};
|
||||
|
||||
struct Qv2rayOutboundsConfig
|
||||
{
|
||||
int mark;
|
||||
Qv2rayOutboundsConfig() : mark(255)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(mark))
|
||||
};
|
||||
|
||||
struct Qv2rayUIConfig
|
||||
struct Qv2rayConfig_UI
|
||||
{
|
||||
QString theme;
|
||||
QString language;
|
||||
QList<QString> recentConnections;
|
||||
QList<ConnectionGroupPair> recentConnections;
|
||||
bool quietMode;
|
||||
bool useDarkTheme;
|
||||
bool useDarkTrayIcon;
|
||||
int maximumLogLines;
|
||||
int maxJumpListCount;
|
||||
Qv2rayUIConfig()
|
||||
: theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500), maxJumpListCount(20)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(theme, language, quietMode, useDarkTheme, useDarkTrayIcon, maximumLogLines, maxJumpListCount, recentConnections))
|
||||
Qv2rayConfig_UI()
|
||||
: theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500), maxJumpListCount(20){};
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfig_UI,
|
||||
F(theme, language, quietMode, useDarkTheme, useDarkTrayIcon, maximumLogLines, maxJumpListCount, recentConnections))
|
||||
};
|
||||
|
||||
struct Qv2rayRouteConfig_Impl
|
||||
{
|
||||
QList<QString> direct;
|
||||
QList<QString> block;
|
||||
QList<QString> proxy;
|
||||
Qv2rayRouteConfig_Impl(){};
|
||||
friend bool operator==(const Qv2rayRouteConfig_Impl &left, const Qv2rayRouteConfig_Impl &right)
|
||||
{
|
||||
return left.direct == right.direct && left.block == right.block && left.proxy == left.proxy;
|
||||
}
|
||||
Qv2rayRouteConfig_Impl(const QList<QString> &_direct, const QList<QString> &_block, const QList<QString> &_proxy)
|
||||
: direct(_direct), block(_block), proxy(_proxy){};
|
||||
XTOSTRUCT(O(proxy, block, direct))
|
||||
};
|
||||
|
||||
struct Qv2rayRouteConfig
|
||||
{
|
||||
QString domainStrategy;
|
||||
Qv2rayRouteConfig_Impl domains;
|
||||
Qv2rayRouteConfig_Impl ips;
|
||||
friend bool operator==(const Qv2rayRouteConfig &left, const Qv2rayRouteConfig &right)
|
||||
{
|
||||
return left.domainStrategy == right.domainStrategy && left.domains == right.domains && left.ips == right.ips;
|
||||
}
|
||||
Qv2rayRouteConfig(){};
|
||||
Qv2rayRouteConfig(const Qv2rayRouteConfig_Impl &_domains, const Qv2rayRouteConfig_Impl &_ips, const QString &ds)
|
||||
: domainStrategy(ds), domains(_domains), ips(_ips){};
|
||||
XTOSTRUCT(O(domainStrategy, domains, ips))
|
||||
};
|
||||
|
||||
struct Qv2rayPluginConfig
|
||||
struct Qv2rayConfig_Plugin
|
||||
{
|
||||
QMap<QString, bool> pluginStates;
|
||||
bool v2rayIntegration;
|
||||
int portAllocationStart;
|
||||
Qv2rayPluginConfig() : pluginStates(), v2rayIntegration(true), portAllocationStart(15000){};
|
||||
XTOSTRUCT(O(pluginStates, v2rayIntegration))
|
||||
Qv2rayConfig_Plugin() : pluginStates(), v2rayIntegration(true), portAllocationStart(15000){};
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfig_Plugin, F(pluginStates, v2rayIntegration, portAllocationStart))
|
||||
};
|
||||
|
||||
struct Qv2rayConnectionConfig
|
||||
{
|
||||
bool bypassCN;
|
||||
bool enableProxy;
|
||||
bool v2rayFreedomDNS;
|
||||
bool withLocalDNS;
|
||||
Qv2rayRouteConfig routeConfig;
|
||||
QList<QString> dnsList;
|
||||
Qv2rayForwardProxyConfig forwardProxyConfig;
|
||||
Qv2rayConnectionConfig()
|
||||
: bypassCN(true), enableProxy(true), v2rayFreedomDNS(false), withLocalDNS(false), routeConfig(),
|
||||
dnsList(QStringList{ "8.8.4.4", "1.1.1.1" })
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(bypassCN, enableProxy, v2rayFreedomDNS, withLocalDNS, dnsList, forwardProxyConfig, routeConfig))
|
||||
};
|
||||
|
||||
struct Qv2rayAPIConfig
|
||||
struct Qv2rayConfig_Kernel
|
||||
{
|
||||
bool enableAPI;
|
||||
int statsPort;
|
||||
Qv2rayAPIConfig() : enableAPI(true), statsPort(15490)
|
||||
{
|
||||
}
|
||||
XTOSTRUCT(O(enableAPI, statsPort))
|
||||
};
|
||||
|
||||
struct Qv2rayKernelConfig
|
||||
{
|
||||
//
|
||||
QString v2CorePath_linux;
|
||||
QString v2AssetsPath_linux;
|
||||
QString v2CorePath_macx;
|
||||
QString v2AssetsPath_macx;
|
||||
QString v2CorePath_win;
|
||||
QString v2AssetsPath_win; //
|
||||
Qv2rayKernelConfig()
|
||||
: v2CorePath_linux(), v2AssetsPath_linux(), //
|
||||
QString v2AssetsPath_win;
|
||||
Qv2rayConfig_Kernel()
|
||||
: enableAPI(true), statsPort(15490), //
|
||||
v2CorePath_linux(), v2AssetsPath_linux(), //
|
||||
v2CorePath_macx(), v2AssetsPath_macx(), //
|
||||
v2CorePath_win(), v2AssetsPath_win() //
|
||||
{
|
||||
}
|
||||
{};
|
||||
//
|
||||
#ifdef Q_OS_LINUX
|
||||
#define _VARNAME_VCOREPATH_ v2CorePath_linux
|
||||
@ -229,10 +73,14 @@ namespace Qv2ray::base::config
|
||||
#undef _VARNAME_VCOREPATH_
|
||||
#undef _VARNAME_VASSETSPATH_
|
||||
|
||||
XTOSTRUCT(O(v2CorePath_linux, v2AssetsPath_linux, v2CorePath_macx, v2AssetsPath_macx, v2CorePath_win, v2AssetsPath_win))
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfig_Kernel, //
|
||||
F(enableAPI, statsPort), //
|
||||
F(v2CorePath_linux, v2AssetsPath_linux), //
|
||||
F(v2CorePath_macx, v2AssetsPath_macx), //
|
||||
F(v2CorePath_win, v2AssetsPath_win))
|
||||
};
|
||||
|
||||
struct Qv2rayUpdateConfig
|
||||
struct Qv2rayConfig_Update
|
||||
{
|
||||
QString ignoredVersion;
|
||||
///
|
||||
@ -240,105 +88,96 @@ namespace Qv2ray::base::config
|
||||
/// 0: Stable
|
||||
/// 1: Testing
|
||||
int updateChannel;
|
||||
XTOSTRUCT(O(ignoredVersion, updateChannel))
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfig_Update, F(ignoredVersion, updateChannel))
|
||||
};
|
||||
|
||||
struct Qv2rayAdvancedConfig
|
||||
struct Qv2rayConfig_Advanced
|
||||
{
|
||||
bool setAllowInsecure;
|
||||
bool setAllowInsecureCiphers;
|
||||
bool setSessionResumption;
|
||||
bool testLatencyPeriodcally;
|
||||
XTOSTRUCT(O(setAllowInsecure, setAllowInsecureCiphers, testLatencyPeriodcally))
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfig_Advanced, F(setAllowInsecure, setSessionResumption, testLatencyPeriodcally))
|
||||
};
|
||||
|
||||
struct Qv2rayNetworkConfig
|
||||
enum Qv2rayLatencyTestingMethod
|
||||
{
|
||||
enum Qv2rayProxyType
|
||||
TCPING,
|
||||
ICMPING
|
||||
};
|
||||
|
||||
struct Qv2rayConfig_Network
|
||||
{
|
||||
Qv2rayLatencyTestingMethod latencyTestingMethod;
|
||||
enum Qv2rayProxyType : int
|
||||
{
|
||||
QVPROXY_NONE,
|
||||
QVPROXY_SYSTEM,
|
||||
QVPROXY_CUSTOM
|
||||
QVPROXY_NONE = 0,
|
||||
QVPROXY_SYSTEM = 1,
|
||||
QVPROXY_CUSTOM = 2
|
||||
} proxyType;
|
||||
|
||||
QString address;
|
||||
QString type;
|
||||
int port;
|
||||
QString userAgent;
|
||||
Qv2rayNetworkConfig()
|
||||
Qv2rayConfig_Network()
|
||||
: proxyType(QVPROXY_NONE), //
|
||||
address("127.0.0.1"), //
|
||||
type("http"), //
|
||||
port(8000), //
|
||||
userAgent("Qv2ray/$VERSION WebRequestHelper"){};
|
||||
XTOSTRUCT(O(proxyType, type, address, port, userAgent))
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfig_Network, F(latencyTestingMethod, proxyType, type, address, port, userAgent))
|
||||
};
|
||||
|
||||
struct Qv2rayConfig
|
||||
enum Qv2rayAutoConnectionBehavior
|
||||
{
|
||||
AUTO_CONNECTION_NONE = 0,
|
||||
AUTO_CONNECTION_FIXED = 1,
|
||||
AUTO_CONNECTION_LAST_CONNECTED = 2
|
||||
};
|
||||
|
||||
struct Qv2rayConfigObject
|
||||
{
|
||||
int config_version;
|
||||
bool tProxySupport;
|
||||
int logLevel;
|
||||
//
|
||||
QString autoStartId;
|
||||
ConnectionGroupPair autoStartId;
|
||||
ConnectionGroupPair lastConnectedId;
|
||||
Qv2rayAutoConnectionBehavior autoStartBehavior;
|
||||
//
|
||||
// Key = groupId, connectionId
|
||||
QMap<QString, GroupObject_Config> groups;
|
||||
QMap<QString, SubscriptionObject_Config> subscriptions;
|
||||
/// Connections are used privately.
|
||||
QMap<QString, ConnectionObject_Config> connections;
|
||||
// QList<GroupId> groups;
|
||||
// QList<ConnectionId> connections;
|
||||
//
|
||||
Qv2rayUIConfig uiConfig;
|
||||
Qv2rayAPIConfig apiConfig;
|
||||
Qv2rayPluginConfig pluginConfig;
|
||||
Qv2rayKernelConfig kernelConfig;
|
||||
Qv2rayUpdateConfig updateConfig;
|
||||
Qv2rayNetworkConfig networkConfig;
|
||||
Qv2rayToolBarConfig toolBarConfig;
|
||||
Qv2rayInboundsConfig inboundConfig;
|
||||
Qv2rayOutboundsConfig outboundConfig;
|
||||
Qv2rayAdvancedConfig advancedConfig;
|
||||
Qv2rayConnectionConfig connectionConfig;
|
||||
Qv2rayConfig_UI uiConfig;
|
||||
Qv2rayConfig_Plugin pluginConfig;
|
||||
Qv2rayConfig_Kernel kernelConfig;
|
||||
Qv2rayConfig_Update updateConfig;
|
||||
Qv2rayConfig_Network networkConfig;
|
||||
QvConfig_Inbounds inboundConfig;
|
||||
QvConfig_Outbounds outboundConfig;
|
||||
Qv2rayConfig_Advanced advancedConfig;
|
||||
GroupRoutingConfig defaultRouteConfig;
|
||||
|
||||
Qv2rayConfig()
|
||||
Qv2rayConfigObject()
|
||||
: config_version(QV2RAY_CONFIG_VERSION), //
|
||||
tProxySupport(false), //
|
||||
logLevel(), //
|
||||
autoStartId("null"), //
|
||||
groups(), //
|
||||
subscriptions(), //
|
||||
connections(), //
|
||||
autoStartId(), //
|
||||
autoStartBehavior(), //
|
||||
uiConfig(), //
|
||||
apiConfig(), //
|
||||
pluginConfig(), //
|
||||
kernelConfig(), //
|
||||
updateConfig(), //
|
||||
networkConfig(), //
|
||||
toolBarConfig(), //
|
||||
inboundConfig(), //
|
||||
outboundConfig(), //
|
||||
advancedConfig(), //
|
||||
connectionConfig()
|
||||
{
|
||||
}
|
||||
defaultRouteConfig(){};
|
||||
|
||||
XTOSTRUCT(O(config_version, //
|
||||
tProxySupport, //
|
||||
logLevel, //
|
||||
uiConfig, //
|
||||
pluginConfig, //
|
||||
updateConfig, //
|
||||
kernelConfig, //
|
||||
networkConfig, //
|
||||
groups, //
|
||||
connections, //
|
||||
subscriptions, //
|
||||
autoStartId, //
|
||||
inboundConfig, //
|
||||
outboundConfig, //
|
||||
connectionConfig, //
|
||||
toolBarConfig, //
|
||||
advancedConfig, //
|
||||
apiConfig //
|
||||
))
|
||||
JSONSTRUCT_REGISTER(Qv2rayConfigObject, //
|
||||
F(config_version, tProxySupport, autoStartId, lastConnectedId, autoStartBehavior, logLevel), //
|
||||
F(uiConfig, advancedConfig, pluginConfig, updateConfig, kernelConfig, networkConfig), //
|
||||
F(inboundConfig, outboundConfig, defaultRouteConfig))
|
||||
};
|
||||
} // namespace Qv2ray::base::config
|
||||
|
@ -1,24 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
namespace Qv2ray
|
||||
namespace Qv2ray::base
|
||||
{
|
||||
namespace base
|
||||
struct QvStartupOptions
|
||||
{
|
||||
struct QvStartupOptions
|
||||
{
|
||||
/// No API subsystem
|
||||
bool noAPI;
|
||||
/// Explicitly run as root user.
|
||||
bool forceRunAsRootUser;
|
||||
/// Enable Debug Log.
|
||||
bool debugLog;
|
||||
/// Enable Network toolbar plugin.
|
||||
bool enableToolbarPlguin;
|
||||
/// Disable Qt scale factors support.
|
||||
bool noScaleFactors;
|
||||
/// Disable all plugin features.
|
||||
bool noPlugins;
|
||||
};
|
||||
} // namespace base
|
||||
inline base::QvStartupOptions StartupOption = base::QvStartupOptions();
|
||||
} // namespace Qv2ray
|
||||
/// No API subsystem
|
||||
bool noAPI;
|
||||
|
||||
/// Enable Debug Log.
|
||||
bool debugLog;
|
||||
|
||||
/// Disable Qt scale factors support.
|
||||
bool noScaleFactor;
|
||||
|
||||
/// Disable all plugin features.
|
||||
bool noPlugins;
|
||||
|
||||
/// Exit existing Qv2ray instance
|
||||
bool exitQv2ray;
|
||||
|
||||
///
|
||||
};
|
||||
} // namespace Qv2ray::base
|
||||
|
||||
inline Qv2ray::base::QvStartupOptions StartupOption = Qv2ray::base::QvStartupOptions();
|
||||
|
@ -1,83 +0,0 @@
|
||||
#include "CommandArgs.hpp"
|
||||
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
namespace Qv2ray::common
|
||||
{
|
||||
QvCommandArgParser::QvCommandArgParser()
|
||||
: QObject(), noAPIOption("noAPI", tr("Disable gRPC API subsystems.")), //
|
||||
runAsRootOption("I-just-wanna-run-with-root", tr("Explicitly run Qv2ray as root.")), //
|
||||
debugOption("debug", tr("Enable Debug Output")), //
|
||||
noScaleFactorOption("noScaleFactor", tr("Disable manually set QT_SCALE_FACTOR")), //
|
||||
noPluginsOption("noPlugin", tr("Disable plugin feature")), //
|
||||
withToolbarOption("withToolbarPlugin", tr("Enable Qv2ray network toolbar plugin")), //
|
||||
//
|
||||
helpOption("FAKE"), versionOption("FAKE")
|
||||
{
|
||||
parser.setApplicationDescription(QObject::tr("Qv2ray - A cross-platform Qt frontend for V2ray."));
|
||||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||
//
|
||||
parser.addOption(noAPIOption);
|
||||
parser.addOption(runAsRootOption);
|
||||
parser.addOption(debugOption);
|
||||
parser.addOption(noScaleFactorOption);
|
||||
parser.addOption(noPluginsOption);
|
||||
parser.addOption(withToolbarOption);
|
||||
helpOption = parser.addHelpOption();
|
||||
versionOption = parser.addVersionOption();
|
||||
}
|
||||
|
||||
CommandLineParseResult QvCommandArgParser::ParseCommandLine(QString *errorMessage)
|
||||
{
|
||||
if (!parser.parse(QCoreApplication::arguments()))
|
||||
{
|
||||
*errorMessage = parser.errorText();
|
||||
return CommandLineError;
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption))
|
||||
return CommandLineVersionRequested;
|
||||
|
||||
if (parser.isSet(helpOption))
|
||||
return CommandLineHelpRequested;
|
||||
|
||||
if (parser.isSet(noAPIOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "noAPIOption is set.")
|
||||
StartupOption.noAPI = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(runAsRootOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "runAsRootOption is set.")
|
||||
StartupOption.forceRunAsRootUser = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(debugOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "debugOption is set.")
|
||||
StartupOption.debugLog = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(noScaleFactorOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "noScaleFactorOption is set.")
|
||||
StartupOption.noScaleFactors = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(noPluginsOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "noPluginOption is set.")
|
||||
StartupOption.noPlugins = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(withToolbarOption))
|
||||
{
|
||||
DEBUG(MODULE_INIT, "withToolbarOption is set.")
|
||||
StartupOption.enableToolbarPlguin = true;
|
||||
}
|
||||
|
||||
return CommandLineOk;
|
||||
}
|
||||
|
||||
} // namespace Qv2ray::common
|
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
namespace Qv2ray::common
|
||||
{
|
||||
enum CommandLineParseResult
|
||||
{
|
||||
CommandLineOk,
|
||||
CommandLineError,
|
||||
CommandLineVersionRequested,
|
||||
CommandLineHelpRequested
|
||||
};
|
||||
class QvCommandArgParser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QvCommandArgParser();
|
||||
CommandLineParseResult ParseCommandLine(QString *errorMessage);
|
||||
const QCommandLineParser *Parser()
|
||||
{
|
||||
return &parser;
|
||||
}
|
||||
|
||||
private:
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption noAPIOption;
|
||||
QCommandLineOption runAsRootOption;
|
||||
QCommandLineOption debugOption;
|
||||
QCommandLineOption noScaleFactorOption;
|
||||
QCommandLineOption noPluginsOption;
|
||||
QCommandLineOption withToolbarOption;
|
||||
QCommandLineOption helpOption;
|
||||
QCommandLineOption versionOption;
|
||||
};
|
||||
} // namespace Qv2ray::common
|
||||
|
||||
using namespace Qv2ray::common;
|
@ -5,39 +5,30 @@
|
||||
#include <QByteArray>
|
||||
#include <QNetworkProxy>
|
||||
|
||||
namespace Qv2ray::common
|
||||
namespace Qv2ray::common::network
|
||||
{
|
||||
QvHttpRequestHelper::QvHttpRequestHelper(QObject *parent) : QObject(parent), reply()
|
||||
{
|
||||
}
|
||||
|
||||
QvHttpRequestHelper::~QvHttpRequestHelper()
|
||||
{
|
||||
accessManager.disconnect();
|
||||
}
|
||||
|
||||
void QvHttpRequestHelper::setHeader(const QByteArray &key, const QByteArray &value)
|
||||
void NetworkRequestHelper::setHeader(QNetworkRequest &request, const QByteArray &key, const QByteArray &value)
|
||||
{
|
||||
DEBUG(MODULE_NETWORK, "Adding HTTP request header: " + key + ":" + value)
|
||||
request.setRawHeader(key, value);
|
||||
}
|
||||
|
||||
void QvHttpRequestHelper::setAccessManagerAttributes(QNetworkAccessManager &accessManager)
|
||||
void NetworkRequestHelper::setAccessManagerAttributes(QNetworkRequest &request, QNetworkAccessManager &accessManager)
|
||||
{
|
||||
switch (GlobalConfig.networkConfig.proxyType)
|
||||
{
|
||||
case Qv2rayNetworkConfig::QVPROXY_NONE:
|
||||
case Qv2rayConfig_Network::QVPROXY_NONE:
|
||||
{
|
||||
DEBUG(MODULE_NETWORK, "Get without proxy.")
|
||||
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
|
||||
break;
|
||||
}
|
||||
case Qv2rayNetworkConfig::QVPROXY_SYSTEM:
|
||||
case Qv2rayConfig_Network::QVPROXY_SYSTEM:
|
||||
{
|
||||
accessManager.setProxy(QNetworkProxyFactory::systemProxyForQuery().first());
|
||||
break;
|
||||
}
|
||||
case Qv2rayNetworkConfig::QVPROXY_CUSTOM:
|
||||
case Qv2rayConfig_Network::QVPROXY_CUSTOM:
|
||||
{
|
||||
QNetworkProxy p{
|
||||
GlobalConfig.networkConfig.type == "http" ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy, //
|
||||
@ -47,6 +38,7 @@ namespace Qv2ray::common
|
||||
accessManager.setProxy(p);
|
||||
break;
|
||||
}
|
||||
default: Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy)
|
||||
@ -56,59 +48,60 @@ namespace Qv2ray::common
|
||||
}
|
||||
|
||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
// request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);
|
||||
#else
|
||||
// request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||
#endif
|
||||
|
||||
auto ua = GlobalConfig.networkConfig.userAgent;
|
||||
ua.replace("$VERSION", QV2RAY_VERSION_STRING);
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, ua);
|
||||
}
|
||||
|
||||
QByteArray QvHttpRequestHelper::Get(const QString &url)
|
||||
QByteArray NetworkRequestHelper::HttpGet(const QUrl &url)
|
||||
{
|
||||
request.setUrl({ url });
|
||||
setAccessManagerAttributes(accessManager);
|
||||
QNetworkRequest request;
|
||||
QNetworkAccessManager accessManager;
|
||||
request.setUrl(url);
|
||||
setAccessManagerAttributes(request, accessManager);
|
||||
auto _reply = accessManager.get(request);
|
||||
//
|
||||
QEventLoop loop;
|
||||
connect(_reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
{
|
||||
QEventLoop loop;
|
||||
QObject::connect(&accessManager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
}
|
||||
//
|
||||
// Data or timeout?
|
||||
LOG(MODULE_NETWORK, _reply->errorString());
|
||||
auto data = _reply->readAll();
|
||||
return data;
|
||||
}
|
||||
|
||||
void QvHttpRequestHelper::AsyncGet(const QString &url)
|
||||
void NetworkRequestHelper::AsyncHttpGet(const QString &url, std::function<void(const QByteArray &)> funcPtr)
|
||||
{
|
||||
request.setUrl({ url });
|
||||
setAccessManagerAttributes(accessManager);
|
||||
reply = accessManager.get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
|
||||
connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead_p);
|
||||
QNetworkRequest request;
|
||||
request.setUrl(url);
|
||||
setAccessManagerAttributes(request, accessManager);
|
||||
auto reply = accessManager.get(request);
|
||||
QObject::connect(reply, &QNetworkReply::finished, [=]() {
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
bool h2Used = reply->attribute(QNetworkRequest::Http2WasUsedAttribute).toBool();
|
||||
#else
|
||||
bool h2Used = reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool();
|
||||
#endif
|
||||
if (h2Used)
|
||||
DEBUG(MODULE_NETWORK, "HTTP/2 was used.")
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
LOG(MODULE_NETWORK, "Network error: " + QString(QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error())))
|
||||
|
||||
funcPtr(reply->readAll());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void QvHttpRequestHelper::onRequestFinished_p()
|
||||
{
|
||||
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool())
|
||||
{
|
||||
DEBUG(MODULE_NETWORK, "HTTP/2 was used.")
|
||||
}
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
|
||||
LOG(MODULE_NETWORK, "Network request error string: " + error)
|
||||
QByteArray empty;
|
||||
emit OnRequestFinished(empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit OnRequestFinished(this->data);
|
||||
}
|
||||
}
|
||||
|
||||
void QvHttpRequestHelper::onReadyRead_p()
|
||||
{
|
||||
DEBUG(MODULE_NETWORK, "A request is now ready read")
|
||||
this->data += reply->readAll();
|
||||
}
|
||||
} // namespace Qv2ray::common
|
||||
} // namespace Qv2ray::common::network
|
||||
|
@ -1,55 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2019 SoneWinstone (jianwenzhen@qq.com)
|
||||
Copyright (C) 2019 Leroy.H.Y
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
|
||||
namespace Qv2ray::common
|
||||
namespace Qv2ray::common::network
|
||||
{
|
||||
class QvHttpRequestHelper : public QObject
|
||||
class NetworkRequestHelper : QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QvHttpRequestHelper(QObject *parent = nullptr);
|
||||
~QvHttpRequestHelper();
|
||||
// get
|
||||
void AsyncGet(const QString &url);
|
||||
QByteArray Get(const QString &url);
|
||||
signals:
|
||||
void OnRequestFinished(QByteArray &data);
|
||||
|
||||
private slots:
|
||||
void onRequestFinished_p();
|
||||
void onReadyRead_p();
|
||||
explicit NetworkRequestHelper(QObject *parent) : QObject(parent){};
|
||||
~NetworkRequestHelper(){};
|
||||
void AsyncHttpGet(const QString &url, std::function<void(const QByteArray &)> funcPtr);
|
||||
static QByteArray HttpGet(const QUrl &url);
|
||||
|
||||
private:
|
||||
void setAccessManagerAttributes(QNetworkAccessManager &accessManager);
|
||||
void setHeader(const QByteArray &key, const QByteArray &value);
|
||||
QByteArray data;
|
||||
QUrl url;
|
||||
QNetworkReply *reply;
|
||||
QNetworkRequest request;
|
||||
static void setAccessManagerAttributes(QNetworkRequest &request, QNetworkAccessManager &accessManager);
|
||||
static void setHeader(QNetworkRequest &request, const QByteArray &key, const QByteArray &value);
|
||||
QNetworkAccessManager accessManager;
|
||||
};
|
||||
} // namespace Qv2ray::common
|
||||
} // namespace Qv2ray::common::network
|
||||
|
||||
using namespace Qv2ray::common;
|
||||
using namespace Qv2ray::common::network;
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFont>
|
||||
|
||||
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
|
||||
{
|
||||
|
@ -25,12 +25,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIcon>
|
||||
#include <QByteArray>
|
||||
#include <QIODevice>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
class QJsonModel;
|
||||
class QJsonItem;
|
||||
|
||||
|
@ -1,18 +1,13 @@
|
||||
#include "common/QvHelpers.hpp"
|
||||
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
#include "libs/puresource/src/PureJson.hpp"
|
||||
|
||||
#include <QGraphicsEffect>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
#include <QQueue>
|
||||
|
||||
namespace Qv2ray::common
|
||||
{
|
||||
const QString GenerateRandomString(int len)
|
||||
{
|
||||
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||
const QString possibleCharacters("abcdefghijklmnopqrstuvwxyz");
|
||||
QString randomString;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
@ -41,39 +36,31 @@ namespace Qv2ray::common
|
||||
if (!wasOpened)
|
||||
source.close();
|
||||
//
|
||||
QTextCodec::ConverterState state;
|
||||
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
||||
QTextCodec::ConverterState state;
|
||||
const QString text = codec->toUnicode(byteArray.constData(), byteArray.size(), &state);
|
||||
if (state.invalidChars > 0)
|
||||
{
|
||||
LOG(MODULE_FILEIO, "Not a valid UTF-8 sequence: " + source.fileName())
|
||||
return byteArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
return text;
|
||||
}
|
||||
return state.invalidChars > 0 ? byteArray : text;
|
||||
}
|
||||
|
||||
bool StringToFile(const QString &text, const QString &targetpath)
|
||||
{
|
||||
auto file = QFile(targetpath);
|
||||
return StringToFile(text, file);
|
||||
}
|
||||
bool StringToFile(const QString &text, QFile &targetFile)
|
||||
{
|
||||
QFileInfo info(targetFile);
|
||||
if (!info.dir().exists())
|
||||
bool override = false;
|
||||
{
|
||||
info.dir().mkpath(info.dir().path());
|
||||
QFileInfo info(targetpath);
|
||||
override = info.exists();
|
||||
if (!override && !info.dir().exists())
|
||||
info.dir().mkpath(info.dir().path());
|
||||
}
|
||||
bool override = targetFile.exists();
|
||||
targetFile.open(QFile::WriteOnly);
|
||||
targetFile.write(text.toUtf8());
|
||||
targetFile.close();
|
||||
QSaveFile f{ targetpath };
|
||||
f.open(QIODevice::WriteOnly);
|
||||
f.write(text.toUtf8());
|
||||
f.commit();
|
||||
return override;
|
||||
}
|
||||
|
||||
QString JsonToString(const QJsonObject &json, QJsonDocument::JsonFormat format)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
@ -116,6 +103,31 @@ namespace Qv2ray::common
|
||||
return doc.object();
|
||||
}
|
||||
|
||||
// backported from QvPlugin-SSR.
|
||||
QString SafeBase64Decode(QString string)
|
||||
{
|
||||
QByteArray ba = string.replace(QChar('-'), QChar('+')).replace(QChar('_'), QChar('/')).toUtf8();
|
||||
return QByteArray::fromBase64(ba, QByteArray::Base64Option::OmitTrailingEquals);
|
||||
}
|
||||
|
||||
// backported from QvPlugin-SSR.
|
||||
QString SafeBase64Encode(const QString &string, bool trim)
|
||||
{
|
||||
QString base64 = string.toUtf8().toBase64();
|
||||
if (trim)
|
||||
{
|
||||
auto tmp = base64.replace(QChar('+'), QChar('-')).replace(QChar('/'), QChar('_'));
|
||||
auto crbedin = tmp.crbegin();
|
||||
auto idx = tmp.length();
|
||||
while (crbedin != tmp.crend() && (*crbedin) == '=') idx -= 1, crbedin++;
|
||||
return idx != tmp.length() ? tmp.remove(idx, tmp.length() - idx) : tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base64.replace(QChar('+'), QChar('-')).replace(QChar('/'), QChar('_'));
|
||||
}
|
||||
}
|
||||
|
||||
QString Base64Encode(const QString &string)
|
||||
{
|
||||
QByteArray ba = string.toUtf8();
|
||||
@ -130,19 +142,11 @@ namespace Qv2ray::common
|
||||
|
||||
QStringList SplitLines(const QString &_string)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
return _string.split(QRegExp("[\r\n]"), Qt::SkipEmptyParts);
|
||||
#else
|
||||
return _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
|
||||
}
|
||||
|
||||
list<string> SplitLines_std(const QString &_string)
|
||||
{
|
||||
list<string> list;
|
||||
|
||||
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts))
|
||||
{
|
||||
list.push_back(line.toStdString());
|
||||
}
|
||||
|
||||
return list;
|
||||
#endif
|
||||
}
|
||||
|
||||
QStringList GetFileList(const QDir &dir)
|
||||
@ -155,22 +159,6 @@ namespace Qv2ray::common
|
||||
return GetFileList(dir).contains(fileName);
|
||||
}
|
||||
|
||||
void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text)
|
||||
{
|
||||
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
||||
}
|
||||
|
||||
void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text)
|
||||
{
|
||||
QMessageBox::information(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButton extraButtons)
|
||||
{
|
||||
return QMessageBox::question(parent, title, text, QMessageBox::Yes | QMessageBox::No | extraButtons);
|
||||
}
|
||||
|
||||
QString FormatBytes(const int64_t b)
|
||||
{
|
||||
auto _bytes = b;
|
||||
@ -195,7 +183,7 @@ namespace Qv2ray::common
|
||||
{
|
||||
std::string _name = fileName.toStdString();
|
||||
std::replace_if(
|
||||
_name.begin(), _name.end(), [](char c) { return std::string::npos != string(R"("/\?%&^*;:|><)").find(c); }, '_');
|
||||
_name.begin(), _name.end(), [](char c) { return std::string::npos != std::string(R"("/\?%&^*;:|><)").find(c); }, '_');
|
||||
return QString::fromStdString(_name);
|
||||
}
|
||||
|
||||
@ -225,38 +213,20 @@ namespace Qv2ray::common
|
||||
i++;
|
||||
}
|
||||
}
|
||||
QPixmap ApplyEffectToImage(QPixmap src, QGraphicsEffect *effect, int extent)
|
||||
|
||||
void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text)
|
||||
{
|
||||
constexpr int extent2 = 0;
|
||||
if (src.isNull())
|
||||
return QPixmap(); // No need to do anything else!
|
||||
if (!effect)
|
||||
return src; // No need to do anything else!
|
||||
QGraphicsScene scene;
|
||||
auto p = scene.addPixmap(src);
|
||||
p->setGraphicsEffect(effect);
|
||||
//
|
||||
QImage res(src.size() + QSize(extent2, extent2), QImage::Format_ARGB32);
|
||||
res.fill(Qt::transparent);
|
||||
QPainter ptr(&res);
|
||||
//
|
||||
scene.render(&ptr, QRectF(), QRectF(-extent, -extent, src.width() + extent2, src.height() + extent * 2));
|
||||
//
|
||||
scene.removeItem(p);
|
||||
return QPixmap::fromImage(res);
|
||||
}
|
||||
QPixmap BlurImage(const QPixmap &pixmap, const double rad)
|
||||
{
|
||||
QGraphicsBlurEffect pBlur;
|
||||
pBlur.setBlurRadius(rad);
|
||||
return ApplyEffectToImage(pixmap, &pBlur, 0);
|
||||
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
||||
}
|
||||
|
||||
QPixmap ColorizeImage(const QPixmap &pixmap, const QColor &color, const qreal factor)
|
||||
void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text)
|
||||
{
|
||||
QGraphicsColorizeEffect pColor;
|
||||
pColor.setColor(color);
|
||||
pColor.setStrength(factor);
|
||||
return ApplyEffectToImage(pixmap, &pColor, 0);
|
||||
QMessageBox::information(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
||||
}
|
||||
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButton extraButtons)
|
||||
{
|
||||
return QMessageBox::question(parent, title, text, QMessageBox::Yes | QMessageBox::No | extraButtons);
|
||||
}
|
||||
|
||||
} // namespace Qv2ray::common
|
||||
|
@ -1,8 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QHostAddress>
|
||||
#include <QJsonDocument>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#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*\])"
|
||||
@ -13,21 +17,20 @@
|
||||
namespace Qv2ray::common
|
||||
{
|
||||
QStringList GetFileList(const QDir &dir);
|
||||
|
||||
QString SafeBase64Decode(QString string);
|
||||
QString SafeBase64Encode(const QString &string, bool trim);
|
||||
|
||||
QString Base64Encode(const QString &string);
|
||||
QString Base64Decode(const QString &string);
|
||||
QStringList SplitLines(const QString &str);
|
||||
list<string> SplitLines_std(const QString &_string);
|
||||
// list<string> SplitLines_std(const QString &_string);
|
||||
bool FileExistsIn(const QDir &dir, const QString &fileName);
|
||||
const QString GenerateRandomString(int len = 12);
|
||||
//
|
||||
void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text);
|
||||
void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text);
|
||||
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButton extraButtons = QMessageBox::NoButton);
|
||||
//
|
||||
QString StringFromFile(const QString &filePath);
|
||||
QString StringFromFile(QFile &source);
|
||||
bool StringToFile(const QString &text, QFile &target);
|
||||
// bool StringToFile(const QString &text, QFile &target);
|
||||
bool StringToFile(const QString &text, const QString &targetpath);
|
||||
//
|
||||
QJsonObject JsonFromString(const QString &string);
|
||||
@ -38,9 +41,6 @@ namespace Qv2ray::common
|
||||
QString FormatBytes(const int64_t bytes);
|
||||
void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension);
|
||||
//
|
||||
QPixmap ApplyEffectToImage(QPixmap src, QGraphicsEffect *effect, int extent);
|
||||
QPixmap BlurImage(const QPixmap &pixmap, const double rad = 50);
|
||||
QPixmap ColorizeImage(const QPixmap &pixmap, const QColor &color, const qreal factor);
|
||||
// This function cannot be marked as inline.
|
||||
QString RemoveInvalidFileName(const QString &fileName);
|
||||
bool IsValidFileName(const QString &fileName);
|
||||
@ -49,27 +49,6 @@ namespace Qv2ray::common
|
||||
return GenerateRandomString().toLower();
|
||||
// return QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
}
|
||||
//
|
||||
template<typename TYPE>
|
||||
QString StructToJsonString(const TYPE &t)
|
||||
{
|
||||
return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' '));
|
||||
}
|
||||
//
|
||||
template<typename TYPE>
|
||||
TYPE StructFromJsonString(const QString &str)
|
||||
{
|
||||
TYPE v;
|
||||
x2struct::X::loadjson(str.toStdString(), v, false);
|
||||
return v;
|
||||
}
|
||||
// Misc
|
||||
template<typename T>
|
||||
QJsonObject GetRootObject(const T &t)
|
||||
{
|
||||
auto json = StructToJsonString(t);
|
||||
return JsonFromString(json);
|
||||
}
|
||||
|
||||
inline QString TruncateString(const QString &str, int limit = -1, const QString &suffix = "...")
|
||||
{
|
||||
@ -81,7 +60,6 @@ namespace Qv2ray::common
|
||||
namespace validation
|
||||
{
|
||||
const inline QRegularExpression __regex_ipv4_full(REGEX_IPV4_ADDR "$");
|
||||
const inline QRegularExpression __regex_ipv6_full(REGEX_IPV6_ADDR "$");
|
||||
|
||||
inline bool IsIPv4Address(const QString &addr)
|
||||
{
|
||||
@ -90,12 +68,22 @@ namespace Qv2ray::common
|
||||
|
||||
inline bool IsIPv6Address(const QString &addr)
|
||||
{
|
||||
return __regex_ipv6_full.match(addr).hasMatch();
|
||||
QHostAddress address(addr);
|
||||
return QAbstractSocket::IPv6Protocol == address.protocol();
|
||||
}
|
||||
|
||||
inline bool IsValidIPAddress(const QString &addr)
|
||||
{
|
||||
return IsIPv4Address(addr) || IsIPv6Address(addr);
|
||||
return !addr.isEmpty() && (IsIPv4Address(addr) || IsIPv6Address(addr));
|
||||
}
|
||||
|
||||
inline bool IsValidDNSServer(const QString &addr)
|
||||
{
|
||||
return IsIPv4Address(addr) //
|
||||
|| IsIPv6Address(addr) //
|
||||
|| addr.startsWith("https://") //
|
||||
|| addr.startsWith("https+local://") //
|
||||
|| addr == "localhost";
|
||||
}
|
||||
} // namespace validation
|
||||
|
||||
@ -103,18 +91,12 @@ namespace Qv2ray::common
|
||||
{
|
||||
QDateTime timestamp;
|
||||
timestamp.setSecsSinceEpoch(t);
|
||||
return timestamp.toString(Qt::SystemLocaleShortDate);
|
||||
}
|
||||
|
||||
inline void FastAppendTextDocument(const QString &message, QTextDocument *doc)
|
||||
{
|
||||
QTextCursor cursor(doc);
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
cursor.beginEditBlock();
|
||||
cursor.insertBlock();
|
||||
cursor.insertText(message);
|
||||
cursor.endEditBlock();
|
||||
return timestamp.toString();
|
||||
}
|
||||
void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text);
|
||||
void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text);
|
||||
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButton extraButtons = QMessageBox::StandardButton::NoButton);
|
||||
} // namespace Qv2ray::common
|
||||
|
||||
using namespace Qv2ray::common;
|
||||
|
@ -1,16 +1,8 @@
|
||||
#include "QvTranslator.hpp"
|
||||
|
||||
#include "base/Qv2rayLog.hpp"
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
#include "common/QvHelpers.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QTranslator>
|
||||
#include <memory>
|
||||
|
||||
using namespace Qv2ray::base;
|
||||
|
||||
// path searching list.
|
||||
@ -27,20 +19,19 @@ QStringList getLanguageSearchPaths()
|
||||
list << QString(QV2RAY_TRANSLATION_PATH);
|
||||
#endif
|
||||
return list;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Qv2ray::common
|
||||
{
|
||||
QvTranslator::QvTranslator()
|
||||
{
|
||||
DEBUG(MODULE_UI, "QvTranslator constructor.")
|
||||
GetAvailableLanguages();
|
||||
}
|
||||
|
||||
QStringList QvTranslator::GetAvailableLanguages()
|
||||
{
|
||||
languages.clear();
|
||||
for (auto path : getLanguageSearchPaths())
|
||||
for (const auto &path : getLanguageSearchPaths())
|
||||
{
|
||||
languages << QDir(path).entryList(QStringList{ "*.qm" }, QDir::Hidden | QDir::Files);
|
||||
}
|
||||
@ -52,20 +43,21 @@ namespace Qv2ray::common
|
||||
|
||||
bool QvTranslator::InstallTranslation(const QString &code)
|
||||
{
|
||||
for (auto path : getLanguageSearchPaths())
|
||||
for (const auto &path : getLanguageSearchPaths())
|
||||
{
|
||||
if (FileExistsIn(QDir(path), code + ".qm"))
|
||||
{
|
||||
LOG(MODULE_UI, "Found " + code + " in folder: " + path)
|
||||
DEBUG(MODULE_UI, "Found " + code + " in folder: " + path)
|
||||
QTranslator *translatorNew = new QTranslator();
|
||||
translatorNew->load(code + ".qm", path);
|
||||
if (pTranslator)
|
||||
{
|
||||
LOG(MODULE_INIT, "Removed translations")
|
||||
LOG(MODULE_UI, "Removed translations")
|
||||
qApp->removeTranslator(pTranslator.get());
|
||||
}
|
||||
this->pTranslator.reset(translatorNew);
|
||||
qApp->installTranslator(pTranslator.get());
|
||||
LOG(MODULE_UI, "Successfully installed a translator for " + code)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "QvAutoLaunch.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
@ -29,7 +31,7 @@ namespace Qv2ray::components::autolaunch
|
||||
bool GetLaunchAtLoginStatus()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
QString appName = QApplication::applicationName();
|
||||
QString appName = QCoreApplication::applicationName();
|
||||
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||
return reg.contains(appName);
|
||||
}
|
||||
@ -80,7 +82,7 @@ namespace Qv2ray::components::autolaunch
|
||||
}
|
||||
|
||||
#elif defined Q_OS_LINUX
|
||||
QString appName = QApplication::applicationName();
|
||||
QString appName = QCoreApplication::applicationName();
|
||||
QString desktopFileLocation = getUserAutostartDir_private() + appName + QLatin1String(".desktop");
|
||||
return QFile::exists(desktopFileLocation);
|
||||
}
|
||||
@ -89,7 +91,7 @@ namespace Qv2ray::components::autolaunch
|
||||
void SetLaunchAtLoginStatus(bool enable)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
QString appName = QApplication::applicationName();
|
||||
QString appName = QCoreApplication::applicationName();
|
||||
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||
|
||||
if (enable)
|
||||
@ -160,7 +162,7 @@ namespace Qv2ray::components::autolaunch
|
||||
auto binPath = qEnvironmentVariableIsSet("APPIMAGE") ? qEnvironmentVariable("APPIMAGE") : QCoreApplication::applicationFilePath();
|
||||
//
|
||||
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_unix.cpp
|
||||
QString appName = QApplication::applicationName();
|
||||
QString appName = QCoreApplication::applicationName();
|
||||
QString userAutoStartPath = getUserAutostartDir_private();
|
||||
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
|
||||
|
||||
@ -184,24 +186,23 @@ namespace Qv2ray::components::autolaunch
|
||||
|
||||
QTextStream ts(&iniFile);
|
||||
ts.setCodec("UTF-8");
|
||||
ts << QLatin1String("[Desktop Entry]") << endl
|
||||
<< QLatin1String("Name=") << QApplication::applicationName() << endl
|
||||
<< QLatin1String("GenericName=") << QLatin1String("V2ray Frontend") << endl
|
||||
<< QLatin1String("Exec=") << binPath << endl
|
||||
<< QLatin1String("Terminal=") << "false" << endl
|
||||
<< QLatin1String("Icon=") << "qv2ray" << endl // always use lowercase for icons
|
||||
<< QLatin1String("Categories=") << "Network" << endl
|
||||
<< QLatin1String("Type=") << "Application" << endl
|
||||
<< QLatin1String("StartupNotify=") << "false" << endl
|
||||
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl;
|
||||
ts << QLatin1String("[Desktop Entry]") << NEWLINE //
|
||||
<< QLatin1String("Name=") << QCoreApplication::applicationName() + QCoreApplication::arguments().join(" ") << NEWLINE //
|
||||
<< QLatin1String("GenericName=") << QLatin1String("V2ray Frontend") << NEWLINE //
|
||||
<< QLatin1String("Exec=") << binPath << NEWLINE //
|
||||
<< QLatin1String("Terminal=") << "false" << NEWLINE //
|
||||
<< QLatin1String("Icon=") << "qv2ray" << NEWLINE //
|
||||
<< QLatin1String("Categories=") << "Network" << NEWLINE //
|
||||
<< QLatin1String("Type=") << "Application" << NEWLINE //
|
||||
<< QLatin1String("StartupNotify=") << "false" << NEWLINE //
|
||||
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << NEWLINE;
|
||||
ts.flush();
|
||||
iniFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QFile::remove(desktopFileLocation))
|
||||
{
|
||||
// qCWarning(lcUtility) << "Could not remove autostart desktop
|
||||
// file";
|
||||
}
|
||||
QFile::remove(desktopFileLocation);
|
||||
QFile::remove(desktopFileLocation.replace("qv2ray", "Qv2ray"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include "DarkmodeDetector.hpp"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
#ifdef Q_OS_LINUX
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
#elif defined(Q_OS_WIN32)
|
||||
#include <QSettings>
|
||||
#else
|
||||
@ -16,7 +17,7 @@ namespace Qv2ray::components::darkmode
|
||||
// Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
||||
bool isDarkMode()
|
||||
{
|
||||
#if defined(Q_OS_LINUX)
|
||||
#if !QvHasFeature(NativeDarkmode)
|
||||
if (!qApp || !qApp->style())
|
||||
{
|
||||
return false;
|
||||
@ -25,9 +26,6 @@ namespace Qv2ray::components::darkmode
|
||||
#elif defined(Q_OS_WIN32)
|
||||
QSettings settings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", QSettings::NativeFormat);
|
||||
return settings.value("AppsUseLightTheme", 1).toInt() == 0;
|
||||
#elif defined(Q_OS_DARWIN)
|
||||
// TODO: expand this stub
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1,41 +1,54 @@
|
||||
#include "QvGeositeReader.hpp"
|
||||
|
||||
#include "v2ray_geosite.pb.h"
|
||||
#ifndef ANDROID
|
||||
#include "v2ray_geosite.pb.h"
|
||||
#endif
|
||||
|
||||
namespace Qv2ray::components::geosite
|
||||
{
|
||||
QMap<QString, QStringList> GeositeEntries;
|
||||
QStringList ReadGeoSiteFromFile(const QString &filepath)
|
||||
{
|
||||
QStringList list;
|
||||
LOG(MODULE_FILEIO, "Reading geosites from: " + filepath)
|
||||
//
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
//
|
||||
QFile f(filepath);
|
||||
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
|
||||
|
||||
if (!opened)
|
||||
if (GeositeEntries.contains(filepath))
|
||||
{
|
||||
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
|
||||
return GeositeEntries.value(filepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList list;
|
||||
#ifndef ANDROID
|
||||
LOG(MODULE_FILEIO, "Reading geosites from: " + filepath)
|
||||
//
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
//
|
||||
QFile f(filepath);
|
||||
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
|
||||
|
||||
if (!opened)
|
||||
{
|
||||
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
|
||||
return list;
|
||||
}
|
||||
|
||||
auto content = f.readAll();
|
||||
f.close();
|
||||
//
|
||||
GeoSiteList sites;
|
||||
sites.ParseFromArray(content.data(), content.size());
|
||||
|
||||
for (const auto &e : sites.entry())
|
||||
{
|
||||
// We want to use lower string.
|
||||
list << QString::fromStdString(e.country_code()).toLower();
|
||||
}
|
||||
|
||||
LOG(MODULE_FILEIO, "Loaded " + QSTRN(list.count()) + " geosite entries from data file.")
|
||||
// Optional: Delete all global objects allocated by libprotobuf.
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
#endif
|
||||
list.sort();
|
||||
GeositeEntries[filepath] = list;
|
||||
return list;
|
||||
}
|
||||
|
||||
auto content = f.readAll();
|
||||
f.close();
|
||||
//
|
||||
GeoSiteList sites;
|
||||
sites.ParseFromArray(content.data(), content.size());
|
||||
|
||||
for (auto e : sites.entry())
|
||||
{
|
||||
// We want to use lower string.
|
||||
list << QString::fromStdString(e.country_code()).toLower();
|
||||
}
|
||||
|
||||
LOG(MODULE_FILEIO, "Loaded " + QSTRN(list.count()) + " geosite entries from data file.")
|
||||
// Optional: Delete all global objects allocated by libprotobuf.
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
list.sort();
|
||||
return list;
|
||||
}
|
||||
} // namespace Qv2ray::components::geosite
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace Qv2ray::components::geosite
|
||||
{
|
||||
QStringList ReadGeoSiteFromFile(const QString &filepath);
|
||||
}
|
||||
} // namespace Qv2ray::components::geosite
|
||||
|
||||
using namespace Qv2ray::components;
|
||||
using namespace Qv2ray::components::geosite;
|
||||
|
50
src/components/latency/LatencyTest.cpp
Normal file
50
src/components/latency/LatencyTest.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "LatencyTest.hpp"
|
||||
|
||||
#include "LatencyTestThread.hpp"
|
||||
#include "core/handler/ConfigHandler.hpp"
|
||||
|
||||
constexpr auto LATENCY_PROPERTY_KEY = "__QvLatencyTest__";
|
||||
|
||||
namespace Qv2ray::components::latency
|
||||
{
|
||||
LatencyTestHost::LatencyTestHost(const int defaultCount, QObject *parent) : QObject(parent)
|
||||
{
|
||||
totalTestCount = defaultCount;
|
||||
}
|
||||
|
||||
void LatencyTestHost::StopAllLatencyTest()
|
||||
{
|
||||
for (const auto &thread : latencyThreads)
|
||||
{
|
||||
thread->terminate();
|
||||
thread->deleteLater();
|
||||
}
|
||||
}
|
||||
void LatencyTestHost::TestLatency(const ConnectionId &id, Qv2rayLatencyTestingMethod method)
|
||||
{
|
||||
const auto &[protocol, host, port] = GetConnectionInfo(id);
|
||||
auto thread = new LatencyTestThread(host, port, method, totalTestCount, this);
|
||||
connect(thread, &QThread::finished, this, &LatencyTestHost::OnLatencyThreadProcessCompleted);
|
||||
thread->setProperty(LATENCY_PROPERTY_KEY, QVariant::fromValue(id));
|
||||
latencyThreads.push_back(thread);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void LatencyTestHost::OnLatencyThreadProcessCompleted()
|
||||
{
|
||||
const auto senderThread = qobject_cast<LatencyTestThread *>(sender());
|
||||
latencyThreads.removeOne(senderThread);
|
||||
auto result = senderThread->GetResult();
|
||||
|
||||
if (!result.errorMessage.isEmpty())
|
||||
{
|
||||
LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage)
|
||||
result.avg = LATENCY_TEST_VALUE_ERROR;
|
||||
result.best = LATENCY_TEST_VALUE_ERROR;
|
||||
result.worst = LATENCY_TEST_VALUE_ERROR;
|
||||
}
|
||||
|
||||
emit OnLatencyTestCompleted(senderThread->property(LATENCY_PROPERTY_KEY).value<ConnectionId>(), result);
|
||||
}
|
||||
|
||||
} // namespace Qv2ray::components::latency
|
37
src/components/latency/LatencyTest.hpp
Normal file
37
src/components/latency/LatencyTest.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
|
||||
namespace Qv2ray::components::latency
|
||||
{
|
||||
class LatencyTestThread;
|
||||
struct LatencyTestResult
|
||||
{
|
||||
QString errorMessage;
|
||||
int totalCount;
|
||||
int failedCount;
|
||||
long worst = LATENCY_TEST_VALUE_ERROR;
|
||||
long best = LATENCY_TEST_VALUE_ERROR;
|
||||
long avg = LATENCY_TEST_VALUE_ERROR;
|
||||
Qv2rayLatencyTestingMethod method;
|
||||
};
|
||||
|
||||
class LatencyTestHost : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LatencyTestHost(const int defaultCount = 3, QObject *parent = nullptr);
|
||||
void TestLatency(const ConnectionId &connectionId, Qv2rayLatencyTestingMethod);
|
||||
void StopAllLatencyTest();
|
||||
signals:
|
||||
void OnLatencyTestCompleted(const ConnectionId &id, const LatencyTestResult &data);
|
||||
|
||||
private slots:
|
||||
void OnLatencyThreadProcessCompleted();
|
||||
|
||||
private:
|
||||
int totalTestCount;
|
||||
QList<LatencyTestThread *> latencyThreads;
|
||||
};
|
||||
} // namespace Qv2ray::components::latency
|
||||
|
||||
using namespace Qv2ray::components::latency;
|
79
src/components/latency/LatencyTestThread.cpp
Normal file
79
src/components/latency/LatencyTestThread.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "LatencyTestThread.hpp"
|
||||
|
||||
#include "TCPing.hpp"
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include "unix/ICMPPing.hpp"
|
||||
#else
|
||||
#include "win/ICMPPing.hpp"
|
||||
#endif
|
||||
|
||||
namespace Qv2ray::components::latency
|
||||
{
|
||||
|
||||
LatencyTestThread::LatencyTestThread(const QString &host, int port, Qv2rayLatencyTestingMethod method, int count, QObject *parent)
|
||||
: QThread(parent)
|
||||
{
|
||||
this->count = count;
|
||||
this->host = host;
|
||||
this->port = port;
|
||||
this->method = method;
|
||||
this->resultData = {};
|
||||
this->resultData.method = method;
|
||||
}
|
||||
void LatencyTestThread::run()
|
||||
{
|
||||
resultData.avg = 0;
|
||||
resultData.best = 0;
|
||||
resultData.worst = 0;
|
||||
switch (method)
|
||||
{
|
||||
case ICMPING:
|
||||
{
|
||||
icmping::ICMPPing ping(30);
|
||||
for (auto i = 0; i < count; i++)
|
||||
{
|
||||
resultData.totalCount++;
|
||||
const auto pair = ping.ping(host);
|
||||
const auto &errMessage = pair.second;
|
||||
const long _latency = pair.first;
|
||||
if (!errMessage.isEmpty())
|
||||
{
|
||||
resultData.errorMessage.append(NEWLINE + errMessage);
|
||||
resultData.failedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
// Is it Windows?
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
resultData.avg += _latency;
|
||||
resultData.best = std::min(resultData.best, _latency);
|
||||
resultData.worst = std::max(resultData.worst, _latency);
|
||||
}
|
||||
}
|
||||
if (resultData.totalCount != 0 && resultData.failedCount != 0)
|
||||
{
|
||||
resultData.errorMessage.clear();
|
||||
resultData.avg = resultData.avg / (resultData.totalCount - resultData.failedCount) / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultData.avg = LATENCY_TEST_VALUE_ERROR;
|
||||
LOG(MODULE_NETWORK, resultData.errorMessage)
|
||||
}
|
||||
//
|
||||
//
|
||||
break;
|
||||
}
|
||||
case TCPING:
|
||||
default:
|
||||
{
|
||||
this->resultData = tcping::TestTCPLatency(host, port, count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Qv2ray::components::latency
|
30
src/components/latency/LatencyTestThread.hpp
Normal file
30
src/components/latency/LatencyTestThread.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "LatencyTest.hpp"
|
||||
|
||||
#include <QThread>
|
||||
namespace Qv2ray::components::latency
|
||||
{
|
||||
class LatencyTestThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LatencyTestThread(const QString &host, int port, Qv2rayLatencyTestingMethod, int count, QObject *parent = nullptr);
|
||||
LatencyTestResult GetResult() const
|
||||
{
|
||||
return resultData;
|
||||
}
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
LatencyTestResult resultData;
|
||||
QString host;
|
||||
int port;
|
||||
int count;
|
||||
Qv2rayLatencyTestingMethod method;
|
||||
|
||||
// static LatencyTestResult TestLatency_p(const ConnectionId &id, const int count);
|
||||
};
|
||||
|
||||
} // namespace Qv2ray::components::latency
|
@ -1,225 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#include <WS2tcpip.h>
|
||||
#include <WinSock2.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "QtConcurrent/QtConcurrent"
|
||||
#include "QvTCPing.hpp"
|
||||
#include "core/handler/ConfigHandler.hpp"
|
||||
|
||||
namespace Qv2ray::components::tcping
|
||||
{
|
||||
static int resolveHost(const std::string &host, int portnr, struct addrinfo **res);
|
||||
static int testLatency(struct addrinfo *addr, std::chrono::system_clock::time_point *start, std::chrono::system_clock::time_point *end);
|
||||
//
|
||||
QvTCPingHelper::QvTCPingHelper(const int defaultCount, QObject *parent) : QObject(parent)
|
||||
{
|
||||
count = defaultCount;
|
||||
}
|
||||
|
||||
void QvTCPingHelper::StopAllLatenceTest()
|
||||
{
|
||||
while (!pingWorkingThreads.isEmpty())
|
||||
{
|
||||
auto worker = pingWorkingThreads.dequeue();
|
||||
worker->future().cancel();
|
||||
worker->cancel();
|
||||
}
|
||||
}
|
||||
void QvTCPingHelper::TestLatency(const ConnectionId &id)
|
||||
{
|
||||
auto watcher = new QFutureWatcher<QvTCPingResultObject>(this);
|
||||
watcher->setFuture(QtConcurrent::run(&QvTCPingHelper::TestLatency_p, id, count));
|
||||
pingWorkingThreads.enqueue(watcher);
|
||||
//
|
||||
connect(watcher, &QFutureWatcher<QvTCPingResultObject>::finished, this, [=]() {
|
||||
auto result = watcher->result();
|
||||
this->pingWorkingThreads.removeOne(watcher);
|
||||
|
||||
if (!result.errorMessage.isEmpty())
|
||||
{
|
||||
LOG(MODULE_NETWORK, "Ping --> " + result.errorMessage)
|
||||
result.avg = QVTCPING_VALUE_ERROR;
|
||||
result.best = QVTCPING_VALUE_ERROR;
|
||||
result.worst = QVTCPING_VALUE_ERROR;
|
||||
}
|
||||
|
||||
emit this->OnLatencyTestCompleted(result);
|
||||
});
|
||||
}
|
||||
|
||||
QvTCPingResultObject QvTCPingHelper::TestLatency_p(const ConnectionId &id, const int count)
|
||||
{
|
||||
QvTCPingResultObject data;
|
||||
data.connectionId = id;
|
||||
|
||||
if (isExiting)
|
||||
return data;
|
||||
|
||||
auto [protocol, host, port] = GetConnectionInfo(id);
|
||||
Q_UNUSED(protocol)
|
||||
double successCount = 0, errorCount = 0;
|
||||
addrinfo *resolved;
|
||||
int errcode;
|
||||
|
||||
if ((errcode = resolveHost(host.toStdString(), port, &resolved)) != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
data.errorMessage = QString::fromStdWString(gai_strerror(errcode));
|
||||
#else
|
||||
data.errorMessage = gai_strerror(errcode);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
|
||||
bool noAddress = false;
|
||||
int currentCount = 0;
|
||||
|
||||
data.avg = 0;
|
||||
data.worst = 0;
|
||||
data.best = 0;
|
||||
|
||||
while (currentCount < count)
|
||||
{
|
||||
system_clock::time_point start;
|
||||
system_clock::time_point end;
|
||||
|
||||
if ((errcode = testLatency(resolved, &start, &end)) != 0)
|
||||
{
|
||||
if (errcode != -EADDRNOTAVAIL)
|
||||
{
|
||||
LOG(MODULE_NETWORK, "error connecting to host: " + host + ":" + QSTRN(port) + " " + strerror(-errcode))
|
||||
errorCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (noAddress)
|
||||
{
|
||||
LOG(MODULE_NETWORK, "no address error")
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(MODULE_NETWORK, "error connecting to host: " + QSTRN(-errcode) + " " + strerror(-errcode))
|
||||
}
|
||||
|
||||
noAddress = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
noAddress = false;
|
||||
successCount++;
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
uint ms = milliseconds.count();
|
||||
data.avg += ms;
|
||||
data.worst = min(data.worst, ms);
|
||||
data.best = max(data.best, ms);
|
||||
|
||||
if (ms > 1000)
|
||||
{
|
||||
LOG(MODULE_NETWORK, "Stop the test on the first long connect()")
|
||||
break; /* Stop the test on the first long connect() */
|
||||
}
|
||||
}
|
||||
|
||||
currentCount++;
|
||||
QThread::msleep(500);
|
||||
}
|
||||
|
||||
data.avg = data.avg / successCount;
|
||||
freeaddrinfo(resolved);
|
||||
data.avg = min(data.avg, QVTCPING_VALUE_ERROR);
|
||||
data.worst = min(data.worst, QVTCPING_VALUE_ERROR);
|
||||
data.best = min(data.best, QVTCPING_VALUE_ERROR);
|
||||
return data;
|
||||
}
|
||||
|
||||
int resolveHost(const string &host, int port, addrinfo **res)
|
||||
{
|
||||
if (isExiting)
|
||||
return 0;
|
||||
|
||||
addrinfo hints;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(0x0202, &wsadata);
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
#else
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
#endif
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
return getaddrinfo(host.c_str(), to_string(port).c_str(), &hints, res);
|
||||
}
|
||||
|
||||
int testLatency(struct addrinfo *addr, std::chrono::system_clock::time_point *start, std::chrono::system_clock::time_point *end)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SOCKET fd;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
const int on = 1;
|
||||
/* int flags; */
|
||||
int rv = 0;
|
||||
|
||||
/* try to connect for each of the entries: */
|
||||
while (addr != nullptr)
|
||||
{
|
||||
if (isExiting)
|
||||
return 0;
|
||||
|
||||
/* create socket */
|
||||
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
goto next_addr0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Windows needs special conversion.
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) < 0)
|
||||
#else
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||
#endif
|
||||
{
|
||||
goto next_addr1;
|
||||
}
|
||||
|
||||
*start = system_clock::now();
|
||||
|
||||
/* connect to peer */
|
||||
// Qt has its own connect() function in QObject....
|
||||
// So we add "::" here
|
||||
if (::connect(fd, addr->ai_addr, addr->ai_addrlen) == 0)
|
||||
{
|
||||
*end = system_clock::now();
|
||||
#ifdef Q_OS_WIN
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_addr1:
|
||||
#ifdef _WIN32
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
next_addr0:
|
||||
addr = addr->ai_next;
|
||||
}
|
||||
|
||||
rv = rv ? rv : -errno;
|
||||
return rv;
|
||||
}
|
||||
} // namespace Qv2ray::core::tcping
|
@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
#include "core/CoreSafeTypes.hpp"
|
||||
|
||||
namespace Qv2ray::components::tcping
|
||||
{
|
||||
struct QvTCPingResultObject
|
||||
{
|
||||
ConnectionId connectionId = NullConnectionId;
|
||||
QString errorMessage;
|
||||
int total, succeed, failed;
|
||||
uint worst = QVTCPING_VALUE_ERROR, best = QVTCPING_VALUE_ERROR, avg = QVTCPING_VALUE_ERROR;
|
||||
};
|
||||
|
||||
class QvTCPingHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QvTCPingHelper(const int defaultCount = 5, QObject *parent = nullptr);
|
||||
void TestLatency(const ConnectionId &connectionId);
|
||||
void StopAllLatenceTest();
|
||||
signals:
|
||||
void OnLatencyTestCompleted(const QvTCPingResultObject &data);
|
||||
|
||||
private:
|
||||
static QvTCPingResultObject TestLatency_p(const ConnectionId &id, const int count);
|
||||
int count;
|
||||
QQueue<QFutureWatcher<QvTCPingResultObject> *> pingWorkingThreads;
|
||||
};
|
||||
} // namespace Qv2ray::components::tcping
|
||||
|
||||
using namespace Qv2ray::components::tcping;
|
364
src/components/latency/TCPing.cpp
Normal file
364
src/components/latency/TCPing.cpp
Normal file
@ -0,0 +1,364 @@
|
||||
#include "TCPing.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WS2tcpip.h>
|
||||
#include <WinSock2.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace Qv2ray::components::latency::tcping
|
||||
{
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
using qv_socket_t = SOCKET;
|
||||
struct TranslateWSAError{
|
||||
~TranslateWSAError(){
|
||||
errno = translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
int translate_sys_error(int sys_errno) {
|
||||
LOG(MODULE_NETWORK, "translate_sys_error:WSAGetLastError()==" + QSTRN(sys_errno))
|
||||
switch (sys_errno) {
|
||||
case ERROR_NOACCESS: return EACCES;
|
||||
case WSAEACCES: return EACCES;
|
||||
case ERROR_ELEVATION_REQUIRED: return EACCES;
|
||||
case ERROR_CANT_ACCESS_FILE: return EACCES;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return EADDRINUSE;
|
||||
case WSAEADDRINUSE: return EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
|
||||
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
|
||||
case WSAEWOULDBLOCK: return EAGAIN;
|
||||
case WSAEALREADY: return EALREADY;
|
||||
case ERROR_INVALID_FLAGS: return EBADF;
|
||||
case ERROR_INVALID_HANDLE: return EBADF;
|
||||
case ERROR_LOCK_VIOLATION: return EBUSY;
|
||||
case ERROR_PIPE_BUSY: return EBUSY;
|
||||
case ERROR_SHARING_VIOLATION: return EBUSY;
|
||||
case ERROR_OPERATION_ABORTED: return ECANCELED;
|
||||
case WSAEINTR: return ECANCELED;
|
||||
/*case ERROR_NO_UNICODE_TRANSLATION: return ECHARSET;*/
|
||||
case ERROR_CONNECTION_ABORTED: return ECONNABORTED;
|
||||
case WSAECONNABORTED: return ECONNABORTED;
|
||||
case ERROR_CONNECTION_REFUSED: return ECONNREFUSED;
|
||||
case WSAECONNREFUSED: return ECONNREFUSED;
|
||||
case ERROR_NETNAME_DELETED: return ECONNRESET;
|
||||
case WSAECONNRESET: return ECONNRESET;
|
||||
case ERROR_ALREADY_EXISTS: return EEXIST;
|
||||
case ERROR_FILE_EXISTS: return EEXIST;
|
||||
case ERROR_BUFFER_OVERFLOW: return EFAULT;
|
||||
case WSAEFAULT: return EFAULT;
|
||||
case ERROR_HOST_UNREACHABLE: return EHOSTUNREACH;
|
||||
case WSAEHOSTUNREACH: return EHOSTUNREACH;
|
||||
case ERROR_INSUFFICIENT_BUFFER: return EINVAL;
|
||||
case ERROR_INVALID_DATA: return EINVAL;
|
||||
case ERROR_INVALID_PARAMETER: return EINVAL;
|
||||
case ERROR_SYMLINK_NOT_SUPPORTED: return EINVAL;
|
||||
case WSAEINVAL: return EINVAL;
|
||||
case WSAEPFNOSUPPORT: return EINVAL;
|
||||
case WSAESOCKTNOSUPPORT: return EINVAL;
|
||||
case ERROR_BEGINNING_OF_MEDIA: return EIO;
|
||||
case ERROR_BUS_RESET: return EIO;
|
||||
case ERROR_CRC: return EIO;
|
||||
case ERROR_DEVICE_DOOR_OPEN: return EIO;
|
||||
case ERROR_DEVICE_REQUIRES_CLEANING: return EIO;
|
||||
case ERROR_DISK_CORRUPT: return EIO;
|
||||
case ERROR_EOM_OVERFLOW: return EIO;
|
||||
case ERROR_FILEMARK_DETECTED: return EIO;
|
||||
case ERROR_GEN_FAILURE: return EIO;
|
||||
case ERROR_INVALID_BLOCK_LENGTH: return EIO;
|
||||
case ERROR_IO_DEVICE: return EIO;
|
||||
case ERROR_NO_DATA_DETECTED: return EIO;
|
||||
case ERROR_NO_SIGNAL_SENT: return EIO;
|
||||
case ERROR_OPEN_FAILED: return EIO;
|
||||
case ERROR_SETMARK_DETECTED: return EIO;
|
||||
case ERROR_SIGNAL_REFUSED: return EIO;
|
||||
case WSAEISCONN: return EISCONN;
|
||||
case ERROR_CANT_RESOLVE_FILENAME: return ELOOP;
|
||||
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
|
||||
case WSAEMFILE: return EMFILE;
|
||||
case WSAEMSGSIZE: return EMSGSIZE;
|
||||
case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
|
||||
case ERROR_NETWORK_UNREACHABLE: return ENETUNREACH;
|
||||
case WSAENETUNREACH: return ENETUNREACH;
|
||||
case WSAENOBUFS: return ENOBUFS;
|
||||
case ERROR_BAD_PATHNAME: return ENOENT;
|
||||
case ERROR_DIRECTORY: return ENOENT;
|
||||
case ERROR_ENVVAR_NOT_FOUND: return ENOENT;
|
||||
case ERROR_FILE_NOT_FOUND: return ENOENT;
|
||||
case ERROR_INVALID_NAME: return ENOENT;
|
||||
case ERROR_INVALID_DRIVE: return ENOENT;
|
||||
case ERROR_INVALID_REPARSE_DATA: return ENOENT;
|
||||
case ERROR_MOD_NOT_FOUND: return ENOENT;
|
||||
case ERROR_PATH_NOT_FOUND: return ENOENT;
|
||||
case WSAHOST_NOT_FOUND: return ENOENT;
|
||||
case WSANO_DATA: return ENOENT;
|
||||
case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM;
|
||||
case ERROR_OUTOFMEMORY: return ENOMEM;
|
||||
case ERROR_CANNOT_MAKE: return ENOSPC;
|
||||
case ERROR_DISK_FULL: return ENOSPC;
|
||||
case ERROR_EA_TABLE_FULL: return ENOSPC;
|
||||
case ERROR_END_OF_MEDIA: return ENOSPC;
|
||||
case ERROR_HANDLE_DISK_FULL: return ENOSPC;
|
||||
case ERROR_NOT_CONNECTED: return ENOTCONN;
|
||||
case WSAENOTCONN: return ENOTCONN;
|
||||
case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY;
|
||||
case WSAENOTSOCK: return ENOTSOCK;
|
||||
case ERROR_NOT_SUPPORTED: return ENOTSUP;
|
||||
case ERROR_BROKEN_PIPE: return EOF;
|
||||
case ERROR_ACCESS_DENIED: return EPERM;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: return EPERM;
|
||||
case ERROR_BAD_PIPE: return EPIPE;
|
||||
case ERROR_NO_DATA: return EPIPE;
|
||||
case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
|
||||
case WSAESHUTDOWN: return EPIPE;
|
||||
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
|
||||
case ERROR_WRITE_PROTECT: return EROFS;
|
||||
case ERROR_SEM_TIMEOUT: return ETIMEDOUT;
|
||||
case WSAETIMEDOUT: return ETIMEDOUT;
|
||||
case ERROR_NOT_SAME_DEVICE: return EXDEV;
|
||||
case ERROR_INVALID_FUNCTION: return EISDIR;
|
||||
case ERROR_META_EXPANSION_TOO_LONG: return E2BIG;
|
||||
default: return EIO;/*unknown*/
|
||||
}
|
||||
}
|
||||
};
|
||||
#else
|
||||
using qv_socket_t = int;
|
||||
#endif
|
||||
|
||||
inline int setnonblocking(qv_socket_t sockno, int &opt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG block = 1;
|
||||
if (ioctlsocket(sockno, FIONBIO, &block) == SOCKET_ERROR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if ((opt = fcntl(sockno, F_GETFL, NULL)) < 0)
|
||||
{
|
||||
// get socket flags
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(sockno, F_SETFL, opt | O_NONBLOCK) < 0)
|
||||
{
|
||||
// set socket non-blocking
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int setblocking(qv_socket_t sockno, int &opt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG block = 0;
|
||||
if (ioctlsocket(sockno, FIONBIO, &block) == SOCKET_ERROR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (fcntl(sockno, F_SETFL, opt) < 0)
|
||||
{
|
||||
// reset socket flags
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connect_wait(qv_socket_t sockno, struct sockaddr *addr, size_t addrlen, int timeout_sec = 5)
|
||||
{
|
||||
int res;
|
||||
int opt;
|
||||
timeval tv = { 0, 0 };
|
||||
#ifdef _WIN32
|
||||
TranslateWSAError _translateWSAError_;
|
||||
#endif
|
||||
tv.tv_sec = timeout_sec;
|
||||
tv.tv_usec = 0;
|
||||
if ((res = setnonblocking(sockno, opt)) != 0)
|
||||
return -1;
|
||||
if ((res = ::connect(sockno, addr, addrlen)) < 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
{
|
||||
#else
|
||||
if (errno == EINPROGRESS)
|
||||
{
|
||||
#endif
|
||||
// connecting
|
||||
fd_set wait_set;
|
||||
FD_ZERO(&wait_set);
|
||||
FD_SET(sockno, &wait_set);
|
||||
res = select(sockno + 1, NULL, &wait_set, NULL, &tv);
|
||||
}
|
||||
}
|
||||
else
|
||||
// connect immediately
|
||||
res = 1;
|
||||
|
||||
if (setblocking(sockno, opt) != 0)
|
||||
return -1;
|
||||
|
||||
if (res < 0)
|
||||
// an error occured
|
||||
return -1;
|
||||
else if (res == 0)
|
||||
{
|
||||
// timeout
|
||||
errno = ETIMEDOUT;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
socklen_t len = sizeof(opt);
|
||||
if (getsockopt(sockno, SOL_SOCKET, SO_ERROR, (char *) (&opt), &len) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resolveHost(const QString &host, int port, addrinfo **res)
|
||||
{
|
||||
addrinfo hints;
|
||||
#ifdef Q_OS_WIN
|
||||
WSADATA wsadata;
|
||||
WSAStartup(0x0202, &wsadata);
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
#else
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
#endif
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
return getaddrinfo(host.toStdString().c_str(), std::to_string(port).c_str(), &hints, res);
|
||||
}
|
||||
|
||||
int testLatency(struct addrinfo *addr, system_clock::time_point *start, system_clock::time_point *end)
|
||||
{
|
||||
qv_socket_t fd;
|
||||
|
||||
const int on = 1;
|
||||
|
||||
/* try to connect for each of the entries: */
|
||||
while (addr != nullptr)
|
||||
{
|
||||
if (isExiting)
|
||||
return 0;
|
||||
|
||||
// create socket
|
||||
if (!(fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)))
|
||||
{
|
||||
goto next_addr0;
|
||||
}
|
||||
|
||||
// Windows needs special conversion.
|
||||
#ifdef _WIN32
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) < 0)
|
||||
#else
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||
#endif
|
||||
goto next_addr1;
|
||||
*start = system_clock::now();
|
||||
if (connect_wait(fd, addr->ai_addr, addr->ai_addrlen) == 0)
|
||||
{
|
||||
*end = system_clock::now();
|
||||
#ifdef Q_OS_WIN
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_addr1:
|
||||
#ifdef _WIN32
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
next_addr0:
|
||||
addr = addr->ai_next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
LatencyTestResult TestTCPLatency(const QString &host, int port, int testCount)
|
||||
{
|
||||
LatencyTestResult data;
|
||||
int successCount = 0;
|
||||
addrinfo *resolved;
|
||||
int errcode;
|
||||
|
||||
if ((errcode = resolveHost(host, port, &resolved)) != 0)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
data.errorMessage = QString::fromStdWString(gai_strerror(errcode));
|
||||
#else
|
||||
data.errorMessage = gai_strerror(errcode);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
|
||||
int currentCount = 0;
|
||||
|
||||
data.avg = 0;
|
||||
data.worst = 0;
|
||||
data.best = 0;
|
||||
|
||||
while (currentCount < testCount)
|
||||
{
|
||||
system_clock::time_point start;
|
||||
system_clock::time_point end;
|
||||
|
||||
if ((errcode = testLatency(resolved, &start, &end)) != 0)
|
||||
{
|
||||
LOG(MODULE_NETWORK, "error connecting to host: " + host + ":" + QSTRN(port) + " " + strerror(errno))
|
||||
}
|
||||
else
|
||||
{
|
||||
successCount++;
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
long ms = milliseconds.count();
|
||||
data.avg += ms;
|
||||
#ifdef Q_OS_WIN
|
||||
// Is it Windows?
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
data.worst = std::min(data.worst, ms);
|
||||
data.best = std::max(data.best, ms);
|
||||
|
||||
if (ms > 1000)
|
||||
{
|
||||
LOG(MODULE_NETWORK, "Stop the test on the first long connect()")
|
||||
break; /* Stop the test on the first long connect() */
|
||||
}
|
||||
}
|
||||
|
||||
currentCount++;
|
||||
QThread::msleep(200);
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
if (successCount > 0)
|
||||
{
|
||||
data.avg = data.avg / successCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.avg = LATENCY_TEST_VALUE_ERROR;
|
||||
data.worst = LATENCY_TEST_VALUE_ERROR;
|
||||
data.best = LATENCY_TEST_VALUE_ERROR;
|
||||
data.errorMessage = QObject::tr("Timeout");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
} // namespace Qv2ray::components::latency::tcping
|
7
src/components/latency/TCPing.hpp
Normal file
7
src/components/latency/TCPing.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "LatencyTest.hpp"
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
namespace Qv2ray::components::latency::tcping
|
||||
{
|
||||
LatencyTestResult TestTCPLatency(const QString &host, int port, int testCount);
|
||||
} // namespace Qv2ray::components::latency::tcping
|
156
src/components/latency/unix/ICMPPing.cpp
Normal file
156
src/components/latency/unix/ICMPPing.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/* Author: Maciek Muszkowski
|
||||
*
|
||||
* This is a simple ping implementation for Linux.
|
||||
* It will work ONLY on kernels 3.x+ and you need
|
||||
* to set allowed groups in /proc/sys/net/ipv4/ping_group_range */
|
||||
#include "ICMPPing.hpp"
|
||||
|
||||
#include <QObject>
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <unistd.h>
|
||||
//
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <resolv.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef Q_OS_MAC
|
||||
#define SOL_IP 0
|
||||
#endif
|
||||
|
||||
namespace Qv2ray::components::latency::icmping
|
||||
{
|
||||
/// 1s complementary checksum
|
||||
uint16_t ping_checksum(const char *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint64_t sum = 0;
|
||||
|
||||
for (i = 0; i < size; i += 2)
|
||||
{
|
||||
sum += *(uint16_t *) buf;
|
||||
buf += 2;
|
||||
}
|
||||
if (size - i > 0)
|
||||
{
|
||||
sum += *(uint8_t *) buf;
|
||||
}
|
||||
|
||||
while ((sum >> 16) != 0)
|
||||
{
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
|
||||
return (uint16_t) ~sum;
|
||||
}
|
||||
void ICMPPing::deinit()
|
||||
{
|
||||
if (socketId >= 0)
|
||||
{
|
||||
close(socketId);
|
||||
socketId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
ICMPPing::ICMPPing(int ttl)
|
||||
{
|
||||
auto timeout_s = 5;
|
||||
// create socket
|
||||
if ( //((sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) &&
|
||||
((socketId = socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP)) < 0))
|
||||
{
|
||||
initErrorMessage = "EPING_SOCK: " + QObject::tr("Socket creation failed");
|
||||
return;
|
||||
}
|
||||
// set TTL
|
||||
if (setsockopt(socketId, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) != 0)
|
||||
{
|
||||
deinit();
|
||||
initErrorMessage = "EPING_TTL: " + QObject::tr("Failed to setup TTL value");
|
||||
return;
|
||||
}
|
||||
|
||||
// set timeout in secs (do not use secs - BUGGY)
|
||||
timeval timeout;
|
||||
timeout.tv_sec = timeout_s;
|
||||
timeout.tv_usec = 0;
|
||||
if (setsockopt(socketId, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)) != 0)
|
||||
{
|
||||
deinit();
|
||||
initErrorMessage = "EPING_SETTO: " + QObject::tr("Setting timeout failed");
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/// @return value < 0 on error, response time in ms on success
|
||||
QPair<int64_t, QString> ICMPPing::ping(const QString &address)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
return { 0, initErrorMessage };
|
||||
}
|
||||
timeval start, end;
|
||||
socklen_t slen;
|
||||
// not initialized
|
||||
if (socketId < 0)
|
||||
return { 0, "EPING_SOCK:" + QObject::tr("Socket creation failed") };
|
||||
|
||||
// resolve hostname
|
||||
hostent *resolvedAddress = gethostbyname(address.toStdString().c_str());
|
||||
if (!resolvedAddress)
|
||||
return { 0, "EPING_HOST: " + QObject::tr("Unresolvable hostname") };
|
||||
|
||||
// set IP address to ping
|
||||
sockaddr_in targetAddress;
|
||||
memset(&targetAddress, 0, sizeof(targetAddress));
|
||||
targetAddress.sin_family = resolvedAddress->h_addrtype;
|
||||
targetAddress.sin_port = 0;
|
||||
memcpy(&targetAddress.sin_addr, resolvedAddress->h_addr, resolvedAddress->h_length);
|
||||
|
||||
// prepare echo request packet
|
||||
icmp _icmp_request;
|
||||
memset(&_icmp_request, 0, sizeof(_icmp_request));
|
||||
_icmp_request.icmp_type = ICMP_ECHO;
|
||||
_icmp_request.icmp_hun.ih_idseq.icd_id = 0; // SOCK_DGRAM & 0 => id will be set by kernel
|
||||
unsigned short sent_seq;
|
||||
_icmp_request.icmp_hun.ih_idseq.icd_seq = sent_seq = seq++;
|
||||
_icmp_request.icmp_cksum = ping_checksum(reinterpret_cast<char *>(&_icmp_request), sizeof(_icmp_request));
|
||||
|
||||
// send echo request
|
||||
gettimeofday(&start, NULL);
|
||||
if (sendto(socketId, &_icmp_request, sizeof(icmp), 0, (struct sockaddr *) &targetAddress, sizeof(targetAddress)) <= 0)
|
||||
return { 0, "EPING_SEND: " + QObject::tr("Sending echo request failed") };
|
||||
|
||||
// receive response (if any)
|
||||
sockaddr_in remove_addr;
|
||||
slen = sizeof(remove_addr);
|
||||
int rlen;
|
||||
icmp resp;
|
||||
while ((rlen = recvfrom(socketId, &resp, sizeof(icmp), 0, (struct sockaddr *) &remove_addr, &slen)) > 0)
|
||||
{
|
||||
gettimeofday(&end, NULL);
|
||||
|
||||
// skip malformed
|
||||
if (rlen != sizeof(icmp))
|
||||
continue;
|
||||
|
||||
// skip the ones we didn't send
|
||||
if (resp.icmp_hun.ih_idseq.icd_seq != sent_seq)
|
||||
continue;
|
||||
|
||||
switch (resp.icmp_type)
|
||||
{
|
||||
case ICMP_ECHOREPLY: return { 1000000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec), {} };
|
||||
case ICMP_UNREACH: return { 0, "EPING_DST: " + QObject::tr("Destination unreachable") };
|
||||
case ICMP_TIMXCEED: return { 0, "EPING_TIME: " + QObject::tr("Timeout") };
|
||||
default: return { 0, "EPING_UNK: " + QObject::tr("Unknown error") };
|
||||
}
|
||||
}
|
||||
return { 0, "EPING_TIME: " + QObject::tr("Timeout") };
|
||||
}
|
||||
} // namespace Qv2ray::components::latency::icmping
|
||||
#endif
|
28
src/components/latency/unix/ICMPPing.hpp
Normal file
28
src/components/latency/unix/ICMPPing.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
namespace Qv2ray::components::latency::icmping
|
||||
{
|
||||
class ICMPPing
|
||||
{
|
||||
public:
|
||||
explicit ICMPPing(int ttl);
|
||||
~ICMPPing()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
QPair<int64_t, QString> ping(const QString &address);
|
||||
|
||||
private:
|
||||
void deinit();
|
||||
// number incremented with every echo request packet send
|
||||
unsigned short seq = 1;
|
||||
// socket
|
||||
int socketId = -1;
|
||||
bool initialized = false;
|
||||
QString initErrorMessage;
|
||||
};
|
||||
} // namespace Qv2ray::components::latency::icmping
|
||||
#endif
|
87
src/components/latency/win/ICMPPing.cpp
Normal file
87
src/components/latency/win/ICMPPing.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "ICMPPing.hpp"
|
||||
#ifdef Q_OS_WIN
|
||||
//
|
||||
#include <WS2tcpip.h>
|
||||
//
|
||||
#include <Windows.h>
|
||||
//
|
||||
#include <iphlpapi.h>
|
||||
//
|
||||
#include <IcmpAPI.h>
|
||||
//
|
||||
#include <QEventLoop>
|
||||
#include <QHostInfo>
|
||||
namespace Qv2ray::components::latency::icmping
|
||||
{
|
||||
ICMPPing::ICMPPing(uint64_t timeout)
|
||||
{
|
||||
|
||||
// remember the timeout
|
||||
// UNUSED
|
||||
this->timeout = timeout;
|
||||
}
|
||||
|
||||
ICMPPing ::~ICMPPing()
|
||||
{
|
||||
}
|
||||
QPair<long, QString> ICMPPing::ping(const QString &ipAddr)
|
||||
{
|
||||
HANDLE hIcmpFile;
|
||||
// create icmp handle
|
||||
if ((hIcmpFile = IcmpCreateFile()) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw "IcmpCreateFile failed";
|
||||
}
|
||||
QList<QHostAddress> addresses;
|
||||
{
|
||||
QEventLoop loop;
|
||||
QHostInfo::fromName(ipAddr).lookupHost(ipAddr, &loop, [&](const QHostInfo &h) {
|
||||
for (const auto &addr : h.addresses())
|
||||
{
|
||||
if (addr.protocol() == QAbstractSocket::IPv4Protocol)
|
||||
{
|
||||
addresses << addr;
|
||||
}
|
||||
}
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
}
|
||||
if (addresses.isEmpty())
|
||||
{
|
||||
return { 0, QObject::tr("DNS lookup failed.") };
|
||||
}
|
||||
// Parse the destination IP address.
|
||||
IN_ADDR dest_ip{};
|
||||
if (1 != InetPtonA(AF_INET, addresses.first().toString().toStdString().c_str(), &dest_ip))
|
||||
{
|
||||
return { 255, "Cannot convert IP address: " + addresses.first().toString() };
|
||||
}
|
||||
|
||||
// Payload to send.
|
||||
constexpr WORD payload_size = 1;
|
||||
unsigned char payload[payload_size]{ 42 };
|
||||
|
||||
// Reply buffer for exactly 1 echo reply, payload data, and 8 bytes for ICMP error message.
|
||||
constexpr DWORD reply_buf_size = sizeof(ICMP_ECHO_REPLY) + payload_size + 8;
|
||||
unsigned char reply_buf[reply_buf_size]{};
|
||||
|
||||
// Make the echo request.
|
||||
DWORD reply_count = IcmpSendEcho(hIcmpFile, dest_ip.S_un.S_addr, payload, payload_size, NULL, reply_buf, reply_buf_size, 10000);
|
||||
|
||||
// Return value of 0 indicates failure, try to get error info.
|
||||
if (reply_count == 0)
|
||||
{
|
||||
auto e = GetLastError();
|
||||
DWORD buf_size = 1000;
|
||||
TCHAR buf[1000];
|
||||
GetIpErrorString(e, buf, &buf_size);
|
||||
return { 255, "IcmpSendEcho returned error (" + QString::fromStdWString(buf) + ")" };
|
||||
}
|
||||
// release the handle on destruction
|
||||
IcmpCloseHandle(hIcmpFile);
|
||||
const ICMP_ECHO_REPLY *r = (const ICMP_ECHO_REPLY *) reply_buf;
|
||||
return QPair<long, QString>(r->RoundTripTime * 1000, QString{});
|
||||
}
|
||||
} // namespace Qv2ray::components::latency::icmping
|
||||
#endif
|
35
src/components/latency/win/ICMPPing.hpp
Normal file
35
src/components/latency/win/ICMPPing.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* ICMPPinger - An Implementation of ICMPPing on Windows Platform
|
||||
* Required Windows Version: 2000 / XP / 7 / Vista+
|
||||
* License: WTFPL
|
||||
*/
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace Qv2ray::components::latency::icmping
|
||||
{
|
||||
class ICMPPing
|
||||
{
|
||||
public:
|
||||
ICMPPing(uint64_t timeout = DEFAULT_TIMEOUT);
|
||||
~ICMPPing();
|
||||
|
||||
public:
|
||||
static const uint64_t DEFAULT_TIMEOUT = 10000U;
|
||||
|
||||
public:
|
||||
QPair<long, QString> ping(const QString &ipAddr);
|
||||
|
||||
private:
|
||||
uint64_t timeout = DEFAULT_TIMEOUT;
|
||||
};
|
||||
} // namespace Qv2ray::components::latency::icmping
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
#include "ICMPPinger.hpp"
|
||||
#if 0
|
||||
|
||||
ICMPPinger::ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT)
|
||||
{
|
||||
// create icmp handle
|
||||
if ((this->hIcmpFile = IcmpCreateFile()) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw "IcmpCreateFile failed";
|
||||
}
|
||||
|
||||
// remember the timeout
|
||||
this->timeout = timeout;
|
||||
}
|
||||
|
||||
ICMPPinger::~ICMPPinger()
|
||||
{
|
||||
// release the handle on destruction
|
||||
IcmpCloseHandle(this->hIcmpFile);
|
||||
}
|
||||
|
||||
std::pair<std::optional<UINT64>, std::optional<std::string>> ICMPPinger::ping(const std::string &ipAddr)
|
||||
{
|
||||
// convert network address
|
||||
const auto addr = inet_addr(ipAddr.c_str());
|
||||
if (addr == INADDR_NONE)
|
||||
{
|
||||
return std::pair(std::nullopt, "invalid ip address: " + ipAddr);
|
||||
}
|
||||
|
||||
// request buffer
|
||||
const static char bufRequest[] = "echo test";
|
||||
|
||||
// response buffer
|
||||
const auto responseSize = sizeof(ICMP_ECHO_REPLY) + sizeof(bufRequest);
|
||||
const std::unique_ptr<char> bufRecv(new (char[responseSize]));
|
||||
|
||||
// send echo
|
||||
auto ret = IcmpSendEcho(this->hIcmpFile, addr, (LPVOID) bufRequest, sizeof(bufRequest), NULL, bufRecv.get(), responseSize, this->timeout);
|
||||
|
||||
// ret == 0: failed
|
||||
if (ret == 0)
|
||||
{
|
||||
return std::pair(std::nullopt, "IcmpSendEcho returned error");
|
||||
}
|
||||
|
||||
// read round-trip time
|
||||
PICMP_ECHO_REPLY pReply = (PICMP_ECHO_REPLY) bufRecv.get();
|
||||
return std::pair(pReply->RoundTripTime, std::nullopt);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
#include <optional>
|
||||
#if 0
|
||||
/**
|
||||
* ICMPPinger - An Implementation of ICMPPing on Windows Platform
|
||||
* Required Windows Version: 2000 / XP / 7 / Vista+
|
||||
* License: WTFPL
|
||||
*/
|
||||
|
||||
#include <icmpapi.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <winsock2.h>
|
||||
|
||||
class ICMPPinger
|
||||
{
|
||||
public:
|
||||
ICMPPinger(UINT64 timeout = DEFAULT_TIMEOUT);
|
||||
~ICMPPinger();
|
||||
|
||||
public:
|
||||
static const UINT64 DEFAULT_TIMEOUT = 10000U;
|
||||
|
||||
public:
|
||||
std::pair<std::optional<UINT64>, std::optional<std::string>> ping(const std::string &ipAddr);
|
||||
|
||||
private:
|
||||
HANDLE hIcmpFile;
|
||||
UINT64 timeout = DEFAULT_TIMEOUT;
|
||||
};
|
||||
#endif
|
216
src/components/ntp/QvNTPClient.cpp
Normal file
216
src/components/ntp/QvNTPClient.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/* This file from part of QNtp, a library that implements NTP protocol.
|
||||
*
|
||||
* Copyright (C) 2011 Alexander Fokin <apfokin@gmail.com>
|
||||
*
|
||||
* QNtp is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* QNtp is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with QNtp. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "QvNTPClient.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Qv2ray::components::ntp
|
||||
{
|
||||
|
||||
NtpTimestamp NtpTimestamp::fromDateTime(const QDateTime &dateTime)
|
||||
{
|
||||
qint64 ntpMSecs = dateTime.toMSecsSinceEpoch() - january_1_1900;
|
||||
|
||||
quint32 seconds = ntpMSecs / 1000;
|
||||
quint32 fraction = 0x100000000ll * (ntpMSecs % 1000) / 1000;
|
||||
|
||||
NtpTimestamp result;
|
||||
result.seconds = qToBigEndian(seconds);
|
||||
result.fraction = qToBigEndian(fraction);
|
||||
return result;
|
||||
}
|
||||
|
||||
QDateTime NtpTimestamp::toDateTime(const NtpTimestamp &ntpTime)
|
||||
{
|
||||
/* Convert to local-endian. */
|
||||
quint32 seconds = qFromBigEndian(ntpTime.seconds);
|
||||
quint32 fraction = qFromBigEndian(ntpTime.fraction);
|
||||
|
||||
/* Convert NTP timestamp to number of milliseconds passed since Jan 1 1900. */
|
||||
qint64 ntpMSecs = seconds * 1000ll + fraction * 1000ll / 0x100000000ll;
|
||||
|
||||
/* Construct Qt date time. */
|
||||
return QDateTime::fromMSecsSinceEpoch(ntpMSecs + january_1_1900);
|
||||
}
|
||||
|
||||
NtpReply::NtpReply() : d(new NtpReplyPrivate())
|
||||
{
|
||||
/* We don't use shared null because NtpReplyPrivate isn't a POD type and
|
||||
* allocation overhead is negligible here. */
|
||||
memset(&d->packet, 0, sizeof(d->packet));
|
||||
}
|
||||
|
||||
NtpReply::NtpReply(NtpReplyPrivate *dd) : d(dd)
|
||||
{
|
||||
Q_ASSERT(dd != NULL);
|
||||
}
|
||||
|
||||
NtpReply::NtpReply(const NtpReply &other) : d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
NtpReply::~NtpReply()
|
||||
{
|
||||
}
|
||||
|
||||
NtpReply &NtpReply::operator=(const NtpReply &other)
|
||||
{
|
||||
d = other.d;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NtpLeapIndicator NtpReply::leapIndicator() const
|
||||
{
|
||||
return static_cast<NtpLeapIndicator>(d->packet.basic.flags.leapIndicator);
|
||||
}
|
||||
|
||||
quint8 NtpReply::versionNumber() const
|
||||
{
|
||||
return d->packet.basic.flags.versionNumber;
|
||||
}
|
||||
|
||||
NtpMode NtpReply::mode() const
|
||||
{
|
||||
return static_cast<NtpMode>(d->packet.basic.flags.mode);
|
||||
}
|
||||
|
||||
quint8 NtpReply::stratum() const
|
||||
{
|
||||
return d->packet.basic.stratum;
|
||||
}
|
||||
|
||||
qreal NtpReply::pollInterval() const
|
||||
{
|
||||
return std::pow(static_cast<qreal>(2), static_cast<qreal>(d->packet.basic.poll));
|
||||
}
|
||||
|
||||
qreal NtpReply::precision() const
|
||||
{
|
||||
return std::pow(static_cast<qreal>(2), static_cast<qreal>(d->packet.basic.precision));
|
||||
}
|
||||
|
||||
QDateTime NtpReply::referenceTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.referenceTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::originTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.originateTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::receiveTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.receiveTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::transmitTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.transmitTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::destinationTime() const
|
||||
{
|
||||
return d->destinationTime;
|
||||
}
|
||||
|
||||
qint64 NtpReply::roundTripDelay() const
|
||||
{
|
||||
return originTime().msecsTo(destinationTime()) - receiveTime().msecsTo(transmitTime());
|
||||
}
|
||||
|
||||
qint64 NtpReply::localClockOffset() const
|
||||
{
|
||||
return (originTime().msecsTo(receiveTime()) + destinationTime().msecsTo(transmitTime())) / 2;
|
||||
}
|
||||
|
||||
bool NtpReply::isNull() const
|
||||
{
|
||||
return d->destinationTime.isNull();
|
||||
}
|
||||
|
||||
NtpClient::NtpClient(QObject *parent) : QObject(parent)
|
||||
{
|
||||
init(QHostAddress::Any, 0);
|
||||
}
|
||||
|
||||
NtpClient::NtpClient(const QHostAddress &bindAddress, quint16 bindPort, QObject *parent) : QObject(parent)
|
||||
{
|
||||
init(bindAddress, bindPort);
|
||||
}
|
||||
|
||||
void NtpClient::init(const QHostAddress &bindAddress, quint16 bindPort)
|
||||
{
|
||||
mSocket = new QUdpSocket(this);
|
||||
mSocket->bind(bindAddress, bindPort);
|
||||
|
||||
connect(mSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
||||
}
|
||||
|
||||
NtpClient::~NtpClient()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool NtpClient::sendRequest(const QHostAddress &address, quint16 port)
|
||||
{
|
||||
if (mSocket->state() != QAbstractSocket::BoundState)
|
||||
return false;
|
||||
|
||||
/* Initialize the NTP packet. */
|
||||
NtpPacket packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
packet.flags.mode = ClientMode;
|
||||
packet.flags.versionNumber = 4;
|
||||
packet.transmitTimestamp = NtpTimestamp::fromDateTime(QDateTime::currentDateTimeUtc());
|
||||
|
||||
/* Send it. */
|
||||
if (mSocket->writeDatagram(reinterpret_cast<const char *>(&packet), sizeof(packet), address, port) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NtpClient::readPendingDatagrams()
|
||||
{
|
||||
while (mSocket->hasPendingDatagrams())
|
||||
{
|
||||
NtpFullPacket packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
QHostAddress address;
|
||||
quint16 port;
|
||||
|
||||
if (mSocket->readDatagram(reinterpret_cast<char *>(&packet), sizeof(packet), &address, &port) < (qint64) sizeof(NtpPacket))
|
||||
continue;
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
/* Prepare reply. */
|
||||
NtpReplyPrivate *replyPrivate = new NtpReplyPrivate();
|
||||
replyPrivate->packet = packet;
|
||||
replyPrivate->destinationTime = now;
|
||||
NtpReply reply(replyPrivate);
|
||||
|
||||
/* Notify. */
|
||||
Q_EMIT replyReceived(address, port, reply);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Qv2ray::components::ntp
|
165
src/components/ntp/QvNTPClient.hpp
Normal file
165
src/components/ntp/QvNTPClient.hpp
Normal file
@ -0,0 +1,165 @@
|
||||
/* This file from part of QNtp, a library that implements NTP protocol.
|
||||
*
|
||||
* Copyright (C) 2011 Alexander Fokin <apfokin@gmail.com>
|
||||
*
|
||||
* QNtp is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* QNtp is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with QNtp. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHostAddress>
|
||||
#include <QObject>
|
||||
#include <QUdpSocket>
|
||||
#include <QtEndian>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace Qv2ray::components::ntp
|
||||
{
|
||||
const qint64 january_1_1900 = -2208988800000ll;
|
||||
|
||||
enum NtpLeapIndicator
|
||||
{
|
||||
NoWarning = 0, /**< No warning. */
|
||||
LastMinute61Warning = 1, /**< Last minute has 61 seconds. */
|
||||
LastMinute59Warning = 2, /**< Last minute has 59 seconds. */
|
||||
UnsynchronizedWarning = 3, /**< Alarm condition (clock not synchronized). */
|
||||
};
|
||||
|
||||
enum NtpMode
|
||||
{
|
||||
ReservedMode = 0, /**< Reserved. */
|
||||
SymmetricActiveMode = 1, /**< Symmetric active. */
|
||||
SymmetricPassiveMode = 2, /**< Symmetric passive. */
|
||||
ClientMode = 3, /**< Client. */
|
||||
ServerMode = 4, /**< Server. */
|
||||
BroadcastMode = 5, /**< Broadcast. */
|
||||
ControlMode = 6, /**< NTP control message. */
|
||||
PrivateMode = 7, /**< Reserved for private use. */
|
||||
};
|
||||
|
||||
enum NtpStratum
|
||||
{
|
||||
UnspecifiedStratum = 0, /**< Unspecified or unavailable. */
|
||||
PrimaryStratum = 1, /**< Primary reference (e.g. radio-clock). */
|
||||
SecondaryStratumFirst = 2, /**< Secondary reference (via NTP or SNTP). */
|
||||
SecondaryStratumLast = 15,
|
||||
UnsynchronizedStratum = 16, /**< Unsynchronized. */
|
||||
/* 17-255 are reserved. */
|
||||
};
|
||||
|
||||
struct NtpPacketFlags
|
||||
{
|
||||
unsigned char mode : 3;
|
||||
unsigned char versionNumber : 3;
|
||||
unsigned char leapIndicator : 2;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct NtpTimestamp
|
||||
{
|
||||
quint32 seconds;
|
||||
quint32 fraction;
|
||||
static inline NtpTimestamp fromDateTime(const QDateTime &dateTime);
|
||||
static inline QDateTime toDateTime(const NtpTimestamp &ntpTime);
|
||||
};
|
||||
|
||||
struct NtpPacket
|
||||
{
|
||||
NtpPacketFlags flags;
|
||||
quint8 stratum;
|
||||
qint8 poll;
|
||||
qint8 precision;
|
||||
qint32 rootDelay;
|
||||
qint32 rootDispersion;
|
||||
qint8 referenceID[4];
|
||||
NtpTimestamp referenceTimestamp;
|
||||
NtpTimestamp originateTimestamp;
|
||||
NtpTimestamp receiveTimestamp;
|
||||
NtpTimestamp transmitTimestamp;
|
||||
};
|
||||
|
||||
struct NtpAuthenticationInfo
|
||||
{
|
||||
quint32 keyId;
|
||||
quint8 messageDigest[16];
|
||||
};
|
||||
|
||||
struct NtpFullPacket
|
||||
{
|
||||
NtpPacket basic;
|
||||
NtpAuthenticationInfo auth;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
class NtpReplyPrivate : public QSharedData
|
||||
{
|
||||
public:
|
||||
NtpFullPacket packet;
|
||||
QDateTime destinationTime;
|
||||
};
|
||||
|
||||
class NtpReply
|
||||
{
|
||||
public:
|
||||
NtpReply();
|
||||
NtpReply(const NtpReply &other);
|
||||
~NtpReply();
|
||||
NtpReply &operator=(const NtpReply &other);
|
||||
NtpLeapIndicator leapIndicator() const;
|
||||
quint8 versionNumber() const;
|
||||
NtpMode mode() const;
|
||||
quint8 stratum() const;
|
||||
qreal pollInterval() const;
|
||||
qreal precision() const;
|
||||
QDateTime referenceTime() const;
|
||||
QDateTime originTime() const;
|
||||
QDateTime receiveTime() const;
|
||||
QDateTime transmitTime() const;
|
||||
QDateTime destinationTime() const;
|
||||
qint64 roundTripDelay() const;
|
||||
qint64 localClockOffset() const;
|
||||
bool isNull() const;
|
||||
|
||||
protected:
|
||||
friend class NtpClient;
|
||||
NtpReply(NtpReplyPrivate *dd);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<NtpReplyPrivate> d;
|
||||
};
|
||||
|
||||
class NtpClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NtpClient(QObject *parent = NULL);
|
||||
NtpClient(const QHostAddress &bindAddress, quint16 bindPort, QObject *parent = NULL);
|
||||
virtual ~NtpClient();
|
||||
bool sendRequest(const QHostAddress &address, quint16 port);
|
||||
|
||||
Q_SIGNALS:
|
||||
void replyReceived(const QHostAddress &address, quint16 port, const NtpReply &reply);
|
||||
|
||||
private Q_SLOTS:
|
||||
void readPendingDatagrams();
|
||||
|
||||
private:
|
||||
void init(const QHostAddress &bindAddress, quint16 bindPort);
|
||||
|
||||
QUdpSocket *mSocket;
|
||||
};
|
||||
} // namespace Qv2ray::components::ntp
|
@ -55,23 +55,23 @@ namespace Qv2ray::components::plugins
|
||||
info.pluginLoader->unload();
|
||||
continue;
|
||||
}
|
||||
info.metadata = info.pluginInterface->GetMetadata();
|
||||
if (plugins.contains(info.metadata.InternalName))
|
||||
{
|
||||
LOG(MODULE_PLUGINHOST, "Found another plugin with the same internal name: " + info.metadata.InternalName + ". Skipped")
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info.pluginInterface->QvPluginInterfaceVersion != QV2RAY_PLUGIN_INTERFACE_VERSION)
|
||||
{
|
||||
// The plugin was built for a not-compactable version of Qv2ray. Don't load the plugin by default.
|
||||
LOG(MODULE_PLUGINHOST, info.metadata.InternalName + " is built with an older Interface, ignoring")
|
||||
LOG(MODULE_PLUGINHOST, info.libraryPath + " is built with an older Interface, ignoring")
|
||||
QvMessageBoxWarn(nullptr, tr("Cannot load plugin"),
|
||||
info.metadata.Name + " " + tr("cannot be loaded.") + NEWLINE NEWLINE +
|
||||
tr("The plugin located here cannot be loaded: ") + NEWLINE + info.libraryPath + NEWLINE NEWLINE +
|
||||
tr("This plugin was built against an older/newer version of the Plugin Interface.") + NEWLINE +
|
||||
tr("Please contact the plugin provider or report the issue to Qv2ray Workgroup."));
|
||||
continue;
|
||||
}
|
||||
info.metadata = info.pluginInterface->GetMetadata();
|
||||
if (plugins.contains(info.metadata.InternalName))
|
||||
{
|
||||
LOG(MODULE_PLUGINHOST, "Found another plugin with the same internal name: " + info.metadata.InternalName + ". Skipped")
|
||||
continue;
|
||||
}
|
||||
connect(plugin, SIGNAL(PluginLog(const QString &)), this, SLOT(QvPluginLog(const QString &)));
|
||||
connect(plugin, SIGNAL(PluginErrorMessageBox(const QString &)), this, SLOT(QvPluginMessageBox(const QString &)));
|
||||
LOG(MODULE_PLUGINHOST, "Loaded plugin: \"" + info.metadata.Name + "\" made by: \"" + info.metadata.Author + "\"")
|
||||
@ -120,6 +120,7 @@ namespace Qv2ray::components::plugins
|
||||
{
|
||||
// Load plugin if it haven't been loaded.
|
||||
InitializePlugin(internalName);
|
||||
|
||||
QvMessageBoxInfo(nullptr, tr("Enabling a plugin"), tr("The plugin will become fully functional after restarting Qv2ray."));
|
||||
}
|
||||
}
|
||||
@ -241,14 +242,14 @@ namespace Qv2ray::components::plugins
|
||||
return data;
|
||||
}
|
||||
|
||||
const QMultiHash<QString, QPair<QString, QJsonObject>> QvPluginHost::TryDeserializeShareLink(const QString &sharelink, //
|
||||
QString *prefix, //
|
||||
const QList<std::tuple<QString, QString, QJsonObject>> QvPluginHost::TryDeserializeShareLink(const QString &sharelink, //
|
||||
QString *aliasPrefix, //
|
||||
QString *errMessage, //
|
||||
QString *newGroupName, //
|
||||
bool *status) const
|
||||
{
|
||||
Q_UNUSED(newGroupName)
|
||||
QMultiHash<QString, QPair<QString, QJsonObject>> data;
|
||||
QList<std::tuple<QString, QString, QJsonObject>> data;
|
||||
*status = true;
|
||||
for (const auto &plugin : plugins)
|
||||
{
|
||||
@ -262,9 +263,9 @@ namespace Qv2ray::components::plugins
|
||||
}
|
||||
if (thisPluginCanHandle)
|
||||
{
|
||||
auto [protocol, outboundSettings] = serializer->DeserializeOutbound(sharelink, prefix, errMessage);
|
||||
const auto &[protocol, outboundSettings] = serializer->DeserializeOutbound(sharelink, aliasPrefix, errMessage);
|
||||
*status = *status && errMessage->isEmpty();
|
||||
data.insert(*prefix, { protocol, outboundSettings });
|
||||
data << std::tuple{ *aliasPrefix, protocol, outboundSettings };
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,7 +279,7 @@ namespace Qv2ray::components::plugins
|
||||
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_SERIALIZOR))
|
||||
{
|
||||
auto serializer = plugin.pluginInterface->GetSerializer();
|
||||
if (serializer->OutboundProtocols().contains(protocol))
|
||||
if (serializer && serializer->OutboundProtocols().contains(protocol))
|
||||
{
|
||||
auto info = serializer->GetOutboundInfo(protocol, o);
|
||||
*status = true;
|
||||
@ -300,7 +301,7 @@ namespace Qv2ray::components::plugins
|
||||
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_SERIALIZOR))
|
||||
{
|
||||
auto serializer = plugin.pluginInterface->GetSerializer();
|
||||
if (serializer->OutboundProtocols().contains(protocol))
|
||||
if (serializer && serializer->OutboundProtocols().contains(protocol))
|
||||
{
|
||||
auto link = serializer->SerializeOutbound(protocol, alias, groupName, outboundSettings);
|
||||
*status = true;
|
||||
@ -311,18 +312,31 @@ namespace Qv2ray::components::plugins
|
||||
return "";
|
||||
}
|
||||
|
||||
const QMap<QString, std::shared_ptr<QvPluginKernel>> QvPluginHost::GetPluginKernels() const
|
||||
const std::unique_ptr<QvPluginKernel> QvPluginHost::CreatePluginKernel(const QString &pluginInternalName) const
|
||||
{
|
||||
QMap<QString, std::shared_ptr<QvPluginKernel>> kernels;
|
||||
if (!plugins.contains(pluginInternalName))
|
||||
return nullptr;
|
||||
const auto &plugin = plugins.value(pluginInternalName);
|
||||
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_KERNEL))
|
||||
{
|
||||
return plugin.pluginInterface->CreateKernel();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QMap<QString, QList<QString>> QvPluginHost::GetPluginKernels() const
|
||||
{
|
||||
QMap<QString, QList<QString>> kernels;
|
||||
for (const auto &plugin : plugins)
|
||||
{
|
||||
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_KERNEL))
|
||||
{
|
||||
auto kern = plugin.pluginInterface->GetKernel();
|
||||
for (const auto &cap : kern->KernelOutboundCapabilities())
|
||||
QStringList outbounds;
|
||||
for (const auto &info : plugin.metadata.KernelOutboundCapabilities)
|
||||
{
|
||||
kernels.insert(cap.protocol, kern);
|
||||
outbounds << info.protocol;
|
||||
}
|
||||
kernels.insert(plugin.metadata.InternalName, outbounds);
|
||||
}
|
||||
}
|
||||
return kernels;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user