mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-21 19:30:26 +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. -->
|
<!-- 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:
|
Version:
|
||||||
@ -82,3 +82,5 @@ Extra build info:
|
|||||||
## Additional Info
|
## Additional Info
|
||||||
|
|
||||||
<!-- Feel free to write down any info you consider helpful to resolve the bug. -->
|
<!-- 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 有帮助的任何信息都可以在此写出来。 -->
|
<!-- 你认为对修复 bug 有帮助的任何信息都可以在此写出来。 -->
|
||||||
|
|
||||||
|
*请注意打码隐私相关信息。*
|
||||||
|
|
||||||
|
18
.github/workflows/build-qv2ray-cmake.yml
vendored
18
.github/workflows/build-qv2ray-cmake.yml
vendored
@ -74,7 +74,7 @@ jobs:
|
|||||||
path: ../Qt
|
path: ../Qt
|
||||||
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
|
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
|
||||||
- name: Installing Qt - ${{ matrix.arch }}
|
- name: Installing Qt - ${{ matrix.arch }}
|
||||||
uses: jurplel/install-qt-action@v2.5.0
|
uses: jurplel/install-qt-action@v2
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.qt_version }}
|
version: ${{ matrix.qt_version }}
|
||||||
arch: ${{ matrix.qtarch }}
|
arch: ${{ matrix.qtarch }}
|
||||||
@ -118,6 +118,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
if: matrix.platform == 'macos-latest'
|
if: matrix.platform == 'macos-latest'
|
||||||
run: |
|
run: |
|
||||||
|
sudo xcode-select -s "/Applications/Xcode_10.3.app"
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DDS_STORE_SCRIPT=ON
|
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'
|
if: matrix.platform == 'ubuntu-16.04'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
CC: /usr/bin/gcc-9
|
CC: /usr/bin/gcc-7
|
||||||
CXX: /usr/bin/g++-9
|
CXX: /usr/bin/g++-7
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
@ -171,12 +172,23 @@ jobs:
|
|||||||
cd ..
|
cd ..
|
||||||
squashfs-root/AppRun AppDir/usr/share/applications/qv2ray.desktop -appimage -no-strip -always-overwrite
|
squashfs-root/AppRun AppDir/usr/share/applications/qv2ray.desktop -appimage -no-strip -always-overwrite
|
||||||
mv ./Qv2ray*.AppImage ./Qv2ray.AppImage
|
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
|
- name: Linux - ${{ matrix.qt_version }} - Uploading artifact
|
||||||
if: matrix.platform == 'ubuntu-16.04'
|
if: matrix.platform == 'ubuntu-16.04'
|
||||||
uses: actions/upload-artifact@master
|
uses: actions/upload-artifact@master
|
||||||
with:
|
with:
|
||||||
name: Qv2ray-${{ github.sha }}.linux-${{ matrix.arch }}.qt${{ matrix.qt_version }}.AppImage
|
name: Qv2ray-${{ github.sha }}.linux-${{ matrix.arch }}.qt${{ matrix.qt_version }}.AppImage
|
||||||
path: build/Qv2ray.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
|
- name: Linux - ${{ matrix.qt_version }} - Upload binaries to release
|
||||||
uses: svenstaro/upload-release-action@v1-release
|
uses: svenstaro/upload-release-action@v1-release
|
||||||
if: github.event_name == 'release' && matrix.platform == 'ubuntu-16.04' && matrix.qt_version == '5.14.2'
|
if: github.event_name == 'release' && matrix.platform == 'ubuntu-16.04' && matrix.qt_version == '5.14.2'
|
||||||
|
24
.github/workflows/deb.yml
vendored
24
.github/workflows/deb.yml
vendored
@ -21,6 +21,7 @@ jobs:
|
|||||||
|
|
||||||
linux:
|
linux:
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
distro: [stable, unstable]
|
distro: [stable, unstable]
|
||||||
needs: check_commit_msg
|
needs: check_commit_msg
|
||||||
@ -40,20 +41,39 @@ jobs:
|
|||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
run: |
|
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
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
dch -l${{ matrix.distro }} -m 'Build against ${{ matrix.distro }}' -D ${{ matrix.distro }}
|
||||||
dpkg-buildpackage -us -uc -i -b
|
dpkg-buildpackage -us -uc -i -b
|
||||||
- name: Copy binary
|
- name: Copy binary
|
||||||
run: |
|
run: |
|
||||||
cp ../qv2ray_*.deb ./
|
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
|
- name: Get package name
|
||||||
id: get_package
|
id: get_package
|
||||||
run: echo ::set-output name=NAME::$(basename qv2ray_*.deb)
|
run: echo ::set-output name=NAME::$(basename qv2ray_*.deb)
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v2-preview
|
uses: actions/upload-artifact@v2-preview
|
||||||
with:
|
with:
|
||||||
name: qv2ray_${{ matrix.distro }}
|
name: ${{ steps.get_package.outputs.NAME }}
|
||||||
path: ${{ steps.get_package.outputs.NAME }}
|
path: ${{ steps.get_package.outputs.NAME }}
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
uses: svenstaro/upload-release-action@v1-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
|
path: ../Qt
|
||||||
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
|
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
|
||||||
- name: Installing Qt - ${{ matrix.arch }}
|
- name: Installing Qt - ${{ matrix.arch }}
|
||||||
uses: jurplel/install-qt-action@v2.5.0
|
uses: jurplel/install-qt-action@v2
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.qt_version }}
|
version: ${{ matrix.qt_version }}
|
||||||
arch: ${{ matrix.qtarch }}
|
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"]
|
[submodule "3rdparty/SingleApplication"]
|
||||||
path = 3rdparty/SingleApplication
|
path = 3rdparty/SingleApplication
|
||||||
url = https://github.com/itay-grudev/SingleApplication
|
url = https://github.com/itay-grudev/SingleApplication
|
||||||
@ -16,6 +13,15 @@
|
|||||||
[submodule "3rdparty/zxing-cpp"]
|
[submodule "3rdparty/zxing-cpp"]
|
||||||
path = 3rdparty/zxing-cpp
|
path = 3rdparty/zxing-cpp
|
||||||
url = https://github.com/nu-book/zxing-cpp
|
url = https://github.com/nu-book/zxing-cpp
|
||||||
[submodule "src/components/plugins/interface"]
|
[submodule "src/plugin-interface"]
|
||||||
path = src/components/plugins/interface
|
path = src/plugin-interface
|
||||||
url = https://github.com/Qv2ray/QvPlugin-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
|
os: linux
|
||||||
dist: bionic
|
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:
|
script:
|
||||||
- sudo apt-get autoremove lxd --purge
|
- echo Refreshing launchpad repository
|
||||||
- sudo /snap/bin/lxd waitready
|
|
||||||
- sudo /snap/bin/lxd init --auto
|
|
||||||
- sudo snapcraft --use-lxd
|
|
||||||
|
|
||||||
after_failure:
|
|
||||||
- sudo journalctl -u snapd
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
- provider: launchpad
|
- 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
|
425
CMakeLists.txt
425
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)
|
file(STRINGS "${CMAKE_SOURCE_DIR}/makespec/VERSIONSUFFIX" QV2RAY_VERSION_SUFFIX)
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Release")
|
if(NOT CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
math(EXPR QV2RAY_BUILD_VERSION "1 + ${QV2RAY_BUILD_VERSION}")
|
add_definitions(-DNODE_DEBUG_DRAWING)
|
||||||
message("Increasing BUILDVERSION")
|
|
||||||
file(WRITE "${CMAKE_SOURCE_DIR}/makespec/BUILDVERSION" ${QV2RAY_BUILD_VERSION})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(QV2RAY_VERSION_STRING "${QV2RAY_VERSION}${QV2RAY_VERSION_SUFFIX}")
|
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_BUILD=${QV2RAY_BUILD_VERSION})
|
||||||
|
|
||||||
add_definitions(-DQV2RAY_VERSION_STRING="${QV2RAY_VERSION_STRING}")
|
add_definitions(-DQV2RAY_VERSION_STRING="${QV2RAY_VERSION_STRING}")
|
||||||
add_definitions(-DXTOSTRUCT_QT)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
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_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
@ -65,7 +81,7 @@ message(" ")
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_compile_options("/std:c++17")
|
add_compile_options("/std:c++17")
|
||||||
add_definitions(-DUNICODE -D_UNICODE)
|
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)
|
set(GUI_TYPE WIN32)
|
||||||
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||||
if(CMAKE_CL_64)
|
if(CMAKE_CL_64)
|
||||||
@ -76,19 +92,68 @@ if(WIN32)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
# ==================================================================================
|
||||||
|
# Qv2ray Build Arguments
|
||||||
|
# ==================================================================================
|
||||||
set(QV2RAY_QNODEEDITOR_PROVIDER "module" CACHE STRING "qnodeeditor provider")
|
set(QV2RAY_QNODEEDITOR_PROVIDER "module" CACHE STRING "qnodeeditor provider")
|
||||||
set(QV2RAY_ZXING_PROVIDER "module" CACHE STRING "zxing-cpp 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/translations.cmake)
|
||||||
include(cmake/qnodeeditor.cmake)
|
include(cmake/qnodeeditor.cmake)
|
||||||
include(cmake/singleapplication.cmake)
|
if (ANDROID)
|
||||||
include(cmake/protobuf.cmake)
|
else()
|
||||||
include(cmake/cpp-httplib.cmake)
|
include(cmake/singleapplication.cmake)
|
||||||
include(cmake/backend.cmake)
|
include(cmake/protobuf.cmake)
|
||||||
|
include(cmake/backend.cmake)
|
||||||
|
endif()
|
||||||
include(cmake/zxing-cpp.cmake)
|
include(cmake/zxing-cpp.cmake)
|
||||||
|
include(cmake/libsemver.cmake)
|
||||||
|
|
||||||
|
|
||||||
|
# ==================================================================================
|
||||||
|
# Qv2ray Build Info
|
||||||
|
# ==================================================================================
|
||||||
if(QV2RAY_BUILD_INFO)
|
if(QV2RAY_BUILD_INFO)
|
||||||
set(_QV2RAY_BUILD_INFO_STR_ "${QV2RAY_BUILD_INFO}")
|
set(_QV2RAY_BUILD_INFO_STR_ "${QV2RAY_BUILD_INFO}")
|
||||||
elseif(DEFINED ENV{_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}")
|
set(_QV2RAY_BUILD_EXTRA_INFO_STR_ "Qv2ray ${QV2RAY_VERSION_STRING}:${QV2RAY_BUILD_VERSION}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(QV2RAY_BUILD_INFO ${_QV2RAY_BUILD_INFO_STR_} CACHE STRING "Qv2ray build info")
|
set(QV2RAY_BUILD_INFO ${_QV2RAY_BUILD_INFO_STR_})
|
||||||
set(QV2RAY_BUILD_EXTRA_INFO ${_QV2RAY_BUILD_EXTRA_INFO_STR_} CACHE STRING "Qv2ray build extra info")
|
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_INFO_STR_="${_QV2RAY_BUILD_INFO_STR_}")
|
||||||
add_definitions(-D_QV2RAY_BUILD_EXTRA_INFO_STR_="${_QV2RAY_BUILD_EXTRA_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: ${_QV2RAY_BUILD_INFO_STR_}")
|
||||||
message("Qv2ray build info ex: ${_QV2RAY_BUILD_EXTRA_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}")
|
# Plugin Interface Headers
|
||||||
endif()
|
# ==================================================================================
|
||||||
|
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}")
|
# Qv2ray Sources and Headers
|
||||||
endif()
|
# ==================================================================================
|
||||||
|
include(cmake/components/qv2ray-lib.cmake)
|
||||||
|
include(cmake/components/qv2ray-ui.cmake)
|
||||||
|
include(3rdparty/uistyles/uistyles.cmake)
|
||||||
|
|
||||||
if(QV2RAY_USE_BUILTIN_DARKTHEME)
|
set(QRC_RESOURCES
|
||||||
add_definitions(-DQV2RAY_USE_BUILTIN_DARKTHEME=true)
|
${UISTYLE_QRCS}
|
||||||
endif()
|
${CMAKE_SOURCE_DIR}/resources.qrc)
|
||||||
|
|
||||||
if(QV2RAY_DISABLE_AUTO_UPDATE)
|
# Qv2ray baselib
|
||||||
add_definitions(-DDISABLE_AUTO_UPDATE)
|
add_library(qv2ray-baselib STATIC
|
||||||
endif()
|
${QV2RAY_BASE_HEADERS}
|
||||||
|
${QV2RAY_LIB_SOURCES}
|
||||||
set(QVPLUGIN_INTERFACE_INCLUDE_DIR "src/components/plugins/interface")
|
|
||||||
include(src/components/plugins/interface/QvPluginInterface.cmake)
|
|
||||||
|
|
||||||
set(QV2RAY_SOURCES
|
|
||||||
${QVPLUGIN_INTERFACE_HEADERS}
|
${QVPLUGIN_INTERFACE_HEADERS}
|
||||||
3rdparty/libsemver/version.cpp
|
${LIBSEMVER_SOURCES}
|
||||||
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}
|
|
||||||
${PROTO_SRCS}
|
${PROTO_SRCS}
|
||||||
${PROTO_HDRS}
|
${PROTO_HDRS}
|
||||||
${API_GRPC_SRCS}
|
${API_GRPC_SRCS}
|
||||||
${API_PROTO_SRCS}
|
${API_PROTO_SRCS}
|
||||||
${QRC_RESOURCES}
|
|
||||||
${QM_FILES}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
set(QV2RAY_FULL_SOURCES
|
||||||
${QT_LIBRARY}
|
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_PROTOBUF_LIBRARY}
|
||||||
${QV2RAY_BACKEND_LIBRARIES}
|
${QV2RAY_BACKEND_LIBRARIES}
|
||||||
${QNODEEDITOR_LIBRARY}
|
|
||||||
${ZXING_LIBRARY}
|
${ZXING_LIBRARY}
|
||||||
Threads::Threads
|
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}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
${CMAKE_BINARY_DIR}
|
${CMAKE_BINARY_DIR}
|
||||||
${QHTTPSERVER_DIR}
|
|
||||||
${QNODEEDITOR_INCLUDE_PATH}
|
${QNODEEDITOR_INCLUDE_PATH}
|
||||||
${ZXING_INCLUDE_PATH}
|
|
||||||
${SINGLEAPPLICATION_DIR}
|
${SINGLEAPPLICATION_DIR}
|
||||||
${Protobuf_INCLUDE_DIRS}
|
${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)
|
if(APPLE)
|
||||||
find_package(Iconv REQUIRED)
|
find_package(Iconv REQUIRED)
|
||||||
find_library(CARBON NAMES Carbon)
|
find_library(CARBON NAMES Carbon)
|
||||||
find_library(COCOA NAMES Cocoa)
|
find_library(COCOA NAMES Cocoa)
|
||||||
find_library(SECURITY NAMES Security)
|
find_library(SECURITY NAMES Security)
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(qv2ray
|
||||||
Iconv::Iconv
|
Iconv::Iconv
|
||||||
${CARBON}
|
${CARBON}
|
||||||
${COCOA}
|
${COCOA}
|
||||||
${SECURITY}
|
${SECURITY}
|
||||||
)
|
)
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
target_include_directories(qv2ray PRIVATE
|
||||||
${Iconv_INCLUDE_DIR}
|
${Iconv_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -373,11 +304,11 @@ if(APPLE)
|
|||||||
MACOSX_PACKAGE_LOCATION Resources/lang
|
MACOSX_PACKAGE_LOCATION Resources/lang
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(${PROJECT_NAME} PRIVATE
|
target_sources(qv2ray PRIVATE
|
||||||
${MACOSX_ICON}
|
${MACOSX_ICON}
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME}
|
set_target_properties(qv2ray
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
MACOSX_BUNDLE TRUE
|
MACOSX_BUNDLE TRUE
|
||||||
MACOSX_BUNDLE_INFO_PLIST ${MACOSX_PLIST}
|
MACOSX_BUNDLE_INFO_PLIST ${MACOSX_PLIST}
|
||||||
@ -394,20 +325,22 @@ if(APPLE)
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Destination paths below are relative to ${CMAKE_INSTALL_PREFIX}
|
# Destination paths below are relative to ${CMAKE_INSTALL_PREFIX}
|
||||||
install(TARGETS ${PROJECT_NAME}
|
|
||||||
|
install(TARGETS qv2ray
|
||||||
BUNDLE DESTINATION . COMPONENT Runtime
|
BUNDLE DESTINATION . COMPONENT Runtime
|
||||||
RUNTIME DESTINATION bin COMPONENT Runtime
|
RUNTIME DESTINATION bin COMPONENT Runtime
|
||||||
)
|
)
|
||||||
|
if(QV2RAY_AUTO_DEPLOY)
|
||||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
add_custom_command(TARGET qv2ray POST_BUILD
|
||||||
COMMAND macdeployqt ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app
|
COMMAND ${Qt5_DIR}/../../../bin/macdeployqt ${CMAKE_BINARY_DIR}/qv2ray.app
|
||||||
)
|
)
|
||||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app")
|
endif()
|
||||||
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/qv2ray.app")
|
||||||
include(cmake/deployment.cmake)
|
include(cmake/deployment.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE AND NOT WIN32)
|
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.metainfo.xml DESTINATION share/metainfo)
|
||||||
install(FILES assets/qv2ray.desktop DESTINATION share/applications)
|
install(FILES assets/qv2ray.desktop DESTINATION share/applications)
|
||||||
install(FILES assets/icons/qv2ray.png DESTINATION share/icons/hicolor/256x256/apps)
|
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()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(${PROJECT_NAME} wininet wsock32 ws2_32 user32)
|
find_package(OpenSSL REQUIRED)
|
||||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION .)
|
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)
|
if(NOT EMBED_TRANSLATIONS)
|
||||||
install(FILES ${QM_FILES} DESTINATION lang)
|
install(FILES ${QM_FILES} DESTINATION lang)
|
||||||
endif()
|
endif()
|
||||||
|
if(QV2RAY_AUTO_DEPLOY)
|
||||||
if(CMAKE_CL_64)
|
add_custom_command(TARGET qv2ray POST_BUILD
|
||||||
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libssl-1_1-x64.dll DESTINATION .)
|
COMMAND ${Qt5_DIR}/../../../bin/windeployqt ${CMAKE_BINARY_DIR}/qv2ray.exe --compiler-runtime --verbose 2 --dir ${CMAKE_BINARY_DIR}/winqt/
|
||||||
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 .)
|
|
||||||
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/
|
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/winqt/ DESTINATION .)
|
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)
|
include(cmake/deployment.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
@ -5,7 +5,7 @@ AlignAfterOpenBracket: Align
|
|||||||
AllowAllArgumentsOnNextLine: false
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: false
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
AllowShortBlocksOnASingleLine: false
|
AllowShortBlocksOnASingleLine: Never
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: None
|
AllowShortFunctionsOnASingleLine: None
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
@ -42,7 +42,7 @@ SpaceAfterTemplateKeyword: false
|
|||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
SpacesInParentheses: false
|
SpacesInParentheses: false
|
||||||
Standard: Cpp11
|
Standard: c++17
|
||||||
StatementMacros: [ Q_UNUSED LOG DEBUG ]
|
StatementMacros: [ Q_UNUSED LOG DEBUG ]
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
|
@ -34,5 +34,20 @@
|
|||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<string>True</string>
|
<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>
|
</dict>
|
||||||
</plist>
|
</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">
|
<!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">
|
<html>
|
||||||
p, li { white-space: pre-wrap; }
|
|
||||||
</style></head><body style=" font-family:'WenQuanYi Micro Hei'; font-size:10pt; font-weight:400; font-style:normal;">
|
<head>
|
||||||
<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>
|
<meta name="qrichtext" content="1" />
|
||||||
<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>
|
<style type="text/css">
|
||||||
<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,
|
||||||
<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>
|
li {
|
||||||
<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>
|
white-space: pre-wrap;
|
||||||
<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>
|
</style>
|
||||||
<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>
|
</head>
|
||||||
<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>
|
<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'; 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'; 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'; 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'; 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) 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-2020 Qv2ray Development Group.</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="-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'; 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'; 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 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) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)</span></p>
|
||||||
</body></html>
|
<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": [
|
"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" }
|
{ "x": 375, "y": 205, "type": "link", "path": "/Applications" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -2,25 +2,42 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Qv2ray
|
Name=Qv2ray
|
||||||
Type=Application
|
Type=Application
|
||||||
GenericName=V2ray Graphical Frontend
|
GenericName=V2Ray Graphical Frontend
|
||||||
GenericName[zh_CN]=V2ray 图形前端
|
GenericName[zh_CN]=V2Ray 图形前端
|
||||||
Comment=A Cross-platform v2ray Qt GUI Client
|
GenericName[ja]=V2Rayグラフィックフロントエンド
|
||||||
Comment[zh_CN]=跨平台的 v2ray Qt 客户端
|
Comment=A Cross-Platform V2Ray Qt GUI Client
|
||||||
|
Comment[zh_CN]=跨平台的 V2Ray Qt 图形客户端
|
||||||
|
Comment[ja]=とあるクロスプラットフォームV2Rayグラフィックフロントエンド
|
||||||
Keywords=Internet;VPN;Proxy;v2ray;Qt;qv;
|
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;
|
Categories=Network;Qt;
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Icon=qv2ray
|
Icon=qv2ray
|
||||||
Exec=qv2ray
|
Exec=qv2ray %u
|
||||||
Actions=noAPI;withToolbarPlugin;
|
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]
|
[Desktop Action noAPI]
|
||||||
Name=Start without gRPC API
|
Name=Start without gRPC API
|
||||||
Name[zh_CN]=不使用 gRPC API 启动
|
Name[zh_CN]=不使用 gRPC API 启动
|
||||||
|
Name[ja]=gRPC使用せずに起動
|
||||||
Exec=qv2ray --noAPI
|
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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<component type="desktop-application">
|
<component type="desktop-application">
|
||||||
<id>com.github.Qv2ray</id>
|
<id>com.github.Qv2ray</id>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>GPL-3.0+</metadata_license>
|
||||||
<project_license>GPL-3.0</project_license>
|
<project_license>GPL-3.0+</project_license>
|
||||||
<name>Qv2ray</name>
|
<name>Qv2ray</name>
|
||||||
<summary>Qv2ray is a cross-platform v2ray graphical frontend written in Qt.</summary>
|
<summary>Qv2ray is a cross-platform v2ray graphical frontend written in Qt.</summary>
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ VS_VERSION_INFO VERSIONINFO
|
|||||||
BLOCK "040904b0"
|
BLOCK "040904b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Qv2ray Workgroup\0"
|
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 "FileVersion", VER_FILEVERSION_STR
|
||||||
VALUE "LegalCopyright", "Qv2ray is being distributed under GPLv3\0"
|
VALUE "LegalCopyright", "Qv2ray is being distributed under GPLv3\0"
|
||||||
VALUE "OriginalFilename", "qv2ray.exe\0"
|
VALUE "OriginalFilename", "qv2ray.exe\0"
|
||||||
|
@ -15,21 +15,25 @@ pool:
|
|||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
- task: NodeTool@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '12.x'
|
||||||
- script: |
|
- 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
|
displayName: Prepare dependencies
|
||||||
- script: |
|
- script: |
|
||||||
PATH=/usr/local/opt/qt5/bin:$PATH
|
PATH=/usr/local/opt/qt5/bin:$PATH
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.14
|
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13
|
||||||
sudo cmake --build . --target package --parallel $(sysctl -n hw.logicalcpu)
|
cmake --build .
|
||||||
|
sudo cmake --install .
|
||||||
|
appdmg ../assets/package_dmg.json ../qv2ray-legacy.dmg
|
||||||
displayName: Build Qv2ray
|
displayName: Build Qv2ray
|
||||||
env:
|
env:
|
||||||
Qt5_DIR: /usr/local/opt/qt5/lib/cmake/Qt5
|
Qt5_DIR: /usr/local/opt/qt5/lib/cmake/Qt5
|
||||||
- script: |
|
|
||||||
cp build/qv2ray-*.dmg ./qv2ray-legacy.dmg
|
|
||||||
displayName: Copy binary
|
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
inputs:
|
inputs:
|
||||||
PathtoPublish: 'qv2ray-legacy.dmg'
|
PathtoPublish: 'qv2ray-legacy.dmg'
|
||||||
|
@ -11,13 +11,14 @@ if(NOT USE_LIBQVB)
|
|||||||
set(QV2RAY_BACKEND_LIBRARIES ${GRPC_LIBRARIES})
|
set(QV2RAY_BACKEND_LIBRARIES ${GRPC_LIBRARIES})
|
||||||
else()
|
else()
|
||||||
find_library(UPB_LIBRARY NAMES upb)
|
find_library(UPB_LIBRARY NAMES upb)
|
||||||
|
find_library(ADDRESS_SORTING NAMES address_sorting)
|
||||||
pkg_check_modules(GRPC REQUIRED grpc++ grpc gpr)
|
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()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(API_PROTO "${CMAKE_SOURCE_DIR}/tools/v2ray_api.proto")
|
set(API_PROTO "${CMAKE_SOURCE_DIR}/assets/v2ray_api.proto")
|
||||||
set(API_PROTO_PATH "${CMAKE_SOURCE_DIR}/tools")
|
set(API_PROTO_PATH "${CMAKE_SOURCE_DIR}/assets")
|
||||||
set(API_PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.pb.cc")
|
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_PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.pb.h")
|
||||||
set(API_GRPC_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.grpc.pb.cc")
|
set(API_GRPC_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.grpc.pb.cc")
|
||||||
|
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
|
# Packaging
|
||||||
set(CPACK_PACKAGE_VENDOR "Qv2ray Development Group")
|
set(CPACK_PACKAGE_VENDOR "Qv2ray Development Group")
|
||||||
set(CPACK_PACKAGE_VERSION ${QV2RAY_VERSION_STRING})
|
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_MUI_UNIICON "${CMAKE_SOURCE_DIR}/assets/icons/qv2ray.ico")
|
||||||
set(CPACK_NSIS_DISPLAY_NAME "Qv2ray")
|
set(CPACK_NSIS_DISPLAY_NAME "Qv2ray")
|
||||||
set(CPACK_NSIS_PACKAGE_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 "
|
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "
|
||||||
CreateShortCut \\\"$DESKTOP\\\\Qv2ray.lnk\\\" \\\"$INSTDIR\\\\qv2ray.exe\\\"
|
CreateShortCut \\\"$DESKTOP\\\\Qv2ray.lnk\\\" \\\"$INSTDIR\\\\qv2ray.exe\\\"
|
||||||
CreateDirectory \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\"
|
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\\\"
|
WriteRegStr HKLM \\\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\qv2ray\\\" \\\"URLInfoAbout\\\" \\\"https://github.com/Qv2ray/Qv2ray\\\"
|
||||||
")
|
")
|
||||||
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "
|
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "
|
||||||
|
ExecWait \\\"taskkill /f /im qv2ray.exe\\\"
|
||||||
Delete \\\"$DESKTOP\\\\Qv2ray.lnk\\\"
|
Delete \\\"$DESKTOP\\\\Qv2ray.lnk\\\"
|
||||||
Delete \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\\Qv2ray.lnk\\\"
|
Delete \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\\Qv2ray.lnk\\\"
|
||||||
RMDir \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\"
|
RMDir \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qv2ray\\\"
|
||||||
@ -78,3 +54,33 @@ if(APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CPack)
|
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)
|
find_package(Protobuf REQUIRED)
|
||||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/tools/v2ray_geosite.proto)
|
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/assets/v2ray_geosite.proto)
|
||||||
set(QV2RAY_PROTOBUF_LIBRARY
|
set(QV2RAY_PROTOBUF_LIBRARY
|
||||||
protobuf::libprotobuf
|
protobuf::libprotobuf
|
||||||
)
|
)
|
||||||
|
@ -24,11 +24,13 @@ if(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "module")
|
|||||||
${QNODEEDITOR_DIR}/src/Properties.cpp
|
${QNODEEDITOR_DIR}/src/Properties.cpp
|
||||||
${QNODEEDITOR_DIR}/src/StyleCollection.cpp
|
${QNODEEDITOR_DIR}/src/StyleCollection.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(QNODEEDITOR_INCLUDE_PATH
|
set(QNODEEDITOR_INCLUDE_PATH
|
||||||
|
${QNODEEDITOR_DIR}/include
|
||||||
${QNODEEDITOR_DIR}/include/nodes/internal
|
${QNODEEDITOR_DIR}/include/nodes/internal
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADERS_TO_MOC
|
set(QNODEEDITOR_HEADERS
|
||||||
${QNODEEDITOR_DIR}/include/nodes/internal/Compiler.hpp
|
${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/ConnectionGeometry.hpp
|
||||||
@ -58,15 +60,27 @@ if(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "module")
|
|||||||
${QNODEEDITOR_DIR}/include/nodes/internal/TypeConverter.hpp
|
${QNODEEDITOR_DIR}/include/nodes/internal/TypeConverter.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
qt5_wrap_cpp(QNODEEDITOR_SOURCES
|
# qt5_wrap_cpp(QNODEEDITOR_SOURCES
|
||||||
${HEADERS_TO_MOC}
|
# ${HEADERS_TO_MOC}
|
||||||
TARGET qv2ray
|
# TARGET qv2ray
|
||||||
OPTIONS --no-notes # Don't display a note for the headers which don't produce a moc_*.cpp
|
# 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)
|
set(QNODEEDITOR_QRC_RESOURCES ${QNODEEDITOR_DIR}/resources/resources.qrc)
|
||||||
elseif(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "package")
|
elseif(QV2RAY_QNODEEDITOR_PROVIDER STREQUAL "package")
|
||||||
find_package(NodeEditor REQUIRED CONFIG)
|
find_package(NodeEditor REQUIRED CONFIG)
|
||||||
|
find_path(QNODEEDITOR_INCLUDE_PATH NAMES Node.hpp PATH_SUFFIXES nodes/internal)
|
||||||
set(QNODEEDITOR_LIBRARY NodeEditor::nodes)
|
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)
|
add_definitions(-DQAPPLICATION_CLASS=QApplication)
|
||||||
set(SINGLEAPPLICATION_DIR ${CMAKE_SOURCE_DIR}/3rdparty/SingleApplication)
|
if(QV2RAY_SINGLEAPPLICATION_PROVIDER STREQUAL "module")
|
||||||
set(SINGLEAPPLICATION_SOURCES
|
set(SINGLEAPPLICATION_DIR ${CMAKE_SOURCE_DIR}/3rdparty/SingleApplication)
|
||||||
|
set(SINGLEAPPLICATION_SOURCES
|
||||||
${SINGLEAPPLICATION_DIR}/singleapplication.cpp
|
${SINGLEAPPLICATION_DIR}/singleapplication.cpp
|
||||||
${SINGLEAPPLICATION_DIR}/singleapplication_p.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()
|
||||||
|
@ -137,6 +137,13 @@ if(QV2RAY_ZXING_PROVIDER STREQUAL "module")
|
|||||||
${ZXING_DIR}/src/qrcode
|
${ZXING_DIR}/src/qrcode
|
||||||
${ZXING_DIR}/src/textcodec
|
${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")
|
elseif(QV2RAY_ZXING_PROVIDER STREQUAL "package")
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(ZXING REQUIRED zxing)
|
pkg_check_modules(ZXING REQUIRED zxing)
|
||||||
|
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
|
qv2ray (2.5.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* updating translations
|
* 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 (>= 3.6.1.3-1~),
|
||||||
protobuf-compiler-grpc (>= 1.16.1-1~),
|
protobuf-compiler-grpc (>= 1.16.1-1~),
|
||||||
qtbase5-dev (>= 5.11.3-1~),
|
qtbase5-dev (>= 5.11.3-1~),
|
||||||
|
qtdeclarative5-dev (>= 5.11.3-1~),
|
||||||
qttools5-dev (>= 5.11.3-1~)
|
qttools5-dev (>= 5.11.3-1~)
|
||||||
Standards-Version: 4.5.0
|
Standards-Version: 4.5.0
|
||||||
Homepage: https://github.com/Qv2ray/Qv2ray
|
Homepage: https://github.com/Qv2ray/Qv2ray
|
||||||
@ -21,4 +22,7 @@ Package: qv2ray
|
|||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
Recommends: v2ray
|
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
|
dh $@ --buildsystem=cmake+ninja
|
||||||
|
|
||||||
override_dh_auto_configure:
|
override_dh_auto_configure:
|
||||||
dh_auto_configure -- -DEMBED_TRANSLATIONS=ON -DCMAKE_BUILD_TYPE=Release
|
dh_auto_configure -- -DEMBED_TRANSLATIONS=ON -DBUILD_TESTING=ON
|
||||||
|
|
||||||
override_dh_auto_test:
|
|
||||||
|
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
|
name: qv2ray
|
||||||
base: core18
|
base: core20
|
||||||
adopt-info: qv2ray
|
adopt-info: qv2ray
|
||||||
icon: assets/icons/qv2ray.png
|
icon: assets/icons/qv2ray.png
|
||||||
|
|
||||||
@ -44,6 +44,15 @@ apps:
|
|||||||
desktop: "usr/share/applications/qv2ray.desktop"
|
desktop: "usr/share/applications/qv2ray.desktop"
|
||||||
|
|
||||||
parts:
|
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:
|
qv2ray:
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
source-type: git
|
source-type: git
|
||||||
@ -51,14 +60,13 @@ parts:
|
|||||||
parse-info: [usr/share/metainfo/qv2ray.metainfo.xml]
|
parse-info: [usr/share/metainfo/qv2ray.metainfo.xml]
|
||||||
build-packages:
|
build-packages:
|
||||||
- build-essential
|
- build-essential
|
||||||
- qttools5-dev-tools
|
|
||||||
- qttools5-dev
|
- qttools5-dev
|
||||||
- qt5-default
|
- qt5-default
|
||||||
- libgrpc++-dev
|
- libgrpc++-dev
|
||||||
- libprotobuf-dev
|
- libprotobuf-dev
|
||||||
- protobuf-compiler-grpc
|
- protobuf-compiler-grpc
|
||||||
- ninja-build
|
|
||||||
- pkg-config
|
- pkg-config
|
||||||
|
- libzxingcore-dev
|
||||||
stage-packages:
|
stage-packages:
|
||||||
- libgcc1
|
- libgcc1
|
||||||
- libstdc++6
|
- libstdc++6
|
||||||
@ -70,11 +78,13 @@ parts:
|
|||||||
- libqt5network5
|
- libqt5network5
|
||||||
- libqt5widgets5
|
- libqt5widgets5
|
||||||
- libglib2.0-bin
|
- libglib2.0-bin
|
||||||
configflags:
|
- libzxingcore1
|
||||||
|
cmake-parameters:
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
- -GNinja
|
|
||||||
- -DEMBED_TRANSLATIONS=ON
|
- -DEMBED_TRANSLATIONS=ON
|
||||||
|
- -DFALL_BACK_TO_XDG_OPEN=ON
|
||||||
|
- -DQV2RAY_ZXING_PROVIDER=package
|
||||||
override-pull: |
|
override-pull: |
|
||||||
snapcraftctl pull
|
snapcraftctl pull
|
||||||
build_number=$(cat makespec/BUILDVERSION)
|
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
|
sed -i 's|^Icon=.*|Icon=/usr/share/icons/hicolor/256x256/apps/qv2ray.png|g' assets/qv2ray.desktop
|
||||||
after:
|
after:
|
||||||
- desktop-qt5
|
- desktop-qt5
|
||||||
- ppa
|
|
||||||
|
|
||||||
desktop-qt5:
|
desktop-qt5:
|
||||||
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
|
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
|
||||||
@ -110,21 +119,70 @@ parts:
|
|||||||
- locales-all
|
- locales-all
|
||||||
- xdg-user-dirs
|
- xdg-user-dirs
|
||||||
- fcitx-frontend-qt5
|
- fcitx-frontend-qt5
|
||||||
after:
|
|
||||||
- ppa
|
|
||||||
|
|
||||||
qt5-gtk-platform:
|
qt5-gtk-platform:
|
||||||
plugin: nil
|
plugin: nil
|
||||||
stage-packages:
|
stage-packages:
|
||||||
- qt5-gtk-platformtheme
|
- qt5-gtk-platformtheme
|
||||||
after:
|
|
||||||
- ppa
|
|
||||||
|
|
||||||
ppa:
|
qv2ray-ssr-plugin:
|
||||||
plugin: nil
|
plugin: cmake
|
||||||
|
source-type: git
|
||||||
|
source: https://github.com/Qv2ray/QvPlugin-SSR.git
|
||||||
|
source-branch: dev
|
||||||
build-packages:
|
build-packages:
|
||||||
- software-properties-common
|
- build-essential
|
||||||
- dirmngr
|
- libsodium-dev
|
||||||
override-build: |
|
- libuv1-dev
|
||||||
sudo add-apt-repository -y ppa:ymshenyu/qv2ray-deps
|
- libssl-dev
|
||||||
sudo apt-get dist-upgrade -y
|
- 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 CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
|
||||||
#define CONCATENATE2(arg1, arg2) 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'
|
// Add key value pair into JSON named 'root'
|
||||||
|
#define JADDEx(field) root.insert(#field, field);
|
||||||
#define JADD(...) FOR_EACH(JADDEx, __VA_ARGS__)
|
#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
|
#pragma once
|
||||||
//
|
//
|
||||||
#include <QApplication>
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QtGui>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -21,8 +19,6 @@
|
|||||||
#include "base/models/QvSettingsObject.hpp"
|
#include "base/models/QvSettingsObject.hpp"
|
||||||
#include "base/models/QvStartupConfig.hpp"
|
#include "base/models/QvStartupConfig.hpp"
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace std::chrono;
|
|
||||||
using namespace Qv2ray;
|
using namespace Qv2ray;
|
||||||
using namespace Qv2ray::base;
|
using namespace Qv2ray::base;
|
||||||
using namespace Qv2ray::base::safetype;
|
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::protocol;
|
||||||
using namespace Qv2ray::base::objects::transfer;
|
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_INFO QString(_QV2RAY_BUILD_INFO_STR_)
|
||||||
#define QV2RAY_BUILD_EXTRA_INFO QString(_QV2RAY_BUILD_EXTRA_INFO_STR_)
|
#define QV2RAY_BUILD_EXTRA_INFO QString(_QV2RAY_BUILD_EXTRA_INFO_STR_)
|
||||||
|
|
||||||
@ -42,17 +50,14 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get Configured Config Dir Path
|
// 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_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_CONNECTIONS_DIR (QV2RAY_CONFIG_DIR + "connections/")
|
||||||
#define QV2RAY_SUBSCRIPTION_DIR (QV2RAY_CONFIG_DIR + "subscriptions/")
|
//
|
||||||
#define QV2RAY_PLUGIN_SETTINGS_DIR (QV2RAY_CONFIG_DIR + "plugin_settings/")
|
#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_CONFIG_FILE_EXTENSION ".qv2ray.json"
|
||||||
#define QV2RAY_GENERATED_DIR (QV2RAY_CONFIG_DIR + "generated/")
|
#define QV2RAY_GENERATED_DIR (QV2RAY_CONFIG_DIR + "generated/")
|
||||||
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
|
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
|
||||||
@ -85,9 +90,11 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
|
|
||||||
// GUI TOOLS
|
// GUI TOOLS
|
||||||
#define RED(obj) \
|
#define RED(obj) \
|
||||||
|
{ \
|
||||||
auto _temp = obj->palette(); \
|
auto _temp = obj->palette(); \
|
||||||
_temp.setColor(QPalette::Text, Qt::red); \
|
_temp.setColor(QPalette::Text, Qt::red); \
|
||||||
obj->setPalette(_temp);
|
obj->setPalette(_temp); \
|
||||||
|
}
|
||||||
|
|
||||||
#define BLACK(obj) obj->setPalette(QWidget::palette());
|
#define BLACK(obj) obj->setPalette(QWidget::palette());
|
||||||
|
|
||||||
@ -97,11 +104,11 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
#define ACCESS_OPTIONAL_VALUE(obj) (obj.value())
|
#define ACCESS_OPTIONAL_VALUE(obj) (obj.value())
|
||||||
#endif
|
#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 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)
|
#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 QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
|
||||||
|
|
||||||
#define JSON_ROOT_TRY_REMOVE(obj) \
|
|
||||||
if (root.contains(obj)) \
|
|
||||||
{ \
|
|
||||||
root.remove(obj); \
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Qv2ray
|
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)
|
inline QStringList Qv2rayAssetsPaths(const QString &dirName)
|
||||||
{
|
{
|
||||||
// Configuration Path
|
// Configuration Path
|
||||||
QStringList list;
|
QStringList list;
|
||||||
list << QV2RAY_CONFIG_DIR + dirName;
|
list << QV2RAY_CONFIG_DIR + dirName;
|
||||||
|
list << ":/" + dirName;
|
||||||
//
|
//
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// Linux platform directories.
|
// 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/share/qv2ray/" + dirName);
|
||||||
list << QString("/usr/local/share/qv2ray/" + dirName);
|
list << QString("/usr/local/share/qv2ray/" + dirName);
|
||||||
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, QStandardPaths::LocateDirectory);
|
// For AppImage?
|
||||||
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, QStandardPaths::LocateDirectory);
|
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)
|
#elif defined(Q_OS_MAC)
|
||||||
// macOS platform directories.
|
// macOS platform directories.
|
||||||
list << QDir(QApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath();
|
list << QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath();
|
||||||
#endif
|
#endif
|
||||||
|
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, QStandardPaths::LocateDirectory);
|
||||||
|
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, QStandardPaths::LocateDirectory);
|
||||||
// This is the default behavior on Windows
|
// This is the default behavior on Windows
|
||||||
list << QApplication::applicationDirPath() + "/" + dirName;
|
list << QCoreApplication::applicationDirPath() + "/" + dirName;
|
||||||
list.removeDuplicates();
|
list.removeDuplicates();
|
||||||
return list;
|
return list;
|
||||||
};
|
}
|
||||||
|
|
||||||
} // namespace Qv2ray
|
} // namespace Qv2ray
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <QtGlobal>
|
||||||
// Qv2ray build features.
|
// 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 BACKEND_LIBQVB
|
||||||
#ifdef _WIN32
|
#if !QvHasFeature(CanHasLibQvb)
|
||||||
#error "libQvb is not supported on Windows Platform"
|
#error Qv2ray API backend libQvb is not supported on this platform
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define QvHasFeature(feat) ((feat / 1) == 1)
|
||||||
|
@ -4,6 +4,14 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#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
|
namespace Qv2ray::base
|
||||||
{
|
{
|
||||||
// Forwarded from QvTinyLog
|
// 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)
|
void __QV2RAY_LOG_FUNC__(int type, const std::string &func, int line, const QString &module, const QString &log)
|
||||||
{
|
{
|
||||||
auto logString = QString("[" % module % "]: " % 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
|
#ifdef QT_DEBUG
|
||||||
// Debug build version, we only print info for DEBUG logs and print
|
// Debug build version, we only print info for DEBUG logs and print
|
||||||
@ -40,7 +48,11 @@ namespace Qv2ray::base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
QMutexLocker _(&__loggerMutex);
|
||||||
__loggerBuffer->append(logString + NEWLINE);
|
__loggerBuffer->append(logString + NEWLINE);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tiny log module.
|
* Tiny log module.
|
||||||
@ -18,7 +17,7 @@ namespace Qv2ray::base
|
|||||||
#define QV2RAY_LOG_NORMAL 0
|
#define QV2RAY_LOG_NORMAL 0
|
||||||
#define QV2RAY_LOG_DEBUG 1
|
#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 LOG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_NORMAL, (MODULE), (MSG));
|
||||||
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
|
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "3rdparty/x2struct/x2struct.hpp"
|
#include "libs/QJsonStruct/QJsonIO.hpp"
|
||||||
|
#include "libs/QJsonStruct/QJsonStruct.hpp"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
@ -7,13 +8,49 @@
|
|||||||
|
|
||||||
namespace Qv2ray::base::objects
|
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
|
// Used in config generation
|
||||||
struct AccountObject
|
struct AccountObject
|
||||||
{
|
{
|
||||||
QString user;
|
QString user;
|
||||||
QString pass;
|
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;
|
QString tag;
|
||||||
QList<QString> services;
|
QList<QString> services;
|
||||||
ApiObject() : tag("api"), services()
|
ApiObject() : tag("api"), services(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(ApiObject, F(tag, services))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(tag, services))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -32,10 +67,8 @@ namespace Qv2ray::base::objects
|
|||||||
{
|
{
|
||||||
bool statsInboundUplink;
|
bool statsInboundUplink;
|
||||||
bool statsInboundDownlink;
|
bool statsInboundDownlink;
|
||||||
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink()
|
SystemPolicyObject() : statsInboundUplink(), statsInboundDownlink(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(SystemPolicyObject, F(statsInboundUplink, statsInboundDownlink))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(statsInboundUplink, statsInboundDownlink))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -48,10 +81,8 @@ namespace Qv2ray::base::objects
|
|||||||
bool statsUserUplink;
|
bool statsUserUplink;
|
||||||
bool statsUserDownlink;
|
bool statsUserDownlink;
|
||||||
int bufferSize;
|
int bufferSize;
|
||||||
LevelPolicyObject() : handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize()
|
LevelPolicyObject() : handshake(), connIdle(), uplinkOnly(), downlinkOnly(), statsUserUplink(), statsUserDownlink(), bufferSize(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(LevelPolicyObject, F(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(handshake, connIdle, uplinkOnly, downlinkOnly, statsUserUplink, statsUserDownlink, bufferSize))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -59,10 +90,8 @@ namespace Qv2ray::base::objects
|
|||||||
{
|
{
|
||||||
QMap<QString, LevelPolicyObject> level;
|
QMap<QString, LevelPolicyObject> level;
|
||||||
QList<SystemPolicyObject> system;
|
QList<SystemPolicyObject> system;
|
||||||
PolicyObject() : level(), system()
|
PolicyObject() : level(), system(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(PolicyObject, F(level, system))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(level, system))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -87,11 +116,9 @@ namespace Qv2ray::base::objects
|
|||||||
QString balancerTag;
|
QString balancerTag;
|
||||||
RuleObject()
|
RuleObject()
|
||||||
: QV2RAY_RULE_ENABLED(true), QV2RAY_RULE_USE_BALANCER(false), QV2RAY_RULE_TAG("new rule"), type("field"), domain(), ip(),
|
: 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("")
|
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))
|
||||||
XTOSTRUCT(O(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;
|
QString tag;
|
||||||
QList<QString> selector;
|
QList<QString> selector;
|
||||||
BalancerObject() : tag(), selector()
|
BalancerObject() : tag(), selector(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(BalancerObject, F(tag, selector))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(tag, selector))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -114,10 +139,8 @@ namespace Qv2ray::base::objects
|
|||||||
QString method;
|
QString method;
|
||||||
QList<QString> path;
|
QList<QString> path;
|
||||||
QMap<QString, QList<QString>> headers;
|
QMap<QString, QList<QString>> headers;
|
||||||
HTTPRequestObject() : version("1.1"), method("GET"), path(), headers()
|
HTTPRequestObject() : version("1.1"), method("GET"), path(), headers(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(HTTPRequestObject, F(version, method, path, headers))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(version, method, path, headers))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -127,10 +150,8 @@ namespace Qv2ray::base::objects
|
|||||||
QString status;
|
QString status;
|
||||||
QString reason;
|
QString reason;
|
||||||
QMap<QString, QList<QString>> headers;
|
QMap<QString, QList<QString>> headers;
|
||||||
HTTPResponseObject() : version("1.1"), status("200"), reason("OK"), headers()
|
HTTPResponseObject() : version("1.1"), status("200"), reason("OK"), headers(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(HTTPResponseObject, F(version, status, reason, headers))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(version, status, reason, headers))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -139,30 +160,24 @@ namespace Qv2ray::base::objects
|
|||||||
QString type;
|
QString type;
|
||||||
HTTPRequestObject request;
|
HTTPRequestObject request;
|
||||||
HTTPResponseObject response;
|
HTTPResponseObject response;
|
||||||
TCPHeader_M_Object() : type("none"), request(), response()
|
TCPHeader_M_Object() : type("none"), request(), response(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(TCPHeader_M_Object, F(type, request, response))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(type, request, response))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct HeaderObject
|
struct HeaderObject
|
||||||
{
|
{
|
||||||
QString type;
|
QString type;
|
||||||
HeaderObject() : type("none")
|
HeaderObject() : type("none"){};
|
||||||
{
|
JSONSTRUCT_REGISTER(HeaderObject, F(type))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(type))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct TCPObject
|
struct TCPObject
|
||||||
{
|
{
|
||||||
TCPHeader_M_Object header;
|
TCPHeader_M_Object header;
|
||||||
TCPObject() : header()
|
TCPObject() : header(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(TCPObject, F(header))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(header))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -175,11 +190,11 @@ namespace Qv2ray::base::objects
|
|||||||
bool congestion = false;
|
bool congestion = false;
|
||||||
int readBufferSize = 1;
|
int readBufferSize = 1;
|
||||||
int writeBufferSize = 1;
|
int writeBufferSize = 1;
|
||||||
|
QString seed;
|
||||||
HeaderObject header;
|
HeaderObject header;
|
||||||
KCPObject() : header()
|
KCPObject() : header(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(KCPObject,
|
||||||
}
|
F(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header, seed))
|
||||||
XTOSTRUCT(O(mtu, tti, uplinkCapacity, downlinkCapacity, congestion, readBufferSize, writeBufferSize, header))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -187,10 +202,8 @@ namespace Qv2ray::base::objects
|
|||||||
{
|
{
|
||||||
QString path;
|
QString path;
|
||||||
QMap<QString, QString> headers;
|
QMap<QString, QString> headers;
|
||||||
WebSocketObject() : path("/"), headers()
|
WebSocketObject() : path("/"), headers(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(WebSocketObject, F(path, headers))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(path, headers))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -198,20 +211,16 @@ namespace Qv2ray::base::objects
|
|||||||
{
|
{
|
||||||
QList<QString> host;
|
QList<QString> host;
|
||||||
QString path;
|
QString path;
|
||||||
HttpObject() : host(), path("/")
|
HttpObject() : host(), path("/"){};
|
||||||
{
|
JSONSTRUCT_REGISTER(HttpObject, F(host, path))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(host, path))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
struct DomainSocketObject
|
struct DomainSocketObject
|
||||||
{
|
{
|
||||||
QString path;
|
QString path;
|
||||||
DomainSocketObject() : path("/")
|
DomainSocketObject() : path("/"){};
|
||||||
{
|
JSONSTRUCT_REGISTER(DomainSocketObject, F(path))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(path))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -220,10 +229,8 @@ namespace Qv2ray::base::objects
|
|||||||
QString security;
|
QString security;
|
||||||
QString key;
|
QString key;
|
||||||
HeaderObject header;
|
HeaderObject header;
|
||||||
QuicObject() : security(""), key(""), header()
|
QuicObject() : security(""), key(""), header(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(QuicObject, F(security, key, header))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(security, key, header))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -232,10 +239,8 @@ namespace Qv2ray::base::objects
|
|||||||
int mark;
|
int mark;
|
||||||
bool tcpFastOpen;
|
bool tcpFastOpen;
|
||||||
QString tproxy;
|
QString tproxy;
|
||||||
SockoptObject() : mark(0), tcpFastOpen(false), tproxy("off")
|
SockoptObject() : mark(0), tcpFastOpen(false), tproxy("off"){};
|
||||||
{
|
JSONSTRUCT_REGISTER(SockoptObject, F(mark, tcpFastOpen, tproxy))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(mark, tcpFastOpen, tproxy))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -246,10 +251,8 @@ namespace Qv2ray::base::objects
|
|||||||
QString keyFile;
|
QString keyFile;
|
||||||
QList<QString> certificate;
|
QList<QString> certificate;
|
||||||
QList<QString> key;
|
QList<QString> key;
|
||||||
CertificateObject() : usage(), certificateFile(), keyFile(), certificate(), key()
|
CertificateObject() : usage(), certificateFile(), keyFile(), certificate(), key(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(CertificateObject, F(usage, certificateFile, keyFile, certificate, key))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(usage, certificateFile, keyFile, certificate, key))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -258,13 +261,14 @@ namespace Qv2ray::base::objects
|
|||||||
QString serverName;
|
QString serverName;
|
||||||
bool allowInsecure;
|
bool allowInsecure;
|
||||||
bool allowInsecureCiphers;
|
bool allowInsecureCiphers;
|
||||||
|
bool disableSessionResumption;
|
||||||
QList<QString> alpn;
|
QList<QString> alpn;
|
||||||
QList<CertificateObject> certificates;
|
QList<CertificateObject> certificates;
|
||||||
bool disableSystemRoot;
|
bool disableSystemRoot;
|
||||||
TLSObject() : serverName(), allowInsecure(), allowInsecureCiphers(), certificates(), disableSystemRoot()
|
TLSObject()
|
||||||
{
|
: serverName(), allowInsecure(), allowInsecureCiphers(), disableSessionResumption(true), certificates(), disableSystemRoot(){};
|
||||||
}
|
JSONSTRUCT_REGISTER(TLSObject, F(serverName, allowInsecure, allowInsecureCiphers, disableSessionResumption, alpn, certificates,
|
||||||
XTOSTRUCT(O(serverName, allowInsecure, allowInsecureCiphers, alpn, certificates, disableSystemRoot))
|
disableSystemRoot))
|
||||||
};
|
};
|
||||||
} // namespace transfer
|
} // namespace transfer
|
||||||
//
|
//
|
||||||
@ -273,10 +277,8 @@ namespace Qv2ray::base::objects
|
|||||||
{
|
{
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
QList<QString> destOverride;
|
QList<QString> destOverride;
|
||||||
SniffingObject() : enabled(), destOverride()
|
SniffingObject() : enabled(), destOverride(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(SniffingObject, F(enabled, destOverride))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(enabled, destOverride))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -294,10 +296,9 @@ namespace Qv2ray::base::objects
|
|||||||
transfer::QuicObject quicSettings;
|
transfer::QuicObject quicSettings;
|
||||||
StreamSettingsObject()
|
StreamSettingsObject()
|
||||||
: network("tcp"), security("none"), sockopt(), tlsSettings(), tcpSettings(), kcpSettings(), wsSettings(), httpSettings(),
|
: network("tcp"), security("none"), sockopt(), tlsSettings(), tcpSettings(), kcpSettings(), wsSettings(), httpSettings(),
|
||||||
dsSettings(), quicSettings()
|
dsSettings(), quicSettings(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(StreamSettingsObject, F(network, security, sockopt, tcpSettings, tlsSettings, kcpSettings, wsSettings, httpSettings,
|
||||||
}
|
dsSettings, quicSettings))
|
||||||
XTOSTRUCT(O(network, security, sockopt, tcpSettings, tlsSettings, kcpSettings, wsSettings, httpSettings, dsSettings, quicSettings))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -305,10 +306,8 @@ namespace Qv2ray::base::objects
|
|||||||
{
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
int concurrency;
|
int concurrency;
|
||||||
MuxObject() : enabled(), concurrency()
|
MuxObject() : enabled(), concurrency(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(MuxObject, F(enabled, concurrency))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(enabled, concurrency))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// Some protocols from: https://v2ray.com/chapter_02/02_protocols.html
|
// Some protocols from: https://v2ray.com/chapter_02/02_protocols.html
|
||||||
@ -320,10 +319,8 @@ namespace Qv2ray::base::objects
|
|||||||
QString network;
|
QString network;
|
||||||
QString address;
|
QString address;
|
||||||
int port;
|
int port;
|
||||||
DNSOut() : network(""), address("0.0.0.0"), port(0)
|
DNSOut() : network(""), address("0.0.0.0"), port(0){};
|
||||||
{
|
JSONSTRUCT_REGISTER(DNSOut, F(network, address, port))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(network, address, port))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// MTProto, InBound || OutBound
|
// MTProto, InBound || OutBound
|
||||||
@ -334,13 +331,11 @@ namespace Qv2ray::base::objects
|
|||||||
QString email;
|
QString email;
|
||||||
int level;
|
int level;
|
||||||
QString secret;
|
QString secret;
|
||||||
UserObject() : email("user@domain.com"), level(0), secret("")
|
UserObject() : email("user@domain.com"), level(0), secret(""){};
|
||||||
{
|
JSONSTRUCT_REGISTER(UserObject, F(email, level, secret))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(email, level, secret))
|
|
||||||
};
|
};
|
||||||
QList<UserObject> users;
|
QList<UserObject> users;
|
||||||
XTOSTRUCT(O(users))
|
JSONSTRUCT_REGISTER(MTProtoIn, F(users))
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// Socks, OutBound
|
// Socks, OutBound
|
||||||
@ -351,19 +346,14 @@ namespace Qv2ray::base::objects
|
|||||||
QString user;
|
QString user;
|
||||||
QString pass;
|
QString pass;
|
||||||
int level;
|
int level;
|
||||||
UserObject() : user(), pass(), level(0)
|
UserObject() : user(), pass(), level(0){};
|
||||||
{
|
JSONSTRUCT_REGISTER(UserObject, F(user, pass, level))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(user, pass, level))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QString address;
|
QString address;
|
||||||
int port;
|
int port;
|
||||||
QList<UserObject> users;
|
QList<UserObject> users;
|
||||||
SocksServerObject() : address("0.0.0.0"), port(0), users()
|
SocksServerObject() : address("0.0.0.0"), port(0), users(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(SocksServerObject, F(address, port, users))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(address, port, users))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// VMess Server
|
// VMess Server
|
||||||
@ -375,19 +365,16 @@ namespace Qv2ray::base::objects
|
|||||||
int alterId;
|
int alterId;
|
||||||
QString security;
|
QString security;
|
||||||
int level;
|
int level;
|
||||||
UserObject() : id(""), alterId(64), security("auto"), level(0)
|
QString testsEnabled;
|
||||||
{
|
UserObject() : id(), alterId(64), security("auto"), level(0), testsEnabled("none"){};
|
||||||
}
|
JSONSTRUCT_REGISTER(UserObject, F(id, alterId, security, level, testsEnabled))
|
||||||
XTOSTRUCT(O(id, alterId, security, level))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QString address;
|
QString address;
|
||||||
int port;
|
int port;
|
||||||
QList<UserObject> users;
|
QList<UserObject> users;
|
||||||
VMessServerObject() : address(""), port(0), users()
|
VMessServerObject() : address(""), port(0), users(){};
|
||||||
{
|
JSONSTRUCT_REGISTER(VMessServerObject, F(address, port, users))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(address, port, users))
|
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// ShadowSocks Server
|
// ShadowSocks Server
|
||||||
@ -401,10 +388,8 @@ namespace Qv2ray::base::objects
|
|||||||
int level;
|
int level;
|
||||||
int port;
|
int port;
|
||||||
ShadowSocksServerObject()
|
ShadowSocksServerObject()
|
||||||
: email("user@domain.com"), address("0.0.0.0"), method("aes-256-cfb"), password(""), ota(false), level(0), port(0)
|
: 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))
|
||||||
}
|
|
||||||
XTOSTRUCT(O(email, address, port, method, password, ota, level))
|
|
||||||
};
|
};
|
||||||
} // namespace protocol
|
} // namespace protocol
|
||||||
} // namespace Qv2ray::base::objects
|
} // namespace Qv2ray::base::objects
|
||||||
|
@ -1,52 +1,180 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "3rdparty/x2struct/x2struct.hpp"
|
#include "QvCoreSettings.hpp"
|
||||||
|
#include "libs/QJsonStruct/QJsonStruct.hpp"
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QHashFunctions>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
|
|
||||||
namespace Qv2ray::base
|
namespace Qv2ray::base
|
||||||
{
|
{
|
||||||
constexpr unsigned int QVTCPING_VALUE_ERROR = 99999;
|
template<typename T>
|
||||||
constexpr unsigned int QVTCPING_VALUE_NODATA = QVTCPING_VALUE_ERROR - 1;
|
class IDType
|
||||||
using namespace std::chrono;
|
|
||||||
// Common struct for Groups and Subscriptions
|
|
||||||
struct GroupObject_Config
|
|
||||||
{
|
{
|
||||||
QString displayName;
|
public:
|
||||||
QList<QString> connections;
|
explicit IDType() : m_id("null"){};
|
||||||
int64_t importDate;
|
explicit IDType(const QString &id) : m_id(id){};
|
||||||
GroupObject_Config() : displayName(), connections(), importDate()
|
friend bool operator==(const IDType<T> &lhs, const IDType<T> &rhs)
|
||||||
{
|
{
|
||||||
|
return lhs.m_id == rhs.m_id;
|
||||||
}
|
}
|
||||||
XTOSTRUCT(O(displayName, connections, importDate))
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SubscriptionObject_Config : GroupObject_Config
|
// 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;
|
||||||
//
|
//
|
||||||
QString address;
|
inline const static auto NullConnectionId = ConnectionId("null");
|
||||||
int64_t lastUpdated;
|
inline const static auto NullGroupId = GroupId("null");
|
||||||
float updateInterval;
|
inline const static auto NullRoutingId = GroupRoutingId("null");
|
||||||
SubscriptionObject_Config() : address(""), lastUpdated(system_clock::to_time_t(system_clock::now())), updateInterval(10)
|
//
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
XTOSTRUCT(O(lastUpdated, updateInterval, address, connections, displayName, importDate))
|
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;
|
||||||
|
|
||||||
struct ConnectionObject_Config
|
struct __Qv2rayConfigObjectBase
|
||||||
{
|
{
|
||||||
QString displayName;
|
QString displayName;
|
||||||
int64_t importDate;
|
qint64 creationDate;
|
||||||
int64_t lastConnected;
|
qint64 lastUpdatedDate;
|
||||||
int64_t latency;
|
__Qv2rayConfigObjectBase()
|
||||||
int64_t upLinkData;
|
: displayName(), creationDate(system_clock::to_time_t(system_clock::now())), //
|
||||||
int64_t downLinkData;
|
lastUpdatedDate(system_clock::to_time_t(system_clock::now())){}; //
|
||||||
ConnectionObject_Config()
|
JSONSTRUCT_REGISTER(__Qv2rayConfigObjectBase, F(displayName, creationDate, lastUpdatedDate))
|
||||||
: 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))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GroupRoutingConfig : __Qv2rayConfigObjectBase
|
||||||
|
{
|
||||||
|
bool overrideDNS;
|
||||||
|
config::QvConfig_DNS dnsConfig;
|
||||||
|
//
|
||||||
|
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))
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SubscriptionFilterRelation
|
||||||
|
{
|
||||||
|
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
|
} // namespace Qv2ray::base
|
||||||
|
|
||||||
using 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
|
struct Qv2rayRuntimeConfig
|
||||||
{
|
{
|
||||||
bool screenShotHideQv2ray = false;
|
bool screenShotHideQv2ray = false;
|
||||||
|
bool deepinHorribleProxyHint = false;
|
||||||
};
|
};
|
||||||
inline base::Qv2rayRuntimeConfig RuntimeConfig = base::Qv2rayRuntimeConfig();
|
inline base::Qv2rayRuntimeConfig RuntimeConfig = base::Qv2rayRuntimeConfig();
|
||||||
} // namespace Qv2ray::base
|
} // namespace Qv2ray::base
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#define nothing
|
#define nothing
|
||||||
#define SAFE_TYPEDEF(Base, name) SAFE_TYPEDEF_EXTRA(Base, name, nothing)
|
#define SAFE_TYPEDEF(Base, name) SAFE_TYPEDEF_EXTRA(Base, name, nothing)
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
namespace Qv2ray::base::safetype
|
namespace Qv2ray::base::safetype
|
||||||
{
|
{
|
||||||
// To prevent anonying QJsonObject misuse
|
// To prevent anonying QJsonObject misuse
|
||||||
|
@ -1,210 +1,54 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "3rdparty/x2struct/x2struct.hpp"
|
|
||||||
#include "base/models/CoreObjectModels.hpp"
|
|
||||||
#include "base/models/QvConfigIdentifier.hpp"
|
#include "base/models/QvConfigIdentifier.hpp"
|
||||||
|
#include "base/models/QvCoreSettings.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
const int QV2RAY_CONFIG_VERSION = 11;
|
constexpr int QV2RAY_CONFIG_VERSION = 14;
|
||||||
|
|
||||||
namespace Qv2ray::base::config
|
namespace Qv2ray::base::config
|
||||||
{
|
{
|
||||||
struct QvBarLine
|
struct Qv2rayConfig_UI
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
QString theme;
|
QString theme;
|
||||||
QString language;
|
QString language;
|
||||||
QList<QString> recentConnections;
|
QList<ConnectionGroupPair> recentConnections;
|
||||||
bool quietMode;
|
bool quietMode;
|
||||||
bool useDarkTheme;
|
bool useDarkTheme;
|
||||||
bool useDarkTrayIcon;
|
bool useDarkTrayIcon;
|
||||||
int maximumLogLines;
|
int maximumLogLines;
|
||||||
int maxJumpListCount;
|
int maxJumpListCount;
|
||||||
Qv2rayUIConfig()
|
Qv2rayConfig_UI()
|
||||||
: theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500), maxJumpListCount(20)
|
: 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))
|
||||||
XTOSTRUCT(O(theme, language, quietMode, useDarkTheme, useDarkTrayIcon, maximumLogLines, maxJumpListCount, recentConnections))
|
|
||||||
};
|
};
|
||||||
|
struct Qv2rayConfig_Plugin
|
||||||
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
|
|
||||||
{
|
{
|
||||||
QMap<QString, bool> pluginStates;
|
QMap<QString, bool> pluginStates;
|
||||||
bool v2rayIntegration;
|
bool v2rayIntegration;
|
||||||
int portAllocationStart;
|
int portAllocationStart;
|
||||||
Qv2rayPluginConfig() : pluginStates(), v2rayIntegration(true), portAllocationStart(15000){};
|
Qv2rayConfig_Plugin() : pluginStates(), v2rayIntegration(true), portAllocationStart(15000){};
|
||||||
XTOSTRUCT(O(pluginStates, v2rayIntegration))
|
JSONSTRUCT_REGISTER(Qv2rayConfig_Plugin, F(pluginStates, v2rayIntegration, portAllocationStart))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayConnectionConfig
|
struct Qv2rayConfig_Kernel
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
bool enableAPI;
|
bool enableAPI;
|
||||||
int statsPort;
|
int statsPort;
|
||||||
Qv2rayAPIConfig() : enableAPI(true), statsPort(15490)
|
//
|
||||||
{
|
|
||||||
}
|
|
||||||
XTOSTRUCT(O(enableAPI, statsPort))
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Qv2rayKernelConfig
|
|
||||||
{
|
|
||||||
QString v2CorePath_linux;
|
QString v2CorePath_linux;
|
||||||
QString v2AssetsPath_linux;
|
QString v2AssetsPath_linux;
|
||||||
QString v2CorePath_macx;
|
QString v2CorePath_macx;
|
||||||
QString v2AssetsPath_macx;
|
QString v2AssetsPath_macx;
|
||||||
QString v2CorePath_win;
|
QString v2CorePath_win;
|
||||||
QString v2AssetsPath_win; //
|
QString v2AssetsPath_win;
|
||||||
Qv2rayKernelConfig()
|
Qv2rayConfig_Kernel()
|
||||||
: v2CorePath_linux(), v2AssetsPath_linux(), //
|
: enableAPI(true), statsPort(15490), //
|
||||||
|
v2CorePath_linux(), v2AssetsPath_linux(), //
|
||||||
v2CorePath_macx(), v2AssetsPath_macx(), //
|
v2CorePath_macx(), v2AssetsPath_macx(), //
|
||||||
v2CorePath_win(), v2AssetsPath_win() //
|
v2CorePath_win(), v2AssetsPath_win() //
|
||||||
{
|
{};
|
||||||
}
|
|
||||||
//
|
//
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#define _VARNAME_VCOREPATH_ v2CorePath_linux
|
#define _VARNAME_VCOREPATH_ v2CorePath_linux
|
||||||
@ -229,10 +73,14 @@ namespace Qv2ray::base::config
|
|||||||
#undef _VARNAME_VCOREPATH_
|
#undef _VARNAME_VCOREPATH_
|
||||||
#undef _VARNAME_VASSETSPATH_
|
#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;
|
QString ignoredVersion;
|
||||||
///
|
///
|
||||||
@ -240,105 +88,96 @@ namespace Qv2ray::base::config
|
|||||||
/// 0: Stable
|
/// 0: Stable
|
||||||
/// 1: Testing
|
/// 1: Testing
|
||||||
int updateChannel;
|
int updateChannel;
|
||||||
XTOSTRUCT(O(ignoredVersion, updateChannel))
|
JSONSTRUCT_REGISTER(Qv2rayConfig_Update, F(ignoredVersion, updateChannel))
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qv2rayAdvancedConfig
|
struct Qv2rayConfig_Advanced
|
||||||
{
|
{
|
||||||
bool setAllowInsecure;
|
bool setAllowInsecure;
|
||||||
bool setAllowInsecureCiphers;
|
bool setSessionResumption;
|
||||||
bool testLatencyPeriodcally;
|
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
|
||||||
{
|
{
|
||||||
QVPROXY_NONE,
|
Qv2rayLatencyTestingMethod latencyTestingMethod;
|
||||||
QVPROXY_SYSTEM,
|
enum Qv2rayProxyType : int
|
||||||
QVPROXY_CUSTOM
|
{
|
||||||
|
QVPROXY_NONE = 0,
|
||||||
|
QVPROXY_SYSTEM = 1,
|
||||||
|
QVPROXY_CUSTOM = 2
|
||||||
} proxyType;
|
} proxyType;
|
||||||
|
|
||||||
QString address;
|
QString address;
|
||||||
QString type;
|
QString type;
|
||||||
int port;
|
int port;
|
||||||
QString userAgent;
|
QString userAgent;
|
||||||
Qv2rayNetworkConfig()
|
Qv2rayConfig_Network()
|
||||||
: proxyType(QVPROXY_NONE), //
|
: proxyType(QVPROXY_NONE), //
|
||||||
address("127.0.0.1"), //
|
address("127.0.0.1"), //
|
||||||
type("http"), //
|
type("http"), //
|
||||||
port(8000), //
|
port(8000), //
|
||||||
userAgent("Qv2ray/$VERSION WebRequestHelper"){};
|
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;
|
int config_version;
|
||||||
bool tProxySupport;
|
bool tProxySupport;
|
||||||
int logLevel;
|
int logLevel;
|
||||||
//
|
//
|
||||||
QString autoStartId;
|
ConnectionGroupPair autoStartId;
|
||||||
|
ConnectionGroupPair lastConnectedId;
|
||||||
|
Qv2rayAutoConnectionBehavior autoStartBehavior;
|
||||||
//
|
//
|
||||||
// Key = groupId, connectionId
|
// Key = groupId, connectionId
|
||||||
QMap<QString, GroupObject_Config> groups;
|
// QList<GroupId> groups;
|
||||||
QMap<QString, SubscriptionObject_Config> subscriptions;
|
// QList<ConnectionId> connections;
|
||||||
/// Connections are used privately.
|
|
||||||
QMap<QString, ConnectionObject_Config> connections;
|
|
||||||
//
|
//
|
||||||
Qv2rayUIConfig uiConfig;
|
Qv2rayConfig_UI uiConfig;
|
||||||
Qv2rayAPIConfig apiConfig;
|
Qv2rayConfig_Plugin pluginConfig;
|
||||||
Qv2rayPluginConfig pluginConfig;
|
Qv2rayConfig_Kernel kernelConfig;
|
||||||
Qv2rayKernelConfig kernelConfig;
|
Qv2rayConfig_Update updateConfig;
|
||||||
Qv2rayUpdateConfig updateConfig;
|
Qv2rayConfig_Network networkConfig;
|
||||||
Qv2rayNetworkConfig networkConfig;
|
QvConfig_Inbounds inboundConfig;
|
||||||
Qv2rayToolBarConfig toolBarConfig;
|
QvConfig_Outbounds outboundConfig;
|
||||||
Qv2rayInboundsConfig inboundConfig;
|
Qv2rayConfig_Advanced advancedConfig;
|
||||||
Qv2rayOutboundsConfig outboundConfig;
|
GroupRoutingConfig defaultRouteConfig;
|
||||||
Qv2rayAdvancedConfig advancedConfig;
|
|
||||||
Qv2rayConnectionConfig connectionConfig;
|
|
||||||
|
|
||||||
Qv2rayConfig()
|
Qv2rayConfigObject()
|
||||||
: config_version(QV2RAY_CONFIG_VERSION), //
|
: config_version(QV2RAY_CONFIG_VERSION), //
|
||||||
tProxySupport(false), //
|
tProxySupport(false), //
|
||||||
logLevel(), //
|
logLevel(), //
|
||||||
autoStartId("null"), //
|
autoStartId(), //
|
||||||
groups(), //
|
autoStartBehavior(), //
|
||||||
subscriptions(), //
|
|
||||||
connections(), //
|
|
||||||
uiConfig(), //
|
uiConfig(), //
|
||||||
apiConfig(), //
|
|
||||||
pluginConfig(), //
|
pluginConfig(), //
|
||||||
kernelConfig(), //
|
kernelConfig(), //
|
||||||
updateConfig(), //
|
updateConfig(), //
|
||||||
networkConfig(), //
|
networkConfig(), //
|
||||||
toolBarConfig(), //
|
|
||||||
inboundConfig(), //
|
inboundConfig(), //
|
||||||
outboundConfig(), //
|
outboundConfig(), //
|
||||||
advancedConfig(), //
|
advancedConfig(), //
|
||||||
connectionConfig()
|
defaultRouteConfig(){};
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
XTOSTRUCT(O(config_version, //
|
JSONSTRUCT_REGISTER(Qv2rayConfigObject, //
|
||||||
tProxySupport, //
|
F(config_version, tProxySupport, autoStartId, lastConnectedId, autoStartBehavior, logLevel), //
|
||||||
logLevel, //
|
F(uiConfig, advancedConfig, pluginConfig, updateConfig, kernelConfig, networkConfig), //
|
||||||
uiConfig, //
|
F(inboundConfig, outboundConfig, defaultRouteConfig))
|
||||||
pluginConfig, //
|
|
||||||
updateConfig, //
|
|
||||||
kernelConfig, //
|
|
||||||
networkConfig, //
|
|
||||||
groups, //
|
|
||||||
connections, //
|
|
||||||
subscriptions, //
|
|
||||||
autoStartId, //
|
|
||||||
inboundConfig, //
|
|
||||||
outboundConfig, //
|
|
||||||
connectionConfig, //
|
|
||||||
toolBarConfig, //
|
|
||||||
advancedConfig, //
|
|
||||||
apiConfig //
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
} // namespace Qv2ray::base::config
|
} // namespace Qv2ray::base::config
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Qv2ray
|
namespace Qv2ray::base
|
||||||
{
|
{
|
||||||
namespace base
|
|
||||||
{
|
|
||||||
struct QvStartupOptions
|
struct QvStartupOptions
|
||||||
{
|
{
|
||||||
/// No API subsystem
|
/// No API subsystem
|
||||||
bool noAPI;
|
bool noAPI;
|
||||||
/// Explicitly run as root user.
|
|
||||||
bool forceRunAsRootUser;
|
|
||||||
/// Enable Debug Log.
|
/// Enable Debug Log.
|
||||||
bool debugLog;
|
bool debugLog;
|
||||||
/// Enable Network toolbar plugin.
|
|
||||||
bool enableToolbarPlguin;
|
|
||||||
/// Disable Qt scale factors support.
|
/// Disable Qt scale factors support.
|
||||||
bool noScaleFactors;
|
bool noScaleFactor;
|
||||||
|
|
||||||
/// Disable all plugin features.
|
/// Disable all plugin features.
|
||||||
bool noPlugins;
|
bool noPlugins;
|
||||||
|
|
||||||
|
/// Exit existing Qv2ray instance
|
||||||
|
bool exitQv2ray;
|
||||||
|
|
||||||
|
///
|
||||||
};
|
};
|
||||||
} // namespace base
|
} // namespace Qv2ray::base
|
||||||
inline base::QvStartupOptions StartupOption = base::QvStartupOptions();
|
|
||||||
} // namespace Qv2ray
|
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 <QByteArray>
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common::network
|
||||||
{
|
{
|
||||||
QvHttpRequestHelper::QvHttpRequestHelper(QObject *parent) : QObject(parent), reply()
|
void NetworkRequestHelper::setHeader(QNetworkRequest &request, const QByteArray &key, const QByteArray &value)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QvHttpRequestHelper::~QvHttpRequestHelper()
|
|
||||||
{
|
|
||||||
accessManager.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QvHttpRequestHelper::setHeader(const QByteArray &key, const QByteArray &value)
|
|
||||||
{
|
{
|
||||||
DEBUG(MODULE_NETWORK, "Adding HTTP request header: " + key + ":" + value)
|
DEBUG(MODULE_NETWORK, "Adding HTTP request header: " + key + ":" + value)
|
||||||
request.setRawHeader(key, value);
|
request.setRawHeader(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvHttpRequestHelper::setAccessManagerAttributes(QNetworkAccessManager &accessManager)
|
void NetworkRequestHelper::setAccessManagerAttributes(QNetworkRequest &request, QNetworkAccessManager &accessManager)
|
||||||
{
|
{
|
||||||
switch (GlobalConfig.networkConfig.proxyType)
|
switch (GlobalConfig.networkConfig.proxyType)
|
||||||
{
|
{
|
||||||
case Qv2rayNetworkConfig::QVPROXY_NONE:
|
case Qv2rayConfig_Network::QVPROXY_NONE:
|
||||||
{
|
{
|
||||||
DEBUG(MODULE_NETWORK, "Get without proxy.")
|
DEBUG(MODULE_NETWORK, "Get without proxy.")
|
||||||
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
|
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qv2rayNetworkConfig::QVPROXY_SYSTEM:
|
case Qv2rayConfig_Network::QVPROXY_SYSTEM:
|
||||||
{
|
{
|
||||||
accessManager.setProxy(QNetworkProxyFactory::systemProxyForQuery().first());
|
accessManager.setProxy(QNetworkProxyFactory::systemProxyForQuery().first());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qv2rayNetworkConfig::QVPROXY_CUSTOM:
|
case Qv2rayConfig_Network::QVPROXY_CUSTOM:
|
||||||
{
|
{
|
||||||
QNetworkProxy p{
|
QNetworkProxy p{
|
||||||
GlobalConfig.networkConfig.type == "http" ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy, //
|
GlobalConfig.networkConfig.type == "http" ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy, //
|
||||||
@ -47,6 +38,7 @@ namespace Qv2ray::common
|
|||||||
accessManager.setProxy(p);
|
accessManager.setProxy(p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy)
|
if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy)
|
||||||
@ -56,59 +48,60 @@ namespace Qv2ray::common
|
|||||||
}
|
}
|
||||||
|
|
||||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
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;
|
auto ua = GlobalConfig.networkConfig.userAgent;
|
||||||
ua.replace("$VERSION", QV2RAY_VERSION_STRING);
|
ua.replace("$VERSION", QV2RAY_VERSION_STRING);
|
||||||
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, ua);
|
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, ua);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray QvHttpRequestHelper::Get(const QString &url)
|
QByteArray NetworkRequestHelper::HttpGet(const QUrl &url)
|
||||||
{
|
{
|
||||||
request.setUrl({ url });
|
QNetworkRequest request;
|
||||||
setAccessManagerAttributes(accessManager);
|
QNetworkAccessManager accessManager;
|
||||||
|
request.setUrl(url);
|
||||||
|
setAccessManagerAttributes(request, accessManager);
|
||||||
auto _reply = accessManager.get(request);
|
auto _reply = accessManager.get(request);
|
||||||
//
|
//
|
||||||
|
{
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
connect(_reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
QObject::connect(&accessManager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Data or timeout?
|
// Data or timeout?
|
||||||
|
LOG(MODULE_NETWORK, _reply->errorString());
|
||||||
auto data = _reply->readAll();
|
auto data = _reply->readAll();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvHttpRequestHelper::AsyncGet(const QString &url)
|
void NetworkRequestHelper::AsyncHttpGet(const QString &url, std::function<void(const QByteArray &)> funcPtr)
|
||||||
{
|
{
|
||||||
request.setUrl({ url });
|
QNetworkRequest request;
|
||||||
setAccessManagerAttributes(accessManager);
|
request.setUrl(url);
|
||||||
reply = accessManager.get(request);
|
setAccessManagerAttributes(request, accessManager);
|
||||||
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
|
auto reply = accessManager.get(request);
|
||||||
connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead_p);
|
QObject::connect(reply, &QNetworkReply::finished, [=]() {
|
||||||
}
|
|
||||||
|
|
||||||
void QvHttpRequestHelper::onRequestFinished_p()
|
|
||||||
{
|
|
||||||
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool())
|
|
||||||
{
|
{
|
||||||
|
#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.")
|
DEBUG(MODULE_NETWORK, "HTTP/2 was used.")
|
||||||
}
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError)
|
if (reply->error() != QNetworkReply::NoError)
|
||||||
{
|
LOG(MODULE_NETWORK, "Network error: " + QString(QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error())))
|
||||||
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
|
|
||||||
LOG(MODULE_NETWORK, "Network request error string: " + error)
|
funcPtr(reply->readAll());
|
||||||
QByteArray empty;
|
|
||||||
emit OnRequestFinished(empty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit OnRequestFinished(this->data);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void QvHttpRequestHelper::onReadyRead_p()
|
} // namespace Qv2ray::common::network
|
||||||
{
|
|
||||||
DEBUG(MODULE_NETWORK, "A request is now ready read")
|
|
||||||
this->data += reply->readAll();
|
|
||||||
}
|
|
||||||
} // namespace Qv2ray::common
|
|
||||||
|
@ -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
|
#pragma once
|
||||||
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common::network
|
||||||
{
|
{
|
||||||
class QvHttpRequestHelper : public QObject
|
class NetworkRequestHelper : QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QvHttpRequestHelper(QObject *parent = nullptr);
|
explicit NetworkRequestHelper(QObject *parent) : QObject(parent){};
|
||||||
~QvHttpRequestHelper();
|
~NetworkRequestHelper(){};
|
||||||
// get
|
void AsyncHttpGet(const QString &url, std::function<void(const QByteArray &)> funcPtr);
|
||||||
void AsyncGet(const QString &url);
|
static QByteArray HttpGet(const QUrl &url);
|
||||||
QByteArray Get(const QString &url);
|
|
||||||
signals:
|
|
||||||
void OnRequestFinished(QByteArray &data);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onRequestFinished_p();
|
|
||||||
void onReadyRead_p();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setAccessManagerAttributes(QNetworkAccessManager &accessManager);
|
static void setAccessManagerAttributes(QNetworkRequest &request, QNetworkAccessManager &accessManager);
|
||||||
void setHeader(const QByteArray &key, const QByteArray &value);
|
static void setHeader(QNetworkRequest &request, const QByteArray &key, const QByteArray &value);
|
||||||
QByteArray data;
|
|
||||||
QUrl url;
|
|
||||||
QNetworkReply *reply;
|
|
||||||
QNetworkRequest request;
|
|
||||||
QNetworkAccessManager accessManager;
|
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 <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFont>
|
|
||||||
|
|
||||||
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
|
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
|
||||||
{
|
{
|
||||||
|
@ -25,12 +25,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QIcon>
|
#include <QByteArray>
|
||||||
|
#include <QIODevice>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
|
||||||
class QJsonModel;
|
class QJsonModel;
|
||||||
class QJsonItem;
|
class QJsonItem;
|
||||||
|
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "libs/puresource/src/PureJson.hpp"
|
#include "libs/puresource/src/PureJson.hpp"
|
||||||
|
|
||||||
#include <QGraphicsEffect>
|
|
||||||
#include <QGraphicsProxyWidget>
|
|
||||||
#include <QGraphicsScene>
|
|
||||||
#include <QGraphicsView>
|
|
||||||
#include <QQueue>
|
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
const QString GenerateRandomString(int len)
|
const QString GenerateRandomString(int len)
|
||||||
{
|
{
|
||||||
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
const QString possibleCharacters("abcdefghijklmnopqrstuvwxyz");
|
||||||
QString randomString;
|
QString randomString;
|
||||||
|
|
||||||
for (int i = 0; i < len; ++i)
|
for (int i = 0; i < len; ++i)
|
||||||
@ -41,39 +36,31 @@ namespace Qv2ray::common
|
|||||||
if (!wasOpened)
|
if (!wasOpened)
|
||||||
source.close();
|
source.close();
|
||||||
//
|
//
|
||||||
QTextCodec::ConverterState state;
|
|
||||||
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
||||||
|
QTextCodec::ConverterState state;
|
||||||
const QString text = codec->toUnicode(byteArray.constData(), byteArray.size(), &state);
|
const QString text = codec->toUnicode(byteArray.constData(), byteArray.size(), &state);
|
||||||
if (state.invalidChars > 0)
|
if (state.invalidChars > 0)
|
||||||
{
|
{
|
||||||
LOG(MODULE_FILEIO, "Not a valid UTF-8 sequence: " + source.fileName())
|
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)
|
bool StringToFile(const QString &text, const QString &targetpath)
|
||||||
{
|
{
|
||||||
auto file = QFile(targetpath);
|
bool override = false;
|
||||||
return StringToFile(text, file);
|
|
||||||
}
|
|
||||||
bool StringToFile(const QString &text, QFile &targetFile)
|
|
||||||
{
|
|
||||||
QFileInfo info(targetFile);
|
|
||||||
if (!info.dir().exists())
|
|
||||||
{
|
{
|
||||||
|
QFileInfo info(targetpath);
|
||||||
|
override = info.exists();
|
||||||
|
if (!override && !info.dir().exists())
|
||||||
info.dir().mkpath(info.dir().path());
|
info.dir().mkpath(info.dir().path());
|
||||||
}
|
}
|
||||||
bool override = targetFile.exists();
|
QSaveFile f{ targetpath };
|
||||||
targetFile.open(QFile::WriteOnly);
|
f.open(QIODevice::WriteOnly);
|
||||||
targetFile.write(text.toUtf8());
|
f.write(text.toUtf8());
|
||||||
targetFile.close();
|
f.commit();
|
||||||
return override;
|
return override;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString JsonToString(const QJsonObject &json, QJsonDocument::JsonFormat format)
|
QString JsonToString(const QJsonObject &json, QJsonDocument::JsonFormat format)
|
||||||
{
|
{
|
||||||
QJsonDocument doc;
|
QJsonDocument doc;
|
||||||
@ -116,6 +103,31 @@ namespace Qv2ray::common
|
|||||||
return doc.object();
|
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)
|
QString Base64Encode(const QString &string)
|
||||||
{
|
{
|
||||||
QByteArray ba = string.toUtf8();
|
QByteArray ba = string.toUtf8();
|
||||||
@ -130,19 +142,11 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
QStringList SplitLines(const QString &_string)
|
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);
|
return _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
|
||||||
}
|
#endif
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList GetFileList(const QDir &dir)
|
QStringList GetFileList(const QDir &dir)
|
||||||
@ -155,22 +159,6 @@ namespace Qv2ray::common
|
|||||||
return GetFileList(dir).contains(fileName);
|
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)
|
QString FormatBytes(const int64_t b)
|
||||||
{
|
{
|
||||||
auto _bytes = b;
|
auto _bytes = b;
|
||||||
@ -195,7 +183,7 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
std::string _name = fileName.toStdString();
|
std::string _name = fileName.toStdString();
|
||||||
std::replace_if(
|
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);
|
return QString::fromStdString(_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,38 +213,20 @@ namespace Qv2ray::common
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QPixmap ApplyEffectToImage(QPixmap src, QGraphicsEffect *effect, int extent)
|
|
||||||
|
void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text)
|
||||||
{
|
{
|
||||||
constexpr int extent2 = 0;
|
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap ColorizeImage(const QPixmap &pixmap, const QColor &color, const qreal factor)
|
void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text)
|
||||||
{
|
{
|
||||||
QGraphicsColorizeEffect pColor;
|
QMessageBox::information(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
|
||||||
pColor.setColor(color);
|
|
||||||
pColor.setStrength(factor);
|
|
||||||
return ApplyEffectToImage(pixmap, &pColor, 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
|
} // namespace Qv2ray::common
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include <QDateTime>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QJsonDocument>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#define REGEX_IPV6_ADDR \
|
#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*\])"
|
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
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
QStringList GetFileList(const QDir &dir);
|
QStringList GetFileList(const QDir &dir);
|
||||||
|
|
||||||
|
QString SafeBase64Decode(QString string);
|
||||||
|
QString SafeBase64Encode(const QString &string, bool trim);
|
||||||
|
|
||||||
QString Base64Encode(const QString &string);
|
QString Base64Encode(const QString &string);
|
||||||
QString Base64Decode(const QString &string);
|
QString Base64Decode(const QString &string);
|
||||||
QStringList SplitLines(const QString &str);
|
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);
|
bool FileExistsIn(const QDir &dir, const QString &fileName);
|
||||||
const QString GenerateRandomString(int len = 12);
|
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(const QString &filePath);
|
||||||
QString StringFromFile(QFile &source);
|
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);
|
bool StringToFile(const QString &text, const QString &targetpath);
|
||||||
//
|
//
|
||||||
QJsonObject JsonFromString(const QString &string);
|
QJsonObject JsonFromString(const QString &string);
|
||||||
@ -38,9 +41,6 @@ namespace Qv2ray::common
|
|||||||
QString FormatBytes(const int64_t bytes);
|
QString FormatBytes(const int64_t bytes);
|
||||||
void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension);
|
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.
|
// This function cannot be marked as inline.
|
||||||
QString RemoveInvalidFileName(const QString &fileName);
|
QString RemoveInvalidFileName(const QString &fileName);
|
||||||
bool IsValidFileName(const QString &fileName);
|
bool IsValidFileName(const QString &fileName);
|
||||||
@ -49,27 +49,6 @@ namespace Qv2ray::common
|
|||||||
return GenerateRandomString().toLower();
|
return GenerateRandomString().toLower();
|
||||||
// return QUuid::createUuid().toString(QUuid::WithoutBraces);
|
// 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 = "...")
|
inline QString TruncateString(const QString &str, int limit = -1, const QString &suffix = "...")
|
||||||
{
|
{
|
||||||
@ -81,7 +60,6 @@ namespace Qv2ray::common
|
|||||||
namespace validation
|
namespace validation
|
||||||
{
|
{
|
||||||
const inline QRegularExpression __regex_ipv4_full(REGEX_IPV4_ADDR "$");
|
const inline QRegularExpression __regex_ipv4_full(REGEX_IPV4_ADDR "$");
|
||||||
const inline QRegularExpression __regex_ipv6_full(REGEX_IPV6_ADDR "$");
|
|
||||||
|
|
||||||
inline bool IsIPv4Address(const QString &addr)
|
inline bool IsIPv4Address(const QString &addr)
|
||||||
{
|
{
|
||||||
@ -90,12 +68,22 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
inline bool IsIPv6Address(const QString &addr)
|
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)
|
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
|
} // namespace validation
|
||||||
|
|
||||||
@ -103,18 +91,12 @@ namespace Qv2ray::common
|
|||||||
{
|
{
|
||||||
QDateTime timestamp;
|
QDateTime timestamp;
|
||||||
timestamp.setSecsSinceEpoch(t);
|
timestamp.setSecsSinceEpoch(t);
|
||||||
return timestamp.toString(Qt::SystemLocaleShortDate);
|
return timestamp.toString();
|
||||||
}
|
|
||||||
|
|
||||||
inline void FastAppendTextDocument(const QString &message, QTextDocument *doc)
|
|
||||||
{
|
|
||||||
QTextCursor cursor(doc);
|
|
||||||
cursor.movePosition(QTextCursor::End);
|
|
||||||
cursor.beginEditBlock();
|
|
||||||
cursor.insertBlock();
|
|
||||||
cursor.insertText(message);
|
|
||||||
cursor.endEditBlock();
|
|
||||||
}
|
}
|
||||||
|
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
|
} // namespace Qv2ray::common
|
||||||
|
|
||||||
using namespace Qv2ray::common;
|
using namespace Qv2ray::common;
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
#include "QvTranslator.hpp"
|
#include "QvTranslator.hpp"
|
||||||
|
|
||||||
#include "base/Qv2rayLog.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringBuilder>
|
|
||||||
#include <QTranslator>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace Qv2ray::base;
|
using namespace Qv2ray::base;
|
||||||
|
|
||||||
// path searching list.
|
// path searching list.
|
||||||
@ -27,20 +19,19 @@ QStringList getLanguageSearchPaths()
|
|||||||
list << QString(QV2RAY_TRANSLATION_PATH);
|
list << QString(QV2RAY_TRANSLATION_PATH);
|
||||||
#endif
|
#endif
|
||||||
return list;
|
return list;
|
||||||
};
|
}
|
||||||
|
|
||||||
namespace Qv2ray::common
|
namespace Qv2ray::common
|
||||||
{
|
{
|
||||||
QvTranslator::QvTranslator()
|
QvTranslator::QvTranslator()
|
||||||
{
|
{
|
||||||
DEBUG(MODULE_UI, "QvTranslator constructor.")
|
|
||||||
GetAvailableLanguages();
|
GetAvailableLanguages();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QvTranslator::GetAvailableLanguages()
|
QStringList QvTranslator::GetAvailableLanguages()
|
||||||
{
|
{
|
||||||
languages.clear();
|
languages.clear();
|
||||||
for (auto path : getLanguageSearchPaths())
|
for (const auto &path : getLanguageSearchPaths())
|
||||||
{
|
{
|
||||||
languages << QDir(path).entryList(QStringList{ "*.qm" }, QDir::Hidden | QDir::Files);
|
languages << QDir(path).entryList(QStringList{ "*.qm" }, QDir::Hidden | QDir::Files);
|
||||||
}
|
}
|
||||||
@ -52,20 +43,21 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
bool QvTranslator::InstallTranslation(const QString &code)
|
bool QvTranslator::InstallTranslation(const QString &code)
|
||||||
{
|
{
|
||||||
for (auto path : getLanguageSearchPaths())
|
for (const auto &path : getLanguageSearchPaths())
|
||||||
{
|
{
|
||||||
if (FileExistsIn(QDir(path), code + ".qm"))
|
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();
|
QTranslator *translatorNew = new QTranslator();
|
||||||
translatorNew->load(code + ".qm", path);
|
translatorNew->load(code + ".qm", path);
|
||||||
if (pTranslator)
|
if (pTranslator)
|
||||||
{
|
{
|
||||||
LOG(MODULE_INIT, "Removed translations")
|
LOG(MODULE_UI, "Removed translations")
|
||||||
qApp->removeTranslator(pTranslator.get());
|
qApp->removeTranslator(pTranslator.get());
|
||||||
}
|
}
|
||||||
this->pTranslator.reset(translatorNew);
|
this->pTranslator.reset(translatorNew);
|
||||||
qApp->installTranslator(pTranslator.get());
|
qApp->installTranslator(pTranslator.get());
|
||||||
|
LOG(MODULE_UI, "Successfully installed a translator for " + code)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "QvAutoLaunch.hpp"
|
#include "QvAutoLaunch.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
@ -29,7 +31,7 @@ namespace Qv2ray::components::autolaunch
|
|||||||
bool GetLaunchAtLoginStatus()
|
bool GetLaunchAtLoginStatus()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QString appName = QApplication::applicationName();
|
QString appName = QCoreApplication::applicationName();
|
||||||
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||||
return reg.contains(appName);
|
return reg.contains(appName);
|
||||||
}
|
}
|
||||||
@ -80,7 +82,7 @@ namespace Qv2ray::components::autolaunch
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined Q_OS_LINUX
|
#elif defined Q_OS_LINUX
|
||||||
QString appName = QApplication::applicationName();
|
QString appName = QCoreApplication::applicationName();
|
||||||
QString desktopFileLocation = getUserAutostartDir_private() + appName + QLatin1String(".desktop");
|
QString desktopFileLocation = getUserAutostartDir_private() + appName + QLatin1String(".desktop");
|
||||||
return QFile::exists(desktopFileLocation);
|
return QFile::exists(desktopFileLocation);
|
||||||
}
|
}
|
||||||
@ -89,7 +91,7 @@ namespace Qv2ray::components::autolaunch
|
|||||||
void SetLaunchAtLoginStatus(bool enable)
|
void SetLaunchAtLoginStatus(bool enable)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QString appName = QApplication::applicationName();
|
QString appName = QCoreApplication::applicationName();
|
||||||
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
@ -160,7 +162,7 @@ namespace Qv2ray::components::autolaunch
|
|||||||
auto binPath = qEnvironmentVariableIsSet("APPIMAGE") ? qEnvironmentVariable("APPIMAGE") : QCoreApplication::applicationFilePath();
|
auto binPath = qEnvironmentVariableIsSet("APPIMAGE") ? qEnvironmentVariable("APPIMAGE") : QCoreApplication::applicationFilePath();
|
||||||
//
|
//
|
||||||
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_unix.cpp
|
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_unix.cpp
|
||||||
QString appName = QApplication::applicationName();
|
QString appName = QCoreApplication::applicationName();
|
||||||
QString userAutoStartPath = getUserAutostartDir_private();
|
QString userAutoStartPath = getUserAutostartDir_private();
|
||||||
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
|
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
|
||||||
|
|
||||||
@ -184,24 +186,23 @@ namespace Qv2ray::components::autolaunch
|
|||||||
|
|
||||||
QTextStream ts(&iniFile);
|
QTextStream ts(&iniFile);
|
||||||
ts.setCodec("UTF-8");
|
ts.setCodec("UTF-8");
|
||||||
ts << QLatin1String("[Desktop Entry]") << endl
|
ts << QLatin1String("[Desktop Entry]") << NEWLINE //
|
||||||
<< QLatin1String("Name=") << QApplication::applicationName() << endl
|
<< QLatin1String("Name=") << QCoreApplication::applicationName() + QCoreApplication::arguments().join(" ") << NEWLINE //
|
||||||
<< QLatin1String("GenericName=") << QLatin1String("V2ray Frontend") << endl
|
<< QLatin1String("GenericName=") << QLatin1String("V2ray Frontend") << NEWLINE //
|
||||||
<< QLatin1String("Exec=") << binPath << endl
|
<< QLatin1String("Exec=") << binPath << NEWLINE //
|
||||||
<< QLatin1String("Terminal=") << "false" << endl
|
<< QLatin1String("Terminal=") << "false" << NEWLINE //
|
||||||
<< QLatin1String("Icon=") << "qv2ray" << endl // always use lowercase for icons
|
<< QLatin1String("Icon=") << "qv2ray" << NEWLINE //
|
||||||
<< QLatin1String("Categories=") << "Network" << endl
|
<< QLatin1String("Categories=") << "Network" << NEWLINE //
|
||||||
<< QLatin1String("Type=") << "Application" << endl
|
<< QLatin1String("Type=") << "Application" << NEWLINE //
|
||||||
<< QLatin1String("StartupNotify=") << "false" << endl
|
<< QLatin1String("StartupNotify=") << "false" << NEWLINE //
|
||||||
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl;
|
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << NEWLINE;
|
||||||
|
ts.flush();
|
||||||
|
iniFile.close();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!QFile::remove(desktopFileLocation))
|
QFile::remove(desktopFileLocation);
|
||||||
{
|
QFile::remove(desktopFileLocation.replace("qv2ray", "Qv2ray"));
|
||||||
// qCWarning(lcUtility) << "Could not remove autostart desktop
|
|
||||||
// file";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#include "DarkmodeDetector.hpp"
|
#include "DarkmodeDetector.hpp"
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QStyle>
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <QApplication>
|
|
||||||
#include <QStyle>
|
|
||||||
#elif defined(Q_OS_WIN32)
|
#elif defined(Q_OS_WIN32)
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#else
|
#else
|
||||||
@ -16,7 +17,7 @@ namespace Qv2ray::components::darkmode
|
|||||||
// Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
// Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
|
||||||
bool isDarkMode()
|
bool isDarkMode()
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_LINUX)
|
#if !QvHasFeature(NativeDarkmode)
|
||||||
if (!qApp || !qApp->style())
|
if (!qApp || !qApp->style())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -25,9 +26,6 @@ namespace Qv2ray::components::darkmode
|
|||||||
#elif defined(Q_OS_WIN32)
|
#elif defined(Q_OS_WIN32)
|
||||||
QSettings settings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", QSettings::NativeFormat);
|
QSettings settings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", QSettings::NativeFormat);
|
||||||
return settings.value("AppsUseLightTheme", 1).toInt() == 0;
|
return settings.value("AppsUseLightTheme", 1).toInt() == 0;
|
||||||
#elif defined(Q_OS_DARWIN)
|
|
||||||
// TODO: expand this stub
|
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
#include "QvGeositeReader.hpp"
|
#include "QvGeositeReader.hpp"
|
||||||
|
|
||||||
#include "v2ray_geosite.pb.h"
|
#ifndef ANDROID
|
||||||
|
#include "v2ray_geosite.pb.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Qv2ray::components::geosite
|
namespace Qv2ray::components::geosite
|
||||||
{
|
{
|
||||||
|
QMap<QString, QStringList> GeositeEntries;
|
||||||
QStringList ReadGeoSiteFromFile(const QString &filepath)
|
QStringList ReadGeoSiteFromFile(const QString &filepath)
|
||||||
|
{
|
||||||
|
if (GeositeEntries.contains(filepath))
|
||||||
|
{
|
||||||
|
return GeositeEntries.value(filepath);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
QStringList list;
|
QStringList list;
|
||||||
|
#ifndef ANDROID
|
||||||
LOG(MODULE_FILEIO, "Reading geosites from: " + filepath)
|
LOG(MODULE_FILEIO, "Reading geosites from: " + filepath)
|
||||||
//
|
//
|
||||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||||
@ -26,7 +36,7 @@ namespace Qv2ray::components::geosite
|
|||||||
GeoSiteList sites;
|
GeoSiteList sites;
|
||||||
sites.ParseFromArray(content.data(), content.size());
|
sites.ParseFromArray(content.data(), content.size());
|
||||||
|
|
||||||
for (auto e : sites.entry())
|
for (const auto &e : sites.entry())
|
||||||
{
|
{
|
||||||
// We want to use lower string.
|
// We want to use lower string.
|
||||||
list << QString::fromStdString(e.country_code()).toLower();
|
list << QString::fromStdString(e.country_code()).toLower();
|
||||||
@ -35,7 +45,10 @@ namespace Qv2ray::components::geosite
|
|||||||
LOG(MODULE_FILEIO, "Loaded " + QSTRN(list.count()) + " geosite entries from data file.")
|
LOG(MODULE_FILEIO, "Loaded " + QSTRN(list.count()) + " geosite entries from data file.")
|
||||||
// Optional: Delete all global objects allocated by libprotobuf.
|
// Optional: Delete all global objects allocated by libprotobuf.
|
||||||
google::protobuf::ShutdownProtobufLibrary();
|
google::protobuf::ShutdownProtobufLibrary();
|
||||||
|
#endif
|
||||||
list.sort();
|
list.sort();
|
||||||
|
GeositeEntries[filepath] = list;
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // namespace Qv2ray::components::geosite
|
} // namespace Qv2ray::components::geosite
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
namespace Qv2ray::components::geosite
|
namespace Qv2ray::components::geosite
|
||||||
{
|
{
|
||||||
QStringList ReadGeoSiteFromFile(const QString &filepath);
|
QStringList ReadGeoSiteFromFile(const QString &filepath);
|
||||||
}
|
} // namespace Qv2ray::components::geosite
|
||||||
|
|
||||||
using namespace Qv2ray::components;
|
using namespace Qv2ray::components;
|
||||||
using namespace Qv2ray::components::geosite;
|
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();
|
info.pluginLoader->unload();
|
||||||
continue;
|
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)
|
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.
|
// 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"),
|
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("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."));
|
tr("Please contact the plugin provider or report the issue to Qv2ray Workgroup."));
|
||||||
continue;
|
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(PluginLog(const QString &)), this, SLOT(QvPluginLog(const QString &)));
|
||||||
connect(plugin, SIGNAL(PluginErrorMessageBox(const QString &)), this, SLOT(QvPluginMessageBox(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 + "\"")
|
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.
|
// Load plugin if it haven't been loaded.
|
||||||
InitializePlugin(internalName);
|
InitializePlugin(internalName);
|
||||||
|
|
||||||
QvMessageBoxInfo(nullptr, tr("Enabling a plugin"), tr("The plugin will become fully functional after restarting Qv2ray."));
|
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;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMultiHash<QString, QPair<QString, QJsonObject>> QvPluginHost::TryDeserializeShareLink(const QString &sharelink, //
|
const QList<std::tuple<QString, QString, QJsonObject>> QvPluginHost::TryDeserializeShareLink(const QString &sharelink, //
|
||||||
QString *prefix, //
|
QString *aliasPrefix, //
|
||||||
QString *errMessage, //
|
QString *errMessage, //
|
||||||
QString *newGroupName, //
|
QString *newGroupName, //
|
||||||
bool *status) const
|
bool *status) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(newGroupName)
|
Q_UNUSED(newGroupName)
|
||||||
QMultiHash<QString, QPair<QString, QJsonObject>> data;
|
QList<std::tuple<QString, QString, QJsonObject>> data;
|
||||||
*status = true;
|
*status = true;
|
||||||
for (const auto &plugin : plugins)
|
for (const auto &plugin : plugins)
|
||||||
{
|
{
|
||||||
@ -262,9 +263,9 @@ namespace Qv2ray::components::plugins
|
|||||||
}
|
}
|
||||||
if (thisPluginCanHandle)
|
if (thisPluginCanHandle)
|
||||||
{
|
{
|
||||||
auto [protocol, outboundSettings] = serializer->DeserializeOutbound(sharelink, prefix, errMessage);
|
const auto &[protocol, outboundSettings] = serializer->DeserializeOutbound(sharelink, aliasPrefix, errMessage);
|
||||||
*status = *status && errMessage->isEmpty();
|
*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))
|
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_SERIALIZOR))
|
||||||
{
|
{
|
||||||
auto serializer = plugin.pluginInterface->GetSerializer();
|
auto serializer = plugin.pluginInterface->GetSerializer();
|
||||||
if (serializer->OutboundProtocols().contains(protocol))
|
if (serializer && serializer->OutboundProtocols().contains(protocol))
|
||||||
{
|
{
|
||||||
auto info = serializer->GetOutboundInfo(protocol, o);
|
auto info = serializer->GetOutboundInfo(protocol, o);
|
||||||
*status = true;
|
*status = true;
|
||||||
@ -300,7 +301,7 @@ namespace Qv2ray::components::plugins
|
|||||||
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_SERIALIZOR))
|
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_SERIALIZOR))
|
||||||
{
|
{
|
||||||
auto serializer = plugin.pluginInterface->GetSerializer();
|
auto serializer = plugin.pluginInterface->GetSerializer();
|
||||||
if (serializer->OutboundProtocols().contains(protocol))
|
if (serializer && serializer->OutboundProtocols().contains(protocol))
|
||||||
{
|
{
|
||||||
auto link = serializer->SerializeOutbound(protocol, alias, groupName, outboundSettings);
|
auto link = serializer->SerializeOutbound(protocol, alias, groupName, outboundSettings);
|
||||||
*status = true;
|
*status = true;
|
||||||
@ -311,18 +312,31 @@ namespace Qv2ray::components::plugins
|
|||||||
return "";
|
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)
|
for (const auto &plugin : plugins)
|
||||||
{
|
{
|
||||||
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_KERNEL))
|
if (plugin.isLoaded && plugin.metadata.SpecialPluginType.contains(SPECIAL_TYPE_KERNEL))
|
||||||
{
|
{
|
||||||
auto kern = plugin.pluginInterface->GetKernel();
|
QStringList outbounds;
|
||||||
for (const auto &cap : kern->KernelOutboundCapabilities())
|
for (const auto &info : plugin.metadata.KernelOutboundCapabilities)
|
||||||
{
|
{
|
||||||
kernels.insert(cap.protocol, kern);
|
outbounds << info.protocol;
|
||||||
}
|
}
|
||||||
|
kernels.insert(plugin.metadata.InternalName, outbounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return kernels;
|
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