Merge pull request #415 from Qv2ray/dev

[WIP] Qv2ray v2.2 testing
This commit is contained in:
Qv2ray-dev 2020-03-13 20:36:28 +08:00 committed by GitHub
commit 0638060ed0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
186 changed files with 20333 additions and 10563 deletions

View File

@ -1,7 +1,13 @@
name: AUR Test Build name: Build Qv2ray AUR
on: on:
push: push:
paths-ignore: [README.md] paths-ignore:
- '.github'
branches:
- master
- dev
tags:
- 'v**'
schedule: schedule:
- cron: "0 19 * * *" - cron: "0 19 * * *"

View File

@ -1,4 +1,4 @@
name: Qv2ray build matrix name: Qv2ray build matrix - cmake
on: on:
push: push:
@ -9,17 +9,31 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
qt_version: [5.12.6, 5.13.2, 5.14.1] qt_version: [5.11.3, 5.12.7, 5.13.2, 5.14.2]
platform: [ubuntu-16.04, macos-latest, windows-latest] platform: [ubuntu-16.04, macos-latest, windows-latest]
arch: [x86, x64] arch: [x86, x64]
include:
- platform: windows-latest
arch: x86
qtarch: win32_msvc2017
- platform: windows-latest
arch: x64
qtarch: win64_msvc2017_64
exclude: exclude:
- platform: ubuntu-16.04 - platform: ubuntu-16.04
arch: x86 arch: x86
- platform: macos-latest - platform: macos-latest
arch: x86 arch: x86
- platform: windows-latest
qt_version: 5.11.3
- platform: windows-latest
qt_version: 5.12.7
fail-fast: false fail-fast: false
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
env:
_QV2RAY_BUILD_INFO_: "Qv2ray built from Github Action"
_QV2RAY_BUILD_EXTRA_INFO_: "qt${{ matrix.qt_version }}-${{ github.sha }}-ci.${{ matrix.platform }}"
steps: steps:
- name: Get the version - name: Get the version
@ -28,9 +42,14 @@ jobs:
run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3)
- name: Checking out sources - name: Checking out sources
uses: actions/checkout@master uses: actions/checkout@master
- name: Install Python 3.7 version
uses: actions/setup-python@v1
with:
python-version: '3.7'
architecture: ${{ matrix.arch }}
- name: Restoring submodules - name: Restoring submodules
run: git submodule update --init run: git submodule update --init
# -------------------------------------------------------- # =========================================================================================================
- name: Install MSVC compiler - name: Install MSVC compiler
if: matrix.platform == 'windows-latest' if: matrix.platform == 'windows-latest'
uses: ilammy/msvc-dev-cmd@v1 uses: ilammy/msvc-dev-cmd@v1
@ -38,58 +57,85 @@ jobs:
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo # 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
toolset: 14.2 toolset: 14.2
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
- name: Cache Qt
id: cache-qt
uses: actions/cache@v1
with:
path: ../Qt
key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }}
- name: Installing Qt - ${{ matrix.arch }} - name: Installing Qt - ${{ matrix.arch }}
uses: Qv2ray/install-qt-action@master uses: jurplel/install-qt-action@v2.5.0
with: with:
version: ${{ matrix.qt_version }} version: ${{ matrix.qt_version }}
arch: ${{ matrix.arch }} arch: ${{ matrix.qtarch }}
# -------------------------------------------------------- mirror: 'http://mirrors.ocf.berkeley.edu/qt/'
- name: Linux - Install Packages cached: ${{ steps.cache-qt.outputs.cache-hit }}
# =========================================================================================================
- name: Linux - ${{ matrix.qt_version }} - Build preparation - Install Packages
if: matrix.platform == 'ubuntu-16.04' if: matrix.platform == 'ubuntu-16.04'
run: | run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo add-apt-repository ppa:webispy/grpc sudo add-apt-repository ppa:webispy/grpc
sudo add-apt-repository ppa:carsten-uppenbrink-net/openssl sudo add-apt-repository ppa:carsten-uppenbrink-net/openssl
sudo apt update sudo apt update
sudo apt install -y gcc-7 libgl-dev openssl libx11-dev libxkbcommon-x11-dev libprotobuf-dev protobuf-compiler protobuf-c-compiler sudo apt install -y libgl-dev libx11-dev libxkbcommon-x11-dev libssl-dev libprotobuf-dev protobuf-compiler protobuf-c-compiler libgrpc++-dev protobuf-compiler-grpc tree ninja-build
- name: macOS - Install Packages
if: matrix.platform == 'macos-latest'
run: brew install protobuf
# -------------------------------------------------------- # --------------------------------------------------------
- name: Cross-platform - Download libraries - name: macOS - ${{ matrix.qt_version }} - Build preparation - Install Packages
shell: bash if: matrix.platform == 'macos-latest'
run: | run: |
curl -o ./libs/libqvb-linux64.a -L https://github.com/Qv2ray/QvRPCBridge/releases/download/v1.1/libqvb-linux64.a brew install protobuf
curl -o ./libs/libqvb-darwin.a -L https://github.com/Qv2ray/QvRPCBridge/releases/download/v1.1/libqvb-darwin.a brew install grpc
curl -o ./libs/Qv2ray-deps-${{ matrix.arch }}-windows.7z -L https://github.com/Qv2ray/Qv2ray-deps/releases/download/release/Qv2ray-deps-${{ matrix.arch }}-windows.7z brew install ninja
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Extract Windows Dependencies # --------------------------------------------------------
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Build preparation - Download Dependencies
shell: bash
if: matrix.platform == 'windows-latest'
run: |
choco install -y ninja
curl -o ./libs/Qv2ray-deps-grpc-${{ matrix.arch }}-windows.7z -L https://github.com/Qv2ray/Qv2ray-deps/releases/download/release/Qv2ray-deps-grpc-${{ matrix.arch }}-windows.7z
- name: Win-${{ matrix.arch }} - Build preparation - Extract Dependencies
if: matrix.platform == 'windows-latest' if: matrix.platform == 'windows-latest'
uses: DuckSoft/extract-7z-action@v1.0 uses: DuckSoft/extract-7z-action@v1.0
with: with:
pathSource: ./libs/Qv2ray-deps-${{ matrix.arch }}-windows.7z pathSource: ./libs/Qv2ray-deps-grpc-${{ matrix.arch }}-windows.7z
pathTarget: ./libs pathTarget: ./libs
# -------------------------------------------------------- Generate MakeFile # ========================================================================================================= Generate MakeFile and Build
- name: Cross-platform - ${{ matrix.qt_version }} - Generate Dependencies and Makefile - name: macOS - ${{ matrix.qt_version }} - Generate Dependencies and Build
shell: bash shell: bash
if: matrix.platform == 'macos-latest'
run: | run: |
mkdir build mkdir build
cd build cd build
export _QV2RAY_BUILD_INFO_="Qv2ray built from Github Action" cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
export _QV2RAY_BUILD_EXTRA_INFO_="qt${{ matrix.qt_version }}-${{ github.sha }}" cmake --build . --parallel $(sysctl -n hw.logicalcpu)
qmake .. CONFIG+="debug_and_release no_increase_build_number" PREFIX=/usr sudo cmake --install .
# -------------------------------------------------------- Build sudo chmod -Rv a+rw ./
- name: Unix - ${{ matrix.qt_version }} - Build Qv2ray # --------------------------------------------------------
if: matrix.platform != 'windows-latest' - name: Windows - ${{ matrix.qt_version }} - Generate Dependencies and Build
run: | shell: bash
cd build
make -j2 release $([ "${{ matrix.platform }}" == "ubuntu-16.04" ] && echo "CC=gcc-7 CXX=g++-7" LINK="g++-7" || echo "")
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Build Qv2ray
if: matrix.platform == 'windows-latest' if: matrix.platform == 'windows-latest'
env:
CC: cl.exe
CXX: cl.exe
run: | run: |
mkdir build
cd build cd build
nmake release cmake .. -GNinja -DCMAKE_INSTALL_PREFIX=./deployment -DCMAKE_BUILD_TYPE=Release
# -------------------------------------------------------- Deployments cmake --build . --parallel $(nproc)
cmake --install .
# --------------------------------------------------------
- name: Linux - ${{ matrix.qt_version }} - Generate Dependencies and Build
if: matrix.platform == 'ubuntu-16.04'
shell: bash
env:
CC: /usr/bin/gcc-9
CXX: /usr/bin/g++-9
run: |
mkdir build
cd build
cmake .. -GNinja -DCMAKE_INSTALL_PREFIX=./AppDir/usr -DCMAKE_BUILD_TYPE=Release -DQV2RAY_TRANSLATION_PATH=QApplication::applicationDirPath\(\)+"/../share/qv2ray/lang"
cmake --build . --parallel $(nproc)
cmake --install .
# ========================================================================================================= Deployments
- name: Linux - ${{ matrix.qt_version }} - Generating AppImage - name: Linux - ${{ matrix.qt_version }} - Generating AppImage
if: matrix.platform == 'ubuntu-16.04' if: matrix.platform == 'ubuntu-16.04'
run: | run: |
@ -97,7 +143,6 @@ jobs:
wget https://github.com/probonopd/linuxdeployqt/releases/download/6/linuxdeployqt-6-x86_64.AppImage wget https://github.com/probonopd/linuxdeployqt/releases/download/6/linuxdeployqt-6-x86_64.AppImage
chmod +x ./linuxdeployqt-6-x86_64.AppImage chmod +x ./linuxdeployqt-6-x86_64.AppImage
./linuxdeployqt-6-x86_64.AppImage --appimage-extract ./linuxdeployqt-6-x86_64.AppImage --appimage-extract
make install INSTALL_ROOT=AppDir
cd AppDir cd AppDir
wget -c https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64 -O AppRun wget -c https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64 -O AppRun
chmod a+x AppRun chmod a+x AppRun
@ -118,22 +163,19 @@ jobs:
path: build/AppDir/Qv2ray.AppImage path: build/AppDir/Qv2ray.AppImage
- 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' if: github.event_name == 'release' && matrix.platform == 'ubuntu-16.04' && matrix.qt_version == '5.14.2'
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/AppDir/Qv2ray.AppImage file: build/AppDir/Qv2ray.AppImage
asset_name: Qv2ray.${{ steps.get_version.outputs.VERSION }}.linux-${{ matrix.arch }}.qt${{ matrix.qt_version }}.AppImage asset_name: Qv2ray.${{ steps.get_version.outputs.VERSION }}.linux-${{ matrix.arch }}.AppImage
tag: ${{ github.ref }} tag: ${{ github.ref }}
overwrite: true overwrite: true
# == # --------------------------------------------------------
- name: macOS - ${{ matrix.qt_version }} - Making release tarball - name: macOS - ${{ matrix.qt_version }} - Making release tarball
if: matrix.platform == 'macos-latest' if: matrix.platform == 'macos-latest'
run: | run: |
cd build cd build
cd qv2ray.app tar czvf Qv2ray.app.tar.gz qv2ray.app
macdeployqt ./
cd ..
tar czf Qv2ray.app.tar.gz qv2ray.app
- name: macOS - ${{ matrix.qt_version }} - Uploading Artifact - name: macOS - ${{ matrix.qt_version }} - Uploading Artifact
if: matrix.platform == 'macos-latest' if: matrix.platform == 'macos-latest'
uses: actions/upload-artifact@master uses: actions/upload-artifact@master
@ -142,31 +184,19 @@ jobs:
path: build/Qv2ray.app.tar.gz path: build/Qv2ray.app.tar.gz
- name: macOS - ${{ matrix.qt_version }} - Upload binaries to release - name: macOS - ${{ 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 == 'macos-latest' if: github.event_name == 'release' && matrix.platform == 'macos-latest' && matrix.qt_version == '5.14.2'
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/Qv2ray.app.tar.gz file: build/Qv2ray.app.tar.gz
asset_name: Qv2ray.${{ steps.get_version.outputs.VERSION }}.macOS-${{ matrix.arch }}.qt${{ matrix.qt_version }}.tar.gz asset_name: Qv2ray.${{ steps.get_version.outputs.VERSION }}.macOS-${{ matrix.arch }}.tar.gz
tag: ${{ github.ref }} tag: ${{ github.ref }}
overwrite: true overwrite: true
# == # --------------------------------------------------------
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Copying DLLs to build output folders
if: matrix.platform == 'windows-latest'
run: .\.github\workflows\copy_DLLs.bat
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Running windeployqt
if: matrix.platform == 'windows-latest'
shell: cmd
run: |
cd build
cd release
del *.cpp *.h *.o *.qrc *.qm *.hpp *.obj
set VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\
windeployqt ./qv2ray.exe --compiler-runtime --verbose 2
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Create 7z Release - name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Create 7z Release
if: matrix.platform == 'windows-latest' if: matrix.platform == 'windows-latest'
uses: DuckSoft/create-7z-action@v1.0 uses: DuckSoft/create-7z-action@v1.0
with: with:
pathSource: ./build/release/ pathSource: ./build/deployment/
pathTarget: ./release.7z pathTarget: ./release.7z
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Uploading artifact - name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Uploading artifact
if: matrix.platform == 'windows-latest' if: matrix.platform == 'windows-latest'
@ -176,10 +206,10 @@ jobs:
path: release.7z path: release.7z
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Upload binaries to release - name: Win-${{ matrix.arch }} - ${{ 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 == 'windows-latest' if: github.event_name == 'release' && matrix.platform == 'windows-latest' && matrix.qt_version == '5.14.2'
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: release.7z file: release.7z
asset_name: Qv2ray.${{ steps.get_version.outputs.VERSION }}.Windows-${{ matrix.arch }}.qt${{ matrix.qt_version }}.7z asset_name: Qv2ray.${{ steps.get_version.outputs.VERSION }}.Windows-${{ matrix.arch }}.7z
tag: ${{ github.ref }} tag: ${{ github.ref }}
overwrite: true overwrite: true

View File

@ -1,5 +0,0 @@
@echo off
echo Copying DLLs for Windows
forfiles /s /p %GITHUB_WORKSPACE%\libs\x86-windows\bin\ /m "*.dll" /c "cmd.exe /c copy @file %GITHUB_WORKSPACE%\build\release\"
forfiles /s /p %GITHUB_WORKSPACE%\libs\x64-windows\bin\ /m "*.dll" /c "cmd.exe /c copy @file %GITHUB_WORKSPACE%\build\release\"
exit 0

4
.gitignore vendored
View File

@ -1,6 +1,8 @@
# Some files # Some files
.DS_Store .DS_Store
*.pro.user *.pro.user
*.user
.vs/
*.qm *.qm
./.vscode ./.vscode
@ -11,4 +13,4 @@ libs/x64-windows/
libs/x86-windows/ libs/x86-windows/
libs/libqvb-* libs/libqvb-*
build/ build**/

9
.gitmodules vendored
View File

@ -1,9 +1,6 @@
[submodule "3rdparty/x2struct"] [submodule "3rdparty/x2struct"]
path = 3rdparty/x2struct path = 3rdparty/x2struct
url = https://github.com/xyz347/x2struct url = https://github.com/xyz347/x2struct
[submodule "3rdparty/qhttpserver"]
path = 3rdparty/qhttpserver
url = https://github.com/nikhilm/qhttpserver
[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,3 +13,9 @@
[submodule "libs/libqvb"] [submodule "libs/libqvb"]
path = libs/libqvb path = libs/libqvb
url = https://github.com/Qv2ray/QvRPCBridge url = https://github.com/Qv2ray/QvRPCBridge
[submodule "3rdparty/cpp-httplib"]
path = 3rdparty/cpp-httplib
url = https://github.com/yhirose/cpp-httplib
[submodule "libs/puresource"]
path = libs/puresource
url = https://github.com/Qv2ray/PureSource/

View File

@ -1,4 +1,5 @@
language: bash language: shell
os: linux
dist: bionic dist: bionic
git: git:
@ -15,14 +16,15 @@ env:
addons: addons:
snaps: snaps:
- name: snapcraft - name: snapcraft
channel: stable channel: stable
confinement: classic confinement: classic
- name: lxd - name: lxd
channel: stable channel: stable
script: script:
- sudo apt autoremove lxd --purge - sudo apt autoremove lxd --purge
- sudo /snap/bin/lxd waitready
- sudo /snap/bin/lxd init --auto - sudo /snap/bin/lxd init --auto
- sudo snapcraft --use-lxd - sudo snapcraft --use-lxd

@ -1 +1 @@
Subproject commit 0f368335943cc8b84a8b52c5ad7cfd9c25ebb6d6 Subproject commit c93f1c1826d46d5d60f118688cd830b39af8b9c6

@ -1 +1 @@
Subproject commit 0f6695e2a9d8fdaa336e7ad941855c46c61f218a Subproject commit 4abe20afbfa5695ac7a9bce1298943b645aeffe9

1
3rdparty/cpp-httplib vendored Submodule

@ -0,0 +1 @@
Subproject commit 26deffe0c6a1e177e393416b94cdc0f340ca79bd

@ -1 +0,0 @@
Subproject commit 02a6e7174b5be76e2c0e74a109817e39a141b9fd

2
3rdparty/qzxing vendored

@ -1 +1 @@
Subproject commit ee50acba1f10e70ef23c593971621ed7a9f4c5a1 Subproject commit dac9480a652d591c41ec9ef6f6c966c59a252142

382
CMakeLists.txt Normal file
View File

@ -0,0 +1,382 @@
cmake_minimum_required(VERSION 3.10.1)
file(STRINGS "${CMAKE_SOURCE_DIR}/makespec/VERSION" QV2RAY_VERSION)
file(STRINGS "${CMAKE_SOURCE_DIR}/makespec/BUILDVERSION" QV2RAY_BUILD_VERSION)
if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release")
math(EXPR QV2RAY_BUILD_VERSION "1 + ${QV2RAY_BUILD_VERSION}")
message("Increasing BUILDVERSION")
file(WRITE "${CMAKE_SOURCE_DIR}/makespec/BUILDVERSION" ${QV2RAY_BUILD_VERSION})
endif()
set(PACKAGE_VERSION "${QV2RAY_VERSION}.${QV2RAY_BUILD_VERSION}")
project(qv2ray)
set(VERSION_LIST ${PACKAGE_VERSION})
string(REPLACE "." ";" VERSION_LIST ${VERSION_LIST})
separate_arguments(VERSION_LIST)
list(GET VERSION_LIST 0 QV2RAY_VERSION_MAJOR)
list(GET VERSION_LIST 1 QV2RAY_VERSION_MINOR)
list(GET VERSION_LIST 2 QV2RAY_VERSION_BUGFIX)
list(GET VERSION_LIST 3 QV2RAY_VERSION_BUILD)
add_definitions(-DQV2RAY_VERSION_MAJOR=${QV2RAY_VERSION_MAJOR})
add_definitions(-DQV2RAY_VERSION_MINOR=${QV2RAY_VERSION_MINOR})
add_definitions(-DQV2RAY_VERSION_BUGFIX=${QV2RAY_VERSION_BUGFIX})
add_definitions(-DQV2RAY_VERSION_BUILD=${QV2RAY_VERSION_BUILD})
add_definitions(-DQV2RAY_VERSION_STRING="v${PACKAGE_VERSION}")
add_definitions(-DXTOSTRUCT_QT)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
cmake_policy(SET CMP0071 NEW)
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
message(" ")
message("Qv2ray Version: v${PACKAGE_VERSION}")
message("|-------------------------------------------------|")
message("| Qv2ray, A Cross Platform v2ray Qt GUI Client. |")
message("| Licenced under GPLv3 |")
message("| |")
message("| You may only use this program to the extent |")
message("| permitted by local law. |")
message("| |")
message("| See: https://www.gnu.org/licenses/gpl-3.0.html |")
message("|-------------------------------------------------|")
message("| Project Homepage: https://github.com/Qv2ray |")
message("| Welcome to contribute! |")
message("|-------------------------------------------------|")
message(" ")
if(WIN32)
add_compile_options("/std:c++17")
add_definitions(-DUNICODE -D_UNICODE)
add_definitions(-D_HAS_STD_BYTE=0 -D_WIN32_WINNT=0x600 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
set(GUI_TYPE WIN32)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
if(CMAKE_CL_64)
include(${CMAKE_SOURCE_DIR}/libs/x64-windows/scripts/buildsystems/vcpkg.cmake)
else()
include(${CMAKE_SOURCE_DIR}/libs/x86-windows/scripts/buildsystems/vcpkg.cmake)
endif()
endif()
endif()
if(UNIX AND NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
include(cmake/translations.cmake)
include(cmake/qnodeeditor.cmake)
include(cmake/singleapplication.cmake)
include(cmake/qzxing.cmake)
include(cmake/protobuf.cmake)
include(cmake/cpp-httplib.cmake)
include(cmake/backend.cmake)
if(QV2RAY_BUILD_INFO)
set(_QV2RAY_BUILD_INFO_STR_ "${QV2RAY_BUILD_INFO}")
elseif(DEFINED ENV{_QV2RAY_BUILD_INFO_})
set(_QV2RAY_BUILD_INFO_STR_ "$ENV{_QV2RAY_BUILD_INFO_}")
else()
set(_QV2RAY_BUILD_INFO_STR_ "Qv2ray from manual build")
endif()
if(QV2RAY_BUILD_EXTRA_INFO)
set(_QV2RAY_BUILD_EXTRA_INFO_STR_ "${QV2RAY_BUILD_EXTRA_INFO}")
elseif(DEFINED ENV{_QV2RAY_BUILD_EXTRA_INFO_})
set(_QV2RAY_BUILD_EXTRA_INFO_STR_ "$ENV{_QV2RAY_BUILD_EXTRA_INFO_}")
else()
set(_QV2RAY_BUILD_EXTRA_INFO_STR_ "Qv2ray v${PACKAGE_VERSION}")
endif()
set(QV2RAY_BUILD_INFO ${_QV2RAY_BUILD_INFO_STR_} CACHE STRING "Qv2ray build info")
set(QV2RAY_BUILD_EXTRA_INFO ${_QV2RAY_BUILD_EXTRA_INFO_STR_} CACHE STRING "Qv2ray build extra info")
add_definitions(-D_QV2RAY_BUILD_INFO_STR_="${_QV2RAY_BUILD_INFO_STR_}")
add_definitions(-D_QV2RAY_BUILD_EXTRA_INFO_STR_="${_QV2RAY_BUILD_EXTRA_INFO_STR_}")
message("Qv2ray build info: ${_QV2RAY_BUILD_INFO_STR_}")
message("Qv2ray build info ex: ${_QV2RAY_BUILD_EXTRA_INFO_STR_}")
set(QV2RAY_DEFAULT_VASSETS_PATH "unset" CACHE STRING "v2ray assets path")
set(QV2RAY_DEFAULT_VCORE_PATH "unset" CACHE STRING "v2ray core path")
set(QV2RAY_TRANSLATION_PATH "unset" CACHE STRING "Qv2ray translations path")
set(QV2RAY_DISABLE_AUTO_UPDATE OFF CACHE BOOL "Disable update checker")
if(UNIX AND NOT APPLE)
set(QV2RAY_USE_BUILTIN_DARKTHEME OFF CACHE BOOL "Use built-in dark theme instead of followed by the system settings")
else()
set(QV2RAY_USE_BUILTIN_DARKTHEME ON CACHE BOOL "Use built-in dark theme instead of followed by the system settings")
endif()
set(EMBED_TRANSLATIONS OFF CACHE BOOL "Embed translations")
if(QV2RAY_DEFAULT_VASSETS_PATH AND NOT STREQUAL "unset")
add_definitions(-DQV2RAY_DEFAULT_VASSETS_PATH="${QV2RAY_DEFAULT_VASSETS_PATH}")
endif()
if(QV2RAY_DEFAULT_VCORE_PATH AND NOT STREQUAL "unset")
add_definitions(-DQV2RAY_DEFAULT_VCORE_PATH="${QV2RAY_DEFAULT_VCORE_PATH}")
endif()
if(QV2RAY_TRANSLATION_PATH AND NOT STREQUAL "unset")
add_definitions(-DQV2RAY_TRANSLATION_PATH="${QV2RAY_TRANSLATION_PATH}")
endif()
if(QV2RAY_USE_BUILTIN_DARKTHEME)
add_definitions(-DQV2RAY_USE_BUILTIN_DARKTHEME=true)
endif()
if(QV2RAY_DISABLE_AUTO_UPDATE)
add_definitions(-DDISABLE_AUTO_UPDATE)
endif()
set(QV2RAY_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/components/autolaunch/QvAutoLaunch.cpp
src/components/geosite/QvGeositeReader.cpp
src/components/icmping/win/ICMPPinger.cpp
src/components/pac/QvGFWPACConverter.cpp
src/components/pac/QvPACHandler.cpp
src/components/plugins/toolbar/QvToolbar.cpp
src/components/plugins/toolbar/QvToolbar_linux.cpp
src/components/plugins/toolbar/QvToolbar_win.cpp
src/components/proxy/QvProxyConfigurator.cpp
src/components/speedchart/speedplotview.cpp
src/components/speedchart/speedwidget.cpp
src/components/darkmode/DarkmodeDetector.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/V2rayInstanceHandler.cpp
src/core/kernel/APIBackend.cpp
src/core/kernel/KernelInteractions.cpp
src/core/settings/SettingsBackend.cpp
src/core/settings/SettingsUpgrade.cpp
src/core/tcping/QvTCPing.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/w_ImportConfig.cpp
src/ui/w_MainWindow.cpp
src/ui/w_MainWindow_extra.cpp
src/ui/w_PreferencesWindow.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/w_MainWindow.ui
src/ui/w_PreferencesWindow.ui
src/ui/w_ScreenShot_Core.ui
# headers
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/components/autolaunch/QvAutoLaunch.hpp
src/components/darkmode/DarkmodeDetector.hpp
src/components/geosite/QvGeositeReader.hpp
src/components/icmping/win/ICMPPinger.hpp
src/components/pac/QvPACHandler.hpp
src/components/plugins/toolbar/QvToolbar.hpp
src/components/proxy/QvProxyConfigurator.hpp
src/components/speedchart/speedplotview.hpp
src/components/speedchart/speedwidget.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/kernel/APIBackend.hpp
src/core/kernel/KernelInteractions.hpp
src/core/settings/SettingsBackend.hpp
src/core/tcping/QvTCPing.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/StreamSettingsWidget.hpp
src/ui/w_ImportConfig.hpp
src/ui/w_MainWindow.hpp
src/ui/w_PreferencesWindow.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} -no-ui-lines
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}
${QZXING_SOURCES}
${PROTO_SRCS}
${PROTO_HDRS}
${API_GRPC_SRCS}
${API_PROTO_SRCS}
${QRC_RESOURCES}
${QM_FILES}
)
target_link_libraries(${PROJECT_NAME}
${QT_LIBRARY}
${QV2RAY_PROTOBUF_LIBRARY}
${QV2RAY_BACKEND_LIBRARIES}
)
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}
${QHTTPSERVER_DIR}
${QNODEEDITOR_INCLUDE_PATH}
${QZXING_INCLUDE_PATH}
${SINGLEAPPLICATION_DIR}
${Protobuf_INCLUDE_DIRS}
${cpp-httplib_INCLUDE_DIRS}
)
if(APPLE)
find_package(Iconv REQUIRED)
target_link_libraries(${PROJECT_NAME}
Iconv::Iconv
"-framework Carbon"
"-framework Cocoa"
"-framework Security"
)
target_include_directories(${PROJECT_NAME} PRIVATE
${Iconv_INCLUDE_DIR}
)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR})
set(prefix "${PROJECT_NAME}.app/Contents")
set(INSTALL_RUNTIME_DIR "${prefix}/MacOS")
set(INSTALL_CMAKE_DIR "${prefix}/Resources")
# Destination paths below are relative to ${CMAKE_INSTALL_PREFIX}
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${INSTALL_RUNTIME_DIR} )
install(FILES ${CMAKE_SOURCE_DIR}/assets/Info.plist DESTINATION "${prefix}" )
install(FILES ${CMAKE_SOURCE_DIR}/assets/icons/qv2ray.icns DESTINATION "${INSTALL_CMAKE_DIR}" )
if(NOT EMBED_TRANSLATIONS)
install(FILES ${QM_FILES} DESTINATION ${INSTALL_CMAKE_DIR}/lang)
endif()
# Call macdeployqt
install(CODE "execute_process(COMMAND macdeployqt ${PROJECT_NAME}.app)")
set(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app")
include(cmake/deployment.cmake)
endif()
if(UNIX AND NOT APPLE AND NOT WIN32)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
install(FILES assets/qv2ray.metainfo.xml DESTINATION share/metainfo)
install(FILES assets/qv2ray.desktop DESTINATION share/applications)
install(FILES assets/icons/qv2ray.png DESTINATION share/icons/hicolor/256x256/apps)
if(NOT EMBED_TRANSLATIONS)
install(FILES ${QM_FILES} DESTINATION share/qv2ray/lang)
endif()
endif()
if(WIN32)
target_link_libraries(${PROJECT_NAME} wininet wsock32 ws2_32 user32)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION .)
if(NOT EMBED_TRANSLATIONS)
install(FILES ${QM_FILES} DESTINATION lang)
endif()
if(CMAKE_CL_64)
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libssl-1_1-x64.dll DESTINATION .)
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libcrypto-1_1-x64.dll DESTINATION .)
else()
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libssl-1_1.dll DESTINATION .)
install(FILES ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libcrypto-1_1.dll DESTINATION .)
endif()
install(CODE "execute_process(COMMAND windeployqt ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.exe --compiler-runtime --verbose 2)")
set(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.exe")
include(cmake/deployment.cmake)
endif()

View File

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

View File

@ -1,168 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2019-03-28T08:45:32
#
#-------------------------------------------------
QT += core gui widgets network
TARGET = qv2ray
TEMPLATE = app
# Now read build number file.
QV2RAY_VERSION=$$cat($$PWD/makespec/VERSION)
QV2RAY_BUILD_VERSION=$$cat($$PWD/makespec/BUILDVERSION)
VERSION = $${QV2RAY_VERSION}.$${QV2RAY_BUILD_VERSION}
message(" ")
message("Qv2ray Version: $${VERSION}")
message("|-------------------------------------------------|")
message("| Qv2ray, A Cross Platform v2ray Qt GUI Client. |")
message("| Licenced under GPLv3 |")
message("| |")
message("| You may only use this program to the extent |")
message("| permitted by local law. |")
message("| |")
message("| See: https://www.gnu.org/licenses/gpl-3.0.html |")
message("|-------------------------------------------------|")
message("| Project Homepage: https://github.com/Qv2ray |")
message("| Welcome to contribute! |")
message("|-------------------------------------------------|")
message(" ")
# Distinguish debug and release builds.
CONFIG(release, debug|release) {
CONFIG+=Qv2ray_release no_increase_build_number
}
CONFIG(debug, debug|release) {
CONFIG+=Qv2ray_debug
}
# Qv2ray basic configuration
CONFIG += qt c++17 openssl-linked
include($$PWD/makespec/00-deps.pri)
# lrelease will not work when adding BEFORE 00-deps.pri
CONFIG += lrelease embed_translations
DEFINES += QT_DEPRECATED_WARNINGS QV2RAY_VERSION_STRING=\"\\\"v$${VERSION}\\\"\" QAPPLICATION_CLASS=QApplication
# Source file parser
include($$PWD/makespec/01-sourcesparser.pri)
# Main config
Qv2rayAddSource(base, _, GlobalInstances, hpp)
Qv2rayAddSource(base, _, JsonHelpers, hpp)
Qv2rayAddSource(base, _, Qv2rayBase, hpp)
Qv2rayAddSource(base, _, Qv2rayFeatures, hpp)
Qv2rayAddSource(base, _, Qv2rayLog, cpp, hpp)
Qv2rayAddSource(base, models, CoreObjectModels, hpp)
Qv2rayAddSource(base, models, QvConfigModel, hpp)
Qv2rayAddSource(base, models, QvConfigIdentifier, hpp)
Qv2rayAddSource(base, models, QvSafeType, hpp)
Qv2rayAddSource(base, models, QvRuntimeConfig, hpp)
Qv2rayAddSource(base, models, QvStartupConfig, hpp)
Qv2rayAddSource(common, _, CommandArgs, cpp, hpp)
Qv2rayAddSource(common, _, HTTPRequestHelper, cpp, hpp)
Qv2rayAddSource(common, _, LogHighlighter, cpp, hpp)
Qv2rayAddSource(common, _, QJsonModel, cpp, hpp)
Qv2rayAddSource(common, _, QvHelpers, cpp, hpp)
Qv2rayAddSource(common, _, QvTranslator, hpp)
Qv2rayAddSource(components, autolaunch, QvAutoLaunch, cpp, hpp)
Qv2rayAddSource(components, pac, QvGFWPACConverter, cpp)
Qv2rayAddSource(components, pac, QvPACHandler, cpp, hpp)
Qv2rayAddSource(components, plugins/toolbar, QvToolbar, cpp, hpp)
Qv2rayAddSource(components, plugins/toolbar, QvToolbar_linux, cpp)
Qv2rayAddSource(components, plugins/toolbar, QvToolbar_win, cpp)
Qv2rayAddSource(components, proxy, QvProxyConfigurator, cpp, hpp)
Qv2rayAddSource(components, tcping, QvTCPing, cpp, hpp)
Qv2rayAddSource(components, speedchart, speedwidget, cpp, hpp)
Qv2rayAddSource(components, speedchart, speedplotview, cpp, hpp)
Qv2rayAddSource(components, geosite, QvGeositeReader, cpp, hpp)
Qv2rayAddSource(core, config, ConfigBackend, cpp, hpp)
Qv2rayAddSource(core, config, ConfigUpgrade, cpp)
Qv2rayAddSource(core, connection, ConnectionIO, cpp, hpp)
Qv2rayAddSource(core, connection, Generation, cpp, hpp)
Qv2rayAddSource(core, connection, Serialization, cpp, hpp)
Qv2rayAddSource(core, _, CoreUtils, cpp, hpp)
Qv2rayAddSource(core, kernel, KernelInteractions, cpp, hpp)
Qv2rayAddSource(core, kernel, APIBackend, cpp, hpp)
Qv2rayAddSource(ui, editors, w_InboundEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_JsonEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_OutboundEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_RoutesEditor, cpp, hpp, ui)
Qv2rayAddSource(ui, editors, w_RoutesEditor_extra, cpp)
Qv2rayAddSource(ui, nodemodels, InboundNodeModel, cpp, hpp)
Qv2rayAddSource(ui, nodemodels, OutboundNodeModel, cpp, hpp)
Qv2rayAddSource(ui, nodemodels, RuleNodeModel, cpp, hpp)
Qv2rayAddSource(ui, nodemodels, NodeModelsBase, hpp)
Qv2rayAddSource(ui, messaging, QvMessageBus, cpp, hpp)
Qv2rayAddSource(ui, _, w_ExportConfig, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_ImportConfig, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_MainWindow, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_MainWindow_extra, cpp)
Qv2rayAddSource(ui, _, w_PreferencesWindow, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_ScreenShot_Core, cpp, hpp, ui)
Qv2rayAddSource(ui, _, w_SubscriptionManager, cpp, hpp, ui)
Qv2rayAddSource(ui, widgets, StreamSettingsWidget, cpp, hpp, ui)
SOURCES += $$PWD/src/main.cpp
HEADERS +=
FORMS +=
INCLUDEPATH += $$PWD/src
RESOURCES += $$PWD/resources.qrc
ICON = $$PWD/assets/icons/qv2ray.icns
RC_ICONS += $$PWD/assets/icons/qv2ray.ico
include($$PWD/makespec/02-translations.pri)
unix {
include($$PWD/makespec/03-unix.pri)
# Sub-process of Qv2ray per-OS build
!macx: include($$PWD/makespec/04-unix-linux.pri)
macx: include($$PWD/makespec/04-unix-macOS.pri)
} else {
include($$PWD/makespec/03-Windows.pri)
}
# ------------------------------------------ Begin checking protobuf domain list headers.
!exists($$PWD/libs/gen/v2ray_geosite.pb.cc) || !exists($$PWD/libs/gen/v2ray_geosite.pb.cc) {
Qv2rayQMakeError("Protobuf headers for v2ray geosite is missing.")
}
SOURCES += $$PWD/libs/gen/v2ray_geosite.pb.cc
HEADERS += $$PWD/libs/gen/v2ray_geosite.pb.h
# General header and source files for gRPC and libQvb
message(" ")
use_grpc {
DEFINES += WITH_LIB_GRPCPP
message("Qv2ray will use gRPC as API backend")
!exists($$PWD/libs/gen/v2ray_api.grpc.pb.h) || !exists($$PWD/libs/gen/v2ray_api.grpc.pb.cc) || !exists($$PWD/libs/gen/v2ray_api.pb.h) || !exists($$PWD/libs/gen/v2ray_api.pb.cc) {
Qv2rayQMakeError("gRPC and protobuf headers for v2ray API is missing.")
}
SOURCES += $$PWD/libs/gen/v2ray_api.pb.cc $$PWD/libs/gen/v2ray_api.grpc.pb.cc
HEADERS += $$PWD/libs/gen/v2ray_api.pb.h $$PWD/libs/gen/v2ray_api.grpc.pb.h
} else {
message("Qv2ray will use libqvb as API backend")
!exists($$PWD/libs/libqvb/build/libqvb.h) {
Qv2rayQMakeError("libs/libqvb/build/libqvb.h is missing.")
}
HEADERS += $$PWD/libs/libqvb/build/libqvb.h
}
# Misc steps to build Qv2ray.
include($$PWD/makespec/99-others.pri)
message(" ")
message("This Qv2ray build contains: ")
message(" --> $${size(SOURCES)} source files")
message(" --> $${size(HEADERS)} header files")
message(" --> $${size(FORMS)} ui files")
message(" --> $${size(TRANSLATIONS)} translation files")
message(" --> $${size(EXTRA_TRANSLATIONS)} extra translation files")
message(" ")
message("Finished configuring Qv2ray project. Build output will be at:" $$OUT_PWD)
message("Type 'make' or 'nmake' to start building Qv2ray")

50
_clang-format Normal file
View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg t="1583066988697" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7967" width="128" height="128"><path d="M524.474182 1024l-24.901818 0-6.958545-10.053818C481.652364 998.097455 223.837091 624.407273 187.485091 540.974545c-37.026909-84.968727-43.52-110.917818-43.52-173.428364C143.965091 164.864 308.852364 0 511.511273 0c203.682909 0 368.546909 164.864 368.546909 367.546182 0 62.533818-6.493091 88.459636-43.52 173.428364-36.375273 83.432727-294.144 457.099636-305.082182 472.971636L524.474182 1024zM512.512 46.545455C334.498909 46.545455 190.510545 190.557091 190.510545 367.546182c0 56.064 4.817455 74.891636 39.656727 154.833455 29.090909 66.792727 220.485818 348.020364 281.856 437.620364C573.416727 870.4 764.741818 589.172364 793.832727 522.379636c34.839273-79.965091 39.656727-98.769455 39.656727-154.833455C833.489455 190.557091 689.501091 46.545455 512.512 46.545455z" p-id="7968" fill="#e6e6e6"></path><path d="M512 565.364364c-93.835636 0-170.193455-76.334545-170.193455-170.193455S418.164364 225.000727 512 225.000727s170.193455 76.334545 170.193455 170.193455S605.835636 565.364364 512 565.364364zM512 271.546182c-68.189091 0-123.648 55.458909-123.648 123.648S443.810909 518.818909 512 518.818909s123.648-55.458909 123.648-123.648S580.189091 271.546182 512 271.546182z" p-id="7969" fill="#e6e6e6"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1583165428350" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2286" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M128 553.984l0-84.010667 512 0 0 84.010667-512 0zM128 256l768 0 0 86.016-768 0 0-86.016zM128 768l0-86.016 256 0 0 86.016-256 0z" p-id="2287" fill="#e6e6e6"></path></svg>

After

Width:  |  Height:  |  Size: 546 B

View File

@ -17,8 +17,8 @@
version="1.1" version="1.1"
id="svg8" id="svg8"
inkscape:version="0.92.4 5da689c313, 2019-01-14" inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="Qv2ray_System_Tray_Light.svg" sodipodi:docname="tray.svg"
inkscape:export-filename="/home/axionl/Desktop/Qv2ray_Design/qv2ray.png" inkscape:export-filename=""
inkscape:export-xdpi="558.54999" inkscape:export-xdpi="558.54999"
inkscape:export-ydpi="558.54999"> inkscape:export-ydpi="558.54999">
<defs <defs
@ -171,17 +171,17 @@
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="22.627417" inkscape:zoom="22.627417"
inkscape:cx="5.9585184" inkscape:cx="-1.0241611"
inkscape:cy="11.144438" inkscape:cy="11.144438"
inkscape:document-units="mm" inkscape:document-units="mm"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="true" showgrid="true"
units="px" units="px"
inkscape:window-width="1874" inkscape:window-width="1316"
inkscape:window-height="1050" inkscape:window-height="814"
inkscape:window-x="46" inkscape:window-x="270"
inkscape:window-y="30" inkscape:window-y="90"
inkscape:window-maximized="1" inkscape:window-maximized="0"
inkscape:snap-bbox="true" inkscape:snap-bbox="true"
inkscape:bbox-paths="true" inkscape:bbox-paths="true"
inkscape:bbox-nodes="true" inkscape:bbox-nodes="true"
@ -271,7 +271,7 @@
<path <path
id="path1962" id="path1962"
transform="matrix(0.26458333,0,0,0.26458333,1.9173392,290.74464)" transform="matrix(0.26458333,0,0,0.26458333,1.9173392,290.74464)"
style="fill:#f2f2f2;fill-opacity:1;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 7,11 6.2929688,11.707031 8.5859375,14 H 18 V 13 H 9 Z M 6.2929688,11.707031 5,13 H 4 v 1 H 5.4140625 L 7,12.414062 Z M 3,3 V 18.999988 H 19 V 3 Z M 3.9999999,3.9999875 H 18 V 18 H 3.9999999 Z" /> d="M 7,11 6.2929688,11.707031 8.5859375,14 H 18 V 13 H 9 Z M 6.2929688,11.707031 5,13 H 4 v 1 H 5.4140625 L 7,12.414062 Z M 3,3 V 18.999988 H 19 V 3 Z M 3.9999999,3.9999875 H 18 V 18 H 3.9999999 Z" />
<rect <rect
style="opacity:0.5;fill:none;fill-opacity:1;stroke:none;stroke-width:0.04583338;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="opacity:0.5;fill:none;fill-opacity:1;stroke:none;stroke-width:0.04583338;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@ -283,7 +283,7 @@
inkscape:export-xdpi="64" inkscape:export-xdpi="64"
inkscape:export-ydpi="64" /> inkscape:export-ydpi="64" />
<path <path
style="fill:#f2f2f2;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4.5631726,292.06756 -0.2645834,0.26459 v 0.52916 l 0.2645834,-0.26458 v 0.26458 0.52917 l 0.5291666,0.79375 0.5291667,1.32291 v -0.79374 l 0.2645833,-0.26459 -0.2645833,-0.52916 v -0.79375 l -0.2645833,-0.52917 z" d="m 4.5631726,292.06756 -0.2645834,0.26459 v 0.52916 l 0.2645834,-0.26458 v 0.26458 0.52917 l 0.5291666,0.79375 0.5291667,1.32291 v -0.79374 l 0.2645833,-0.26459 -0.2645833,-0.52916 v -0.79375 l -0.2645833,-0.52917 z"
id="path1934" id="path1934"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg t="1583066988697" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7967" width="128" height="128"><path d="M524.474182 1024l-24.901818 0-6.958545-10.053818C481.652364 998.097455 223.837091 624.407273 187.485091 540.974545c-37.026909-84.968727-43.52-110.917818-43.52-173.428364C143.965091 164.864 308.852364 0 511.511273 0c203.682909 0 368.546909 164.864 368.546909 367.546182 0 62.533818-6.493091 88.459636-43.52 173.428364-36.375273 83.432727-294.144 457.099636-305.082182 472.971636L524.474182 1024zM512.512 46.545455C334.498909 46.545455 190.510545 190.557091 190.510545 367.546182c0 56.064 4.817455 74.891636 39.656727 154.833455 29.090909 66.792727 220.485818 348.020364 281.856 437.620364C573.416727 870.4 764.741818 589.172364 793.832727 522.379636c34.839273-79.965091 39.656727-98.769455 39.656727-154.833455C833.489455 190.557091 689.501091 46.545455 512.512 46.545455z" p-id="7968" fill="#515151"></path><path d="M512 565.364364c-93.835636 0-170.193455-76.334545-170.193455-170.193455S418.164364 225.000727 512 225.000727s170.193455 76.334545 170.193455 170.193455S605.835636 565.364364 512 565.364364zM512 271.546182c-68.189091 0-123.648 55.458909-123.648 123.648S443.810909 518.818909 512 518.818909s123.648-55.458909 123.648-123.648S580.189091 271.546182 512 271.546182z" p-id="7969" fill="#515151"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1583165428350" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2286" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M128 553.984l0-84.010667 512 0 0 84.010667-512 0zM128 256l768 0 0 86.016-768 0 0-86.016zM128 768l0-86.016 256 0 0 86.016-256 0z" p-id="2287" fill="#2c2c2c"></path></svg>

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

26
assets/info.plist Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>qv2ray</string>
<key>CFBundleGetInfoString</key>
<string>Created by Qv2ray development team</string>
<key>CFBundleIconFile</key>
<string>qv2ray.icns</string>
<key>CFBundleIdentifier</key>
<string>com.qv2ray.qv2ray</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
<key>NOTE</key>
<string>Qv2ray</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>

48
assets/qv2ray.rc Normal file
View File

@ -0,0 +1,48 @@
#ifdef _WIN32
#include <WINDOWS.H>
#include <WINGDI.H>
#include <WINUSER.H>
#define xstr(s) str(s)
#define str(s) #s
#define VER_FILEVERSION QV2RAY_VERSION_MAJOR,QV2RAY_VERSION_MINOR,QV2RAY_VERSION_BUGFIX,QV2RAY_VERSION_BUILD
#define VER_FILEVERSION_STR xstr(VER_FILEVERSION)
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
IDI_ICON1 ICON DISCARDABLE "assets\\icons\\qv2ray.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Qv2ray Workgroup\0"
VALUE "FileDescription", "Qv2ray, a cross-platform v2ray GUI client.\0"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "LegalCopyright", "Qv2ray is being distributed under GPLv3\0"
VALUE "OriginalFilename", "qv2ray.exe\0"
VALUE "ProductName", "Qv2ray\0"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200
END
END
/* End of Version info */
#endif

50
cmake/backend.cmake Normal file
View File

@ -0,0 +1,50 @@
if(NOT USE_LIBQVB)
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
find_library(GRPC_LIBRARY NAMES grpc)
find_library(GRPCPP_LIBRARY NAMES grpc++)
if(UNIX AND NOT APPLE)
set(QV2RAY_BACKEND_LIBRARIES ${GRPCPP_LIBRARY} ${GRPC_LIBRARY})
elseif(APPLE)
find_library(UPB_LIBRARY NAMES upb)
set(QV2RAY_BACKEND_LIBRARIES ${GRPCPP_LIBRARY} ${GRPC_LIBRARY} ${UPB_LIBRARY})
elseif(WIN32)
find_library(ADDRESS_SORTING NAMES address_sorting)
find_library(ABSL_BASE NAMES absl_base)
find_library(ABSL_STR NAMES absl_strings)
find_library(ABSL_THROW_DELEGATE NAMES absl_throw_delegate)
find_library(GPR_LIBRARY NAMES gpr)
find_library(ZLIB_LIBRARY NAMES zlib)
find_library(UPB_LIBRARY NAMES upb)
find_library(CARES_LIBRARY NAMES cares)
find_library(GRPC_INSECURE_LIBRARY NAMES grpc_unsecure)
find_library(GRPCPP_INSECURE_LIBRARY NAMES grpc++_unsecure)
set(QV2RAY_BACKEND_LIBRARIES ${GRPC_INSECURE_LIBRARY} ${GRPCPP_INSECURE_LIBRARY} ${ABSL_BASE} ${ABSL_STR} ${ADDRESS_SORTING}
${ABSL_THROW_DELEGATE} ${GPR_LIBRARY} ${ZLIB_LIBRARY} ${UPB_LIBRARY} ${CARES_LIBRARY})
endif()
set(API_PROTO "${CMAKE_SOURCE_DIR}/tools/v2ray_api.proto")
set(API_PROTO_PATH "${CMAKE_SOURCE_DIR}/tools")
set(API_PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.pb.cc")
set(API_PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.pb.h")
set(API_GRPC_SRCS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.grpc.pb.cc")
set(API_GRPC_HDRS "${CMAKE_CURRENT_BINARY_DIR}/v2ray_api.grpc.pb.h")
add_custom_command(
OUTPUT "${API_GRPC_SRCS}" "${API_GRPC_HDRS}" "${API_PROTO_HDRS}" "${API_PROTO_SRCS}"
COMMAND ${Protobuf_PROTOC_EXECUTABLE}
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
-I "${API_PROTO_PATH}"
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
"${API_PROTO}"
DEPENDS "${API_PROTO}"
)
else()
add_definitions(-DBACKEND_LIBQVB)
if(UNIX AND NOT APPLE)
set(QV2RAY_BACKEND_LIBRARIES ${CMAKE_SOURCE_DIR}/libs/libqvb-linux64.a)
elseif(APPLE)
set(QV2RAY_BACKEND_LIBRARIES ${CMAKE_SOURCE_DIR}/libs/libqvb-darwin.a)
endif()
endif()

1
cmake/cpp-httplib.cmake Normal file
View File

@ -0,0 +1 @@
set(cpp-httplib_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/3rdparty/cpp-httplib)

23
cmake/deployment.cmake Normal file
View File

@ -0,0 +1,23 @@
# 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")
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}\")")

5
cmake/protobuf.cmake Normal file
View File

@ -0,0 +1,5 @@
find_package(Protobuf REQUIRED)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/tools/v2ray_geosite.proto)
set(QV2RAY_PROTOBUF_LIBRARY
protobuf::libprotobuf
)

69
cmake/qnodeeditor.cmake Normal file
View File

@ -0,0 +1,69 @@
set(QNODEEDITOR_DIR ${CMAKE_SOURCE_DIR}/3rdparty/QNodeEditor)
add_definitions(-DNODE_EDITOR_SHARED -DNODE_EDITOR_EXPORTS)
set(QNODEEDITOR_SOURCES
${QNODEEDITOR_DIR}/src/Connection.cpp
${QNODEEDITOR_DIR}/src/ConnectionBlurEffect.cpp
${QNODEEDITOR_DIR}/src/ConnectionGeometry.cpp
${QNODEEDITOR_DIR}/src/ConnectionGraphicsObject.cpp
${QNODEEDITOR_DIR}/src/ConnectionPainter.cpp
${QNODEEDITOR_DIR}/src/ConnectionState.cpp
${QNODEEDITOR_DIR}/src/ConnectionStyle.cpp
${QNODEEDITOR_DIR}/src/DataModelRegistry.cpp
${QNODEEDITOR_DIR}/src/FlowScene.cpp
${QNODEEDITOR_DIR}/src/FlowView.cpp
${QNODEEDITOR_DIR}/src/FlowViewStyle.cpp
${QNODEEDITOR_DIR}/src/Node.cpp
${QNODEEDITOR_DIR}/src/NodeConnectionInteraction.cpp
${QNODEEDITOR_DIR}/src/NodeDataModel.cpp
${QNODEEDITOR_DIR}/src/NodeGeometry.cpp
${QNODEEDITOR_DIR}/src/NodeGraphicsObject.cpp
${QNODEEDITOR_DIR}/src/NodePainter.cpp
${QNODEEDITOR_DIR}/src/NodeState.cpp
${QNODEEDITOR_DIR}/src/NodeStyle.cpp
${QNODEEDITOR_DIR}/src/Properties.cpp
${QNODEEDITOR_DIR}/src/StyleCollection.cpp
)
set(QNODEEDITOR_INCLUDE_PATH
${QNODEEDITOR_DIR}/src/
${QNODEEDITOR_DIR}/include/
${QNODEEDITOR_DIR}/include/nodes/
${QNODEEDITOR_DIR}/include/nodes/internal
)
set(HEADERS_TO_MOC
${QNODEEDITOR_DIR}/include/nodes/internal/Compiler.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/Connection.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionGeometry.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionGraphicsObject.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionState.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/ConnectionStyle.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/DataModelRegistry.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/Export.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/FlowScene.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/FlowView.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/FlowViewStyle.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/memory.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/Node.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodeData.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodeDataModel.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodeGeometry.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodeGraphicsObject.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodePainterDelegate.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodeState.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/NodeStyle.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/OperatingSystem.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/PortType.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/QStringStdHash.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/QUuidStdHash.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/Serializable.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/Style.hpp
${QNODEEDITOR_DIR}/include/nodes/internal/TypeConverter.hpp
)
qt5_wrap_cpp(QNODEEDITOR_SOURCES
${HEADERS_TO_MOC}
TARGET qv2ray
OPTIONS --no-notes # Don't display a note for the headers which don't produce a moc_*.cpp
)
set(QNODEEDITOR_QRC_RESOURCES ${QNODEEDITOR_DIR}/resources/QNodeEditor_resources.qrc)

97
cmake/qzxing.cmake Normal file
View File

@ -0,0 +1,97 @@
add_definitions(-DQZXING_LIBRARY -DZXING_ICONV_CONST -DDISABLE_LIBRARY_FEATURES -DENABLE_DECODER_QR_CODE -DENABLE_ENCODER_QR_CODE -DENABLE_ENCODER_GENERIC)
set(QZXING_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qzxing/src)
set(QZXING_SOURCES
${QZXING_DIR}/CameraImageWrapper.cpp
${QZXING_DIR}/QZXing.cpp
${QZXING_DIR}/ImageHandler.cpp
${QZXING_DIR}/zxing/zxing/ResultIO.cpp
${QZXING_DIR}/zxing/zxing/InvertedLuminanceSource.cpp
${QZXING_DIR}/zxing/zxing/ChecksumException.cpp
${QZXING_DIR}/zxing/zxing/ResultPointCallback.cpp
${QZXING_DIR}/zxing/zxing/ResultPoint.cpp
${QZXING_DIR}/zxing/zxing/Result.cpp
${QZXING_DIR}/zxing/zxing/ResultMetadata.cpp
${QZXING_DIR}/zxing/zxing/Reader.cpp
${QZXING_DIR}/zxing/zxing/MultiFormatReader.cpp
${QZXING_DIR}/zxing/zxing/LuminanceSource.cpp
${QZXING_DIR}/zxing/zxing/FormatException.cpp
${QZXING_DIR}/zxing/zxing/Exception.cpp
${QZXING_DIR}/zxing/zxing/DecodeHints.cpp
${QZXING_DIR}/zxing/zxing/BinaryBitmap.cpp
${QZXING_DIR}/zxing/zxing/Binarizer.cpp
${QZXING_DIR}/zxing/zxing/BarcodeFormat.cpp
${QZXING_DIR}/zxing/zxing/ReaderException.cpp
${QZXING_DIR}/zxing/zxing/IllegalStateException.cpp
${QZXING_DIR}/zxing/zxing/NotFoundException.cpp
${QZXING_DIR}/zxing/zxing/WriterException.cpp
${QZXING_DIR}/zxing/zxing/common/Counted.cpp
${QZXING_DIR}/zxing/zxing/common/StringUtils.cpp
${QZXING_DIR}/zxing/zxing/common/Str.cpp
${QZXING_DIR}/zxing/zxing/common/PerspectiveTransform.cpp
${QZXING_DIR}/zxing/zxing/common/IllegalArgumentException.cpp
${QZXING_DIR}/zxing/zxing/common/HybridBinarizer.cpp
${QZXING_DIR}/zxing/zxing/common/GridSampler.cpp
${QZXING_DIR}/zxing/zxing/common/GreyscaleRotatedLuminanceSource.cpp
${QZXING_DIR}/zxing/zxing/common/GreyscaleLuminanceSource.cpp
${QZXING_DIR}/zxing/zxing/common/GlobalHistogramBinarizer.cpp
${QZXING_DIR}/zxing/zxing/common/DetectorResult.cpp
${QZXING_DIR}/zxing/zxing/common/DecoderResult.cpp
${QZXING_DIR}/zxing/zxing/common/CharacterSetECI.cpp
${QZXING_DIR}/zxing/zxing/common/BitSource.cpp
${QZXING_DIR}/zxing/zxing/common/BitMatrix.cpp
${QZXING_DIR}/zxing/zxing/common/BitArray.cpp
${QZXING_DIR}/zxing/zxing/common/BitArrayIO.cpp
${QZXING_DIR}/zxing/zxing/common/detector/WhiteRectangleDetector.cpp
${QZXING_DIR}/zxing/zxing/common/detector/MonochromeRectangleDetector.cpp
${QZXING_DIR}/zxing/zxing/common/reedsolomon/ReedSolomonException.cpp
${QZXING_DIR}/zxing/zxing/common/reedsolomon/ReedSolomonDecoder.cpp
${QZXING_DIR}/zxing/zxing/common/reedsolomon/GenericGFPoly.cpp
${QZXING_DIR}/zxing/zxing/common/reedsolomon/GenericGF.cpp
${QZXING_DIR}/zxing/zxing/multi/MultipleBarcodeReader.cpp
${QZXING_DIR}/zxing/zxing/multi/GenericMultipleBarcodeReader.cpp
${QZXING_DIR}/zxing/zxing/multi/ByQuadrantReader.cpp
${QZXING_DIR}/zxing/bigint/BigUnsignedInABase.cc
${QZXING_DIR}/zxing/bigint/BigUnsigned.cc
${QZXING_DIR}/zxing/bigint/BigIntegerUtils.cc
${QZXING_DIR}/zxing/bigint/BigIntegerAlgorithms.cc
${QZXING_DIR}/zxing/bigint/BigInteger.cc
${QZXING_DIR}/zxing/zxing/qrcode/decoder/QRBitMatrixParser.cpp
${QZXING_DIR}/zxing/zxing/qrcode/decoder/QRDataBlock.cpp
${QZXING_DIR}/zxing/zxing/qrcode/decoder/QRDataMask.cpp
${QZXING_DIR}/zxing/zxing/qrcode/decoder/QRDecodedBitStreamParser.cpp
${QZXING_DIR}/zxing/zxing/qrcode/decoder/QRDecoder.cpp
${QZXING_DIR}/zxing/zxing/qrcode/detector/QRAlignmentPattern.cpp
${QZXING_DIR}/zxing/zxing/qrcode/detector/QRAlignmentPatternFinder.cpp
${QZXING_DIR}/zxing/zxing/qrcode/detector/QRDetector.cpp
${QZXING_DIR}/zxing/zxing/qrcode/detector/QRFinderPattern.cpp
${QZXING_DIR}/zxing/zxing/qrcode/detector/QRFinderPatternFinder.cpp
${QZXING_DIR}/zxing/zxing/qrcode/detector/QRFinderPatternInfo.cpp
${QZXING_DIR}/zxing/zxing/qrcode/QRCodeReader.cpp
${QZXING_DIR}/zxing/zxing/multi/qrcode/QRCodeMultiReader.cpp
${QZXING_DIR}/zxing/zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp
${QZXING_DIR}/zxing/zxing/multi/qrcode/detector/MultiDetector.cpp
${QZXING_DIR}/zxing/zxing/qrcode/encoder/ByteMatrix.cpp
${QZXING_DIR}/zxing/zxing/qrcode/encoder/QREncoder.cpp
${QZXING_DIR}/zxing/zxing/qrcode/encoder/MaskUtil.cpp
${QZXING_DIR}/zxing/zxing/qrcode/encoder/MatrixUtil.cpp
${QZXING_DIR}/zxing/zxing/qrcode/encoder/QRCode.cpp
${QZXING_DIR}/zxing/zxing/qrcode/QRVersion.cpp
${QZXING_DIR}/zxing/zxing/qrcode/QRFormatInformation.cpp
${QZXING_DIR}/zxing/zxing/qrcode/QRErrorCorrectionLevel.cpp
${QZXING_DIR}/zxing/zxing/qrcode/decoder/QRMode.cpp
${QZXING_DIR}/zxing/zxing/EncodeHint.cpp
${QZXING_DIR}/zxing/zxing/UnsupportedEncodingException.cpp
${QZXING_DIR}/zxing/zxing/common/reedsolomon/ReedSolomonEncoder.cpp
)
set(QZXING_INCLUDE_PATH
${QZXING_DIR}
${QZXING_DIR}/zxing
)
if(MSVC)
add_definitions(-D__STDC_LIMIT_MACROS)
list(APPEND QZXING_SOURCES ${QZXING_DIR}/zxing/win32/zxing/win_iconv.c)
list(APPEND QZXING_INCLUDE_PATH
${QZXING_DIR}/zxing/win32/zxing
${QZXING_DIR}/zxing/win32/zxing/msvc
)
endif()

View File

@ -0,0 +1,6 @@
add_definitions(-DQAPPLICATION_CLASS=QApplication)
set(SINGLEAPPLICATION_DIR ${CMAKE_SOURCE_DIR}/3rdparty/SingleApplication)
set(SINGLEAPPLICATION_SOURCES
${SINGLEAPPLICATION_DIR}/singleapplication.cpp
${SINGLEAPPLICATION_DIR}/singleapplication_p.cpp
)

4
cmake/translations.cmake Normal file
View File

@ -0,0 +1,4 @@
find_package(Qt5 COMPONENTS LinguistTools)
set(TRANSLATIONS_DIR ${CMAKE_SOURCE_DIR}/translations)
file(GLOB TRANSLATIONS_TS ${TRANSLATIONS_DIR}/**.ts)
qt5_add_translation(QM_FILES ${TRANSLATIONS_TS})

1
libs/puresource Submodule

@ -0,0 +1 @@
Subproject commit bd4f9335bb89e7b1199282c685d49dd5ae4ce1fa

View File

@ -1,48 +0,0 @@
message(" ")
message("Configuring Qv2ray Dependencies...")
defineTest(Qv2rayQMakeError) {
message(" ")
message("-----------------------------------------------")
message("Cannot continue: ")
message(" --> Qv2ray is not properly configured yet: ")
message(" $$ARGS")
message(" --> Please read the build wiki: https://github.com/Qv2ray/Qv2ray/wiki/Manually-Build-Qv2ray")
message("-----------------------------------------------")
message(" ")
warning("IF YOU THINK IT'S A MISTAKE, PLEASE OPEN AN ISSUE")
error("! ABORTING THE BUILD !")
message(" ")
}
CONFIG += enable_decoder_qr_code enable_encoder_qr_code
include($$PWD/../3rdparty/qzxing/src/QZXing-components.pri)
include($$PWD/../3rdparty/SingleApplication/singleapplication.pri)
include($$PWD/../3rdparty/QNodeEditor/QNodeEditor.pri)
#include(3rdparty/x2struct/x2struct.pri)
message("Adding QHttpServer Support")
message(" --> Adding qhttpserver")
HEADERS += \
$$PWD/../3rdparty/qhttpserver/src/qhttpconnection.h \
$$PWD/../3rdparty/qhttpserver/src/qhttprequest.h \
$$PWD/../3rdparty/qhttpserver/src/qhttpresponse.h \
$$PWD/../3rdparty/qhttpserver/src/qhttpserver.h \
$$PWD/../3rdparty/qhttpserver/src/qhttpserverapi.h \
$$PWD/../3rdparty/qhttpserver/src/qhttpserverfwd.h
SOURCES += \
$$PWD/../3rdparty/qhttpserver/src/qhttpconnection.cpp \
$$PWD/../3rdparty/qhttpserver/src/qhttprequest.cpp \
$$PWD/../3rdparty/qhttpserver/src/qhttpresponse.cpp \
$$PWD/../3rdparty/qhttpserver/src/qhttpserver.cpp
INCLUDEPATH += 3rdparty/qhttpserver/src/
message(" --> Adding http parser")
HEADERS += $$PWD/../3rdparty/qhttpserver/http-parser/http_parser.h
SOURCES += $$PWD/../3rdparty/qhttpserver/http-parser/http_parser.c
INCLUDEPATH += $$PWD/../3rdparty/qhttpserver/http-parser/

View File

@ -1,50 +0,0 @@
message(" ")
defineTest(Qv2rayAddFile) {
ext = $$take_last(ARGS)
filename = $${take_first(ARGS)}.$${ext}
qmake_debug: message("Qv2rayAddFile: filename: $$filename")
!exists($$filename) {
error("File: \"$$filename\" is not found, Qv2ray build preparation cannot continue")
}
equals(ext, "cpp") {
SOURCES += $$filename
} else {
equals(ext, "hpp") {
HEADERS += $$filename
} else {
equals(ext, "ui") {
FORMS += $$filename
} else {
error("Unknown extension: $${ext}")
}
}
}
export(SOURCES)
export(HEADERS)
export(FORMS)
}
defineTest(Qv2rayAddSource) {
# Module Compnent Filename extlist
module = $$take_first(ARGS)
component = $$take_first(ARGS)
filename = $$take_first(ARGS)
extlist = $$ARGS
FILEPATH = "$$PWD/src/$${module}"
qmake_debug: message(Qv2rayAddSource: Adding \"$${filename}\" of module \"$${module}\", component \"$${component}\" to the project)
equals(component, "_") {
qmake_debug: message("Qv2rayAddSource: Component is empty, ignore")
FILEPATH += "/$${filename}"
FILEPATH=$$join(FILEPATH)
} else {
FILEPATH += "/$${component}/$${filename}"
FILEPATH=$$join(FILEPATH)
}
qmake_debug: message("Qv2rayAddSource: filepath: $${FILEPATH}, extlist: $${extlist}")
for(iterate, extlist) {
Qv2rayAddFile($$FILEPATH, $$iterate)
}
export(SOURCES)
export(HEADERS)
export(FORMS)
}

View File

@ -1,24 +0,0 @@
message(" ")
message("Looking for language support.")
QM_FILES_RESOURCE_PREFIX = "translations"
for(var, $$list($$files("$$PWD/../translations/*.ts", true))) {
LOCALE_FILENAME = $$basename(var)
message(" --> Found:" $$LOCALE_FILENAME)
!equals(LOCALE_FILENAME, "en_US.ts") {
# ONLY USED IN LRELEASE CONTEXT
# en_US is not EXTRA...
EXTRA_TRANSLATIONS += $$PWD/../translations/$$LOCALE_FILENAME
}
}
TRANSLATIONS += $$PWD/../translations/en_US.ts
message("Qv2ray will build with" $${replace(EXTRA_TRANSLATIONS, "$$PWD/../translations/", "")} and $${replace(TRANSLATIONS, "$$PWD/../translations/", "")})
qmake_lupdate {
message(" ")
message("Running lupdate...")
message("TRANSLATIONS: $$TRANSLATIONS")
lupdate_output = $$system(lupdate -no-ui-lines $$SOURCES $$HEADERS $$FORMS -ts $$TRANSLATIONS)
message(" $$lupdate_output")
message("lupdate finished.")
}

View File

@ -1,43 +0,0 @@
message(" ")
message("Configuring for Windows environment")
QMAKE_CXXFLAGS += /MP /wo4251
DEFINES += QHTTPSERVER_EXPORT
CONFIG += Qv2ray_Windows use_grpc
!contains(QMAKE_TARGET.arch, x86_64) {
CONFIG+=Qv2ray_win32
GRPC_DEPS_PATH=$$PWD/../libs/x86-windows
#
!no_generate_headers: message(" --> Generating gRPC and protobuf headers for Windows x86")
!no_generate_headers: system("$$PWD/../tools/win32-generate-pb.bat")
} else {
CONFIG+=Qv2ray_win64
GRPC_DEPS_PATH=$$PWD/../libs/x64-windows
#
!no_generate_headers: message(" --> Generating gRPC and protobuf headers for Windows x64")
!no_generate_headers: system("$$PWD/../tools/win64-generate-pb.bat")
}
message(" --> Applying a hack for protobuf header")
DEFINES += _WIN32_WINNT=0x600
DEPENDPATH += $$GRPC_DEPS_PATH/include
INCLUDEPATH += $$GRPC_DEPS_PATH/include
message(" --> Setting up target descriptions")
QMAKE_TARGET_DESCRIPTION = "Qv2ray, a cross-platform v2ray GUI client."
QMAKE_TARGET_PRODUCT = "Qv2ray"
Qv2ray_debug: GRPC_LIB_PATH=$$GRPC_DEPS_PATH/debug
Qv2ray_release: GRPC_LIB_PATH=$$GRPC_DEPS_PATH
message(" --> WIN32: Linking against gRPC library: $$GRPC_LIB_PATH")
Qv2ray_debug: LIBS += -L$$GRPC_LIB_PATH/lib/ -laddress_sorting -lcares -lgrpc++_unsecure -lupb -lzlibd -lgrpc_unsecure -lgpr -labsl_base -labsl_strings -labsl_throw_delegate
Qv2ray_release: LIBS += -L$$GRPC_LIB_PATH/lib/ -laddress_sorting -lcares -lgrpc++_unsecure -lupb -lzlib -lgrpc_unsecure -lgpr -labsl_base -labsl_strings -labsl_throw_delegate
message(" --> WIN32: Linking against protobuf library: $$GRPC_LIB_PATH")
Qv2ray_release: LIBS += -lmsvcrt -L$$GRPC_LIB_PATH/lib/ -llibprotobuf
Qv2ray_debug: LIBS += -lmsvcrtd -L$$GRPC_LIB_PATH/lib/ -llibprotobufd
message(" --> Linking against winHTTP and winSock2.")
LIBS += -lwinhttp -lwininet -lws2_32 -luser32

View File

@ -1,28 +0,0 @@
message(" ")
win32: Qv2rayQMakeError("Do not include this file in Windows platform.")
# For Linux and macOS
message("Configuring for unix-like environment")
message(" --> Setting up QMAKE_CXXFLAGS")
QMAKE_CXXFLAGS += -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable
# macOS homebrew include path
message(" --> Adding local include folder to search path")
INCLUDEPATH += /usr/local/include/
# For protobuf in linux and macOS
message(" --> Linking against protobuf library.")
LIBS += -L/usr/local/lib -lprotobuf
message(" --> Generating geosite headers for Unix")
system("$$PWD/../tools/unix-generate-geosite.sh $$PWD")
use_grpc {
no_generate_headers {
message(" --> Skipped generation of protobuf and/or gRPC header files")
} else {
message(" --> Generating gRPC and protobuf headers for Unix")
system("$$PWD/../tools/unix-generate-api.sh $$PWD")
}
}

View File

@ -1,26 +0,0 @@
message(" ")
message("Configuring Qv2ray build for Linux")
isEmpty(PREFIX) {
PREFIX=/usr/local
}
use_grpc {
# For gRPC and protobuf in linux
message(" --> Linking against gRPC and protobuf library.")
LIBS += -L/usr/local/lib -lgrpc++ -lgrpc
} else {
message(" --> Linking libqvb static library, for Linux platform.")
LIBS += -L$$PWD/../libs/ -lqvb-linux64
}
message(" --> Generating desktop dependency.")
desktop.files += $$PWD/../assets/qv2ray.desktop
desktop.path = $$PREFIX/share/applications/
message(" --> Generating icons dependency.")
icon.files += $$PWD/../assets/icons/qv2ray.png
icon.path = $$PREFIX/share/icons/hicolor/256x256/apps/
target.path = $$PREFIX/bin/
INSTALLS += target desktop icon

View File

@ -1,11 +0,0 @@
message(" ")
# For Linux and macOS
message("Configuring for macOS specific environment")
LIBS += -framework Carbon -framework Cocoa
use_grpc: error("The use of gRPC backend is not supported on macOS platform.")
message(" --> Linking libqvb static library and Security framework, for macOS platform.")
LIBS += -L$$PWD/../libs/ -lqvb-darwin
LIBS += -framework Security

View File

@ -1,39 +0,0 @@
message(" ")
with_metainfo {
message(" --> Generating metainfo dependency.")
appdataXml.files += ./assets/qv2ray.metainfo.xml
appdataXml.path = $$PREFIX/share/metainfo/
INSTALLS += appdataXml
DEFINES += WITH_FLATHUB_CONFIG_PATH
}
# Automatically increase build number.
no_increase_build_number | qmake_lupdate {
message("QV2RAY_BUILD_VERSION will not be increased")
} else {
QV2RAY_BUILD_VERSION = $$num_add($$QV2RAY_BUILD_VERSION, 1)
write_file($$PWD/BUILDVERSION, QV2RAY_BUILD_VERSION)
}
# Qv2ray manual build info
!no_build_info {
_QV2RAY_BUILD_INFO_STR_=$$getenv(_QV2RAY_BUILD_INFO_)
_QV2RAY_BUILD_EXTRA_INFO_STR_=$$getenv(_QV2RAY_BUILD_EXTRA_INFO_)
isEmpty(_QV2RAY_BUILD_INFO_STR_) {
_QV2RAY_BUILD_INFO_STR_ = "Qv2ray from manual build"
}
isEmpty(_QV2RAY_BUILD_EXTRA_INFO_STR_) {
_QV2RAY_BUILD_EXTRA_INFO_STR_ = "Qv2ray $$VERSION"
}
} else {
_QV2RAY_BUILD_INFO_STR_ = "No Info"
_QV2RAY_BUILD_EXTRA_INFO_STR_ = "No Extra Info"
}
message("Qv2ray build info:")
message(" --> $$_QV2RAY_BUILD_INFO_STR_")
message(" --> $$_QV2RAY_BUILD_EXTRA_INFO_STR_")
DEFINES += _QV2RAY_BUILD_INFO_STR_=\"\\\"$${_QV2RAY_BUILD_INFO_STR_}\\\"\" _QV2RAY_BUILD_EXTRA_INFO_STR_=\"\\\"$${_QV2RAY_BUILD_EXTRA_INFO_STR_}\\\"\"

View File

@ -1 +1 @@
3861 4685

294
qv2ray-config-models.qmodel Normal file
View File

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<qmt>
<project>
<uid>{e33c4c89-9b5b-44c4-9790-17cef05732d8}</uid>
<root-package>
<instance>
<MPackage>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{6035e8ea-cf65-4a95-b11b-59d640802d5e}</uid>
</MElement>
</base-MElement>
<name>Qv2ray-config-models</name>
<children>
<handles>
<handles>
<qlist>
<item>
<handle>
<uid>{0a303cb9-6681-4f79-9779-e61a34ac44ea}</uid>
<target>
<instance type="MCanvasDiagram">
<MCanvasDiagram>
<base-MDiagram>
<MDiagram>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{0a303cb9-6681-4f79-9779-e61a34ac44ea}</uid>
</MElement>
</base-MElement>
<name>Qv2ray-config-models</name>
</MObject>
</base-MObject>
<elements>
<qlist>
<item>
<instance type="DItem">
<DItem>
<base-DObject>
<DObject>
<base-DElement>
<DElement>
<uid>{89aa1d96-388b-49c0-a4e6-bf55bb570889}</uid>
</DElement>
</base-DElement>
<object>{314756b5-bc93-49b8-ae97-957fe8b30d44}</object>
<name>BaseGroupObject</name>
<pos>x:410;y:235</pos>
<rect>x:-75;y:-50;w:150;h:100</rect>
<auto-sized>false</auto-sized>
<visual-role>0</visual-role>
</DObject>
</base-DObject>
<shape-editable>false</shape-editable>
</DItem>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{7dd68311-11eb-43d0-9e64-91daeae12d97}</uid>
</DElement>
</base-DElement>
<text>Display Name</text>
<pos>x:350;y:215</pos>
<rect>x:0;y:0;w:84.2031;h:30</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DBoundary">
<DBoundary>
<base-DElement>
<DElement>
<uid>{e51a8692-6ecb-4052-8e09-f1b1ee3a2b92}</uid>
</DElement>
</base-DElement>
<text>Connection Groups</text>
<pos>x:260;y:230</pos>
<rect>x:-235;y:-75;w:470;h:150</rect>
</DBoundary>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{b4dc36e8-31f6-4637-9f8f-c27ee155e301}</uid>
</DElement>
</base-DElement>
<text>List&lt;ConnectionId&gt;</text>
<pos>x:350;y:235</pos>
<rect>x:0;y:0;w:111.391;h:30</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DBoundary">
<DBoundary>
<base-DElement>
<DElement>
<uid>{ffc9dfd5-2441-4b3b-b814-3ac76fb03c7e}</uid>
</DElement>
</base-DElement>
<text>Subscriptions</text>
<pos>x:565;y:230</pos>
<rect>x:-240;y:-75;w:480;h:150</rect>
</DBoundary>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{3634dcd7-fac8-4993-b3e7-c10450dae1de}</uid>
</DElement>
</base-DElement>
<text>Nothing here since the base group
is enough</text>
<pos>x:85;y:215</pos>
<rect>x:0;y:0;w:186.047;h:44</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DAnnotation">
<DAnnotation>
<base-DElement>
<DElement>
<uid>{41e1ca4e-8395-472f-8470-912cf2c7b9d1}</uid>
</DElement>
</base-DElement>
<text>Some other metadata of subscription</text>
<pos>x:535;y:220</pos>
<rect>x:0;y:0;w:199.766;h:30</rect>
</DAnnotation>
</instance>
</item>
<item>
<instance type="DItem">
<DItem>
<base-DObject>
<DObject>
<base-DElement>
<DElement>
<uid>{d27ab510-0eda-4d06-ac71-cd8b1d68571f}</uid>
</DElement>
</base-DElement>
<object>{48b1692c-e2da-49cb-b1da-dd1030084013}</object>
<name>Address, last-renewed......</name>
<pos>x:610;y:205</pos>
<rect>x:-75;y:-15;w:150;h:30</rect>
<visual-role>0</visual-role>
</DObject>
</base-DObject>
<shape-editable>false</shape-editable>
</DItem>
</instance>
</item>
</qlist>
</elements>
<last-modified>1581683831371</last-modified>
<toolbarid>General</toolbarid>
</MDiagram>
</base-MDiagram>
</MCanvasDiagram>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{314756b5-bc93-49b8-ae97-957fe8b30d44}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{314756b5-bc93-49b8-ae97-957fe8b30d44}</uid>
</MElement>
</base-MElement>
<name>BaseGroupObject</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{e2922977-d357-43f0-822a-624245d6b470}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{e2922977-d357-43f0-822a-624245d6b470}</uid>
</MElement>
</base-MElement>
<name>New Item</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{8a788e13-b40c-4a33-8121-f0a4817428b1}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{8a788e13-b40c-4a33-8121-f0a4817428b1}</uid>
</MElement>
</base-MElement>
<name>Address</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{ec54fd48-400e-4e7d-9e74-b6333d2101c1}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{ec54fd48-400e-4e7d-9e74-b6333d2101c1}</uid>
</MElement>
</base-MElement>
<name>Some other metadata of subscription</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
<item>
<handle>
<uid>{48b1692c-e2da-49cb-b1da-dd1030084013}</uid>
<target>
<instance type="MItem">
<MItem>
<base-MObject>
<MObject>
<base-MElement>
<MElement>
<uid>{48b1692c-e2da-49cb-b1da-dd1030084013}</uid>
</MElement>
</base-MElement>
<name>Address, last-renewed......</name>
</MObject>
</base-MObject>
</MItem>
</instance>
</target>
</handle>
</item>
</qlist>
</handles>
</handles>
</children>
</MObject>
</base-MObject>
</MPackage>
</instance>
</root-package>
</project>
</qmt>

2321
qv2ray-new.qmodel Normal file

File diff suppressed because it is too large Load Diff

2187
qv2ray.qmodel Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,5 +24,13 @@
<file>assets/icons/qv2ray.ico</file> <file>assets/icons/qv2ray.ico</file>
<file>assets/icons/qv2ray.png</file> <file>assets/icons/qv2ray.png</file>
<file>assets/credit.html</file> <file>assets/credit.html</file>
<file>assets/icons/ui_dark/connect.png</file>
<file>assets/icons/ui_light/connect.png</file>
<file>assets/icons/ui_dark/stop.png</file>
<file>assets/icons/ui_light/stop.png</file>
<file>assets/icons/ui_dark/locate.png</file>
<file>assets/icons/ui_light/locate.png</file>
<file>assets/icons/ui_dark/sort.png</file>
<file>assets/icons/ui_light/sort.png</file>
</qresource> </qresource>
</RCC> </RCC>

174
snap/plugins/x_cmake.py Normal file
View File

@ -0,0 +1,174 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2015-2016 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# 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 <http://www.gnu.org/licenses/>.
"""The cmake plugin is useful for building cmake based parts.
These are projects that have a CMakeLists.txt that drives the build.
The plugin requires a CMakeLists.txt in the root of the source tree.
If the part has a list of build-snaps listed, the part will be set up in
such a way that the paths to those snaps are used as paths for find_package
and find_library by use of `CMAKE_FIND_ROOT_PATH``.
This plugin uses the common plugin keywords as well as those for "sources".
For more information check the 'plugins' topic for the former and the
'sources' topic for the latter.
Additionally, this plugin uses the following plugin-specific keywords:
- configflags:
(list of strings)
configure flags to pass to the build using the common cmake semantics.
"""
import logging
import os
from typing import List, Optional
import subprocess
import snapcraft
from snapcraft.internal import errors
logger = logging.getLogger(name=__name__)
class _Flag:
def __str__(self) -> str:
if self.value is None:
flag = self.name
else:
flag = "{}={}".format(self.name, self.value)
return flag
def __init__(self, flag: str) -> None:
parts = flag.split("=")
self.name = parts[0]
try:
self.value: Optional[str] = parts[1]
except IndexError:
self.value = None
class CMakePlugin(snapcraft.BasePlugin):
@classmethod
def schema(cls):
schema = super().schema()
schema["properties"]["configflags"] = {
"type": "array",
"minitems": 1,
"uniqueItems": True,
"items": {"type": "string"},
"default": [],
}
# For backwards compatibility
schema["properties"]["make-parameters"] = {
"type": "array",
"minitems": 1,
"uniqueItems": True,
"items": {"type": "string"},
"default": [],
}
schema["required"] = ["source"]
return schema
@classmethod
def get_build_properties(cls):
# Inform Snapcraft of the properties associated with building. If these
# change in the YAML Snapcraft will consider the build step dirty.
return super().get_build_properties() + ["configflags"]
def __init__(self, name, options, project):
super().__init__(name, options, project)
self.build_packages.append("cmake")
self.build_packages.append("ninja-build")
self.out_of_source_build = True
cmd = '''
echo 'deb http://archive.neon.kde.org/unstable bionic main' > /etc/apt/sources.list.d/neon.list
echo 'deb http://ppa.launchpad.net/ymshenyu/grpc-1/ubuntu bionic main' > /etc/apt/sources.list.d/grpc.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E6D4736255751E5D
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 281f24e574404629aa3bda1a4f10c386c55cdb04
sudo apt update -qq
'''
subprocess.call(cmd, shell=True)
if project.info.get_build_base() not in ("core", "core16", "core18"):
raise errors.PluginBaseError(
part_name=self.name, base=project.info.get_build_base()
)
if options.make_parameters:
logger.warning("make-paramaters is deprecated, ignoring.")
def build(self):
source_subdir = getattr(self.options, "source_subdir", None)
if source_subdir:
sourcedir = os.path.join(self.sourcedir, source_subdir)
else:
sourcedir = self.sourcedir
env = self._build_environment()
configflags = self._get_processed_flags()
self.run(["cmake", sourcedir, "-DCMAKE_INSTALL_PREFIX="] + configflags, env=env)
# TODO: there is a better way to specify the job count on newer versions of cmake
# https://github.com/Kitware/CMake/commit/1ab3881ec9e809ac5f6cad5cd84048310b8683e2
self.run(
["cmake", "--build", ".", "--", "-j{}".format(self.parallel_build_count)],
env=env,
)
self.run(["cmake", "--build", ".", "--target", "install"], env=env)
def _get_processed_flags(self) -> List[str]:
# Return the original if no build_snaps are in options.
if not self.options.build_snaps:
return self.options.configflags
build_snap_paths = [
os.path.join(os.path.sep, "snap", snap_name.split("/")[0], "current")
for snap_name in self.options.build_snaps
]
flags = [_Flag(f) for f in self.options.configflags]
for flag in flags:
if flag.name == "-DCMAKE_FIND_ROOT_PATH":
flag.value = "{};{}".format(flag.value, ";".join(build_snap_paths))
break
else:
flags.append(
_Flag("-DCMAKE_FIND_ROOT_PATH={}".format(";".join(build_snap_paths)))
)
return [str(f) for f in flags]
def _build_environment(self):
env = os.environ.copy()
env["DESTDIR"] = self.installdir
env["CMAKE_PREFIX_PATH"] = "$CMAKE_PREFIX_PATH:{}".format(
self.project.stage_dir
)
env["CMAKE_INCLUDE_PATH"] = "$CMAKE_INCLUDE_PATH:" + ":".join(
["{0}/include", "{0}/usr/include", "{0}/include/{1}", "{0}/usr/include/{1}"]
).format(self.project.stage_dir, self.project.arch_triplet)
env["CMAKE_LIBRARY_PATH"] = "$CMAKE_LIBRARY_PATH:" + ":".join(
["{0}/lib", "{0}/usr/lib", "{0}/lib/{1}", "{0}/usr/lib/{1}"]
).format(self.project.stage_dir, self.project.arch_triplet)
return env

View File

@ -3,8 +3,8 @@ base: core18
adopt-info: qv2ray adopt-info: qv2ray
icon: assets/icons/qv2ray.png icon: assets/icons/qv2ray.png
grade: devel grade: stable
confinement: devmode confinement: strict
plugs: plugs:
gsettings: gsettings:
@ -26,18 +26,33 @@ apps:
command: bin/desktop-launch qv2ray command: bin/desktop-launch qv2ray
environment: environment:
QT_QPA_PLATFORMTHEME: gtk3 QT_QPA_PLATFORMTHEME: gtk3
plugs:
- home
- x11
- wayland
- opengl
- network
- network-bind
- unity7
- pulseaudio
- desktop
- desktop-legacy
- gsettings
- network-control
- network-manager
common-id: com.github.Qv2ray common-id: com.github.Qv2ray
desktop: "usr/share/applications/qv2ray.desktop" desktop: "usr/share/applications/qv2ray.desktop"
parts: parts:
qv2ray: qv2ray:
plugin: qmake plugin: x-cmake
source-type: git source-type: git
source: . source: .
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-tools
- qttools5-dev
- qt5-default - qt5-default
- libgrpc++-dev - libgrpc++-dev
- libprotobuf-dev - libprotobuf-dev
@ -52,12 +67,12 @@ parts:
- libqt5gui5 - libqt5gui5
- libqt5network5 - libqt5network5
- libqt5widgets5 - libqt5widgets5
- fonts-noto-cjk
- libglib2.0-bin - libglib2.0-bin
options: configflags:
- PREFIX=/usr - -DCMAKE_INSTALL_PREFIX=/usr
- CONFIG+=with_metainfo - -DCMAKE_BUILD_TYPE=Release
- CONFIG+=use_grpc - -GNinja
- -DEMBED_TRANSLATIONS=ON
override-pull: | override-pull: |
snapcraftctl pull snapcraftctl pull
build_number=$(cat makespec/BUILDVERSION) build_number=$(cat makespec/BUILDVERSION)
@ -66,7 +81,6 @@ parts:
snapcraftctl set-version "$version" snapcraftctl set-version "$version"
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:
- mytools
- desktop-qt5 - desktop-qt5
desktop-qt5: desktop-qt5:
@ -93,28 +107,8 @@ parts:
- locales-all - locales-all
- xdg-user-dirs - xdg-user-dirs
- fcitx-frontend-qt5 - fcitx-frontend-qt5
after:
- mytools
qt5-gtk-platform: qt5-gtk-platform:
plugin: nil plugin: nil
stage-packages: stage-packages:
- qt5-gtk-platformtheme - qt5-gtk-platformtheme
after:
- mytools
mytools:
plugin: nil
build-packages:
- dirmngr
override-pull: |
echo 'deb http://archive.neon.kde.org/unstable bionic main' > /etc/apt/sources.list.d/neon.list
echo 'deb http://ppa.launchpad.net/ymshenyu/grpc-1/ubuntu bionic main' >> /etc/apt/sources.list.d/tools.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E6D4736255751E5D
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 281f24e574404629aa3bda1a4f10c386c55cdb04
sudo apt-get update
snapcraftctl pull
override-build: |
snapcraftctl build
sudo apt upgrade -y
sudo apt dist-upgrade -y

View File

@ -1,26 +0,0 @@
#pragma once
#include "base/models/QvRuntimeConfig.hpp"
#include "base/models/QvStartupConfig.hpp"
#include "base/models/QvConfigModel.hpp"
#include <QTranslator>
// Instantiation for Qv2ray global objects.
#ifdef QT_DEBUG
const bool isDebugBuild = true;
#else
const bool isDebugBuild = false;
#endif
namespace Qv2ray
{
// Qv2ray runtime config
inline bool isExiting = false;
inline QString Qv2rayConfigPath = "/";
inline base::Qv2rayRuntimeConfig RuntimeConfig = base::Qv2rayRuntimeConfig();
inline base::config::Qv2rayConfig GlobalConfig = base::config::Qv2rayConfig();
inline base::QvStartupOptions StartupOption = base::QvStartupOptions();
//
inline std::unique_ptr<QTranslator> Qv2rayTranslator;
}

View File

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

View File

@ -1,28 +1,25 @@
#pragma once #pragma once
// //
#ifndef XTOSTRUCT_QT
# define XTOSTRUCT_QT
#endif
//
#include <QtCore>
#include <QtGui>
#include <QApplication> #include <QApplication>
#include <QMap> #include <QMap>
#include <vector> #include <QtCore>
#include <QtGui>
#include <algorithm> #include <algorithm>
#include <ctime> #include <ctime>
#include <iostream>
#include <optional>
#include <vector>
// Base support. // Base support.
#include "base/Qv2rayLog.hpp"
#include "base/Qv2rayFeatures.hpp"
#include "base/JsonHelpers.hpp" #include "base/JsonHelpers.hpp"
#include "base/GlobalInstances.hpp" #include "base/Qv2rayFeatures.hpp"
#include "base/Qv2rayLog.hpp"
// Code Models // Code Models
#include "base/models/QvSafeType.hpp"
#include "base/models/CoreObjectModels.hpp" #include "base/models/CoreObjectModels.hpp"
#include "base/models/QvConfigModel.hpp"
#include "base/models/QvConfigIdentifier.hpp" #include "base/models/QvConfigIdentifier.hpp"
#include "base/models/QvStartupConfig.hpp"
#include "base/models/QvRuntimeConfig.hpp" #include "base/models/QvRuntimeConfig.hpp"
#include "base/models/QvSafeType.hpp"
#include "base/models/QvSettingsObject.hpp"
#include "base/models/QvStartupConfig.hpp"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -34,27 +31,20 @@ 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;
// Linux users and DEs should handle the darkMode UI themselves.
#ifndef QV2RAY_USE_BUILTIN_DARKTHEME
# ifndef Q_OS_LINUX
# define QV2RAY_USE_BUILTIN_DARKTHEME
# endif
#endif
#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_)
extern const bool isDebugBuild;
// Base folder suffix. // Base folder suffix.
#ifdef QT_DEBUG #ifdef QT_DEBUG
# define QV2RAY_CONFIG_DIR_SUFFIX "_debug/" #define QV2RAY_CONFIG_DIR_SUFFIX "_debug/"
#else #else
# define QV2RAY_CONFIG_DIR_SUFFIX "/" #define QV2RAY_CONFIG_DIR_SUFFIX "/"
#endif #endif
// Get Configured Config Dir Path // Get Configured Config Dir Path
#define QV2RAY_CONFIG_DIR (Qv2ray::Qv2rayConfigPath) #define QV2RAY_CONFIG_DIR (Qv2ray::Qv2rayConfigPath)
#define QV2RAY_CONFIG_FILE (QV2RAY_CONFIG_DIR + "Qv2ray.conf") #define QV2RAY_CONFIG_FILE (QV2RAY_CONFIG_DIR + "Qv2ray.conf")
#define QV2RAY_CONNECTIONS_DIR (QV2RAY_CONFIG_DIR + "connections/")
#define QV2RAY_SUBSCRIPTION_DIR (QV2RAY_CONFIG_DIR + "subscriptions/") #define QV2RAY_SUBSCRIPTION_DIR (QV2RAY_CONFIG_DIR + "subscriptions/")
// Get GFWList and PAC file path. // Get GFWList and PAC file path.
@ -66,17 +56,17 @@ extern const bool isDebugBuild;
#define QV2RAY_GENERATED_DIR (QV2RAY_CONFIG_DIR + "generated/") #define QV2RAY_GENERATED_DIR (QV2RAY_CONFIG_DIR + "generated/")
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json") #define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json")
#if ! defined (QV2RAY_DEFAULT_VCORE_PATH) && ! defined (QV2RAY_DEFAULT_VASSETS_PATH) #if !defined(QV2RAY_DEFAULT_VCORE_PATH) && !defined(QV2RAY_DEFAULT_VASSETS_PATH)
# define QV2RAY_DEFAULT_VASSETS_PATH (QV2RAY_CONFIG_DIR + "vcore/") #define QV2RAY_DEFAULT_VASSETS_PATH (QV2RAY_CONFIG_DIR + "vcore/")
# ifdef Q_OS_WIN #ifdef Q_OS_WIN
# define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe") #define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
# else #else
# define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray") #define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
# endif #endif
#elif defined (QV2RAY_DEFAULT_VCORE_PATH) && defined (QV2RAY_DEFAULT_VASSETS_PATH) #elif defined(QV2RAY_DEFAULT_VCORE_PATH) && defined(QV2RAY_DEFAULT_VASSETS_PATH)
// ---- Using user-specified VCore and VAssets path // ---- Using user-specified VCore and VAssets path
#else #else
# error Both QV2RAY_DEFAULT_VCORE_PATH and QV2RAY_DEFAULT_VASSETS_PATH need to present when specifying the paths. #error Both QV2RAY_DEFAULT_VCORE_PATH and QV2RAY_DEFAULT_VASSETS_PATH need to be presented when using manually specify the paths.
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@ -84,8 +74,8 @@ extern const bool isDebugBuild;
//# define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe") //# define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray.exe")
//# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl.exe") //# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl.exe")
#else #else
# define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray") #define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray")
# define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl") #define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl")
#endif #endif
#define QV2RAY_VCORE_LOG_DIRNAME "logs/" #define QV2RAY_VCORE_LOG_DIRNAME "logs/"
@ -93,20 +83,19 @@ extern const bool isDebugBuild;
#define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log" #define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log"
// GUI TOOLS // GUI TOOLS
#define RED(obj) \ #define RED(obj) \
auto _temp = obj->palette(); \ auto _temp = obj->palette(); \
_temp.setColor(QPalette::Text, Qt::red); \ _temp.setColor(QPalette::Text, Qt::red); \
obj->setPalette(_temp); obj->setPalette(_temp);
#define BLACK(obj) \ #define BLACK(obj) obj->setPalette(QWidget::palette());
obj->setPalette(this->palette());
#define QV2RAY_UI_RESOURCES_ROOT ((GlobalConfig.uiConfig.useDarkTheme) ? QStringLiteral(":/assets/icons/ui_dark/") : QStringLiteral(":/assets/icons/ui_light/")) #define QV2RAY_UI_COLORSCHEME_ROOT \
#define QICON_R(file) QIcon(QV2RAY_UI_RESOURCES_ROOT + file) ((GlobalConfig.uiConfig.useDarkTheme) ? QStringLiteral(":/assets/icons/ui_dark/") : QStringLiteral(":/assets/icons/ui_light/"))
#define QICON_R(file) QIcon(QV2RAY_UI_COLORSCHEME_ROOT + file)
#define QSTRN(num) QString::number(num) #define QSTRN(num) QString::number(num)
#define OUTBOUND_TAG_DIRECT "outBound_DIRECT" #define OUTBOUND_TAG_DIRECT "outBound_DIRECT"
#define OUTBOUND_TAG_PROXY "outBound_PROXY" #define OUTBOUND_TAG_PROXY "outBound_PROXY"
#define OUTBOUND_TAG_FORWARD_PROXY "_QV2RAY_FORWARD_PROXY_" #define OUTBOUND_TAG_FORWARD_PROXY "_QV2RAY_FORWARD_PROXY_"
@ -116,16 +105,25 @@ extern const bool isDebugBuild;
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_" #define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
#define JSON_ROOT_TRY_REMOVE(obj) if (root.contains(obj)) { root.remove(obj); } #define JSON_ROOT_TRY_REMOVE(obj) \
if (root.contains(obj)) \
{ \
root.remove(obj); \
}
namespace Qv2ray namespace Qv2ray
{ {
// Extra header for QvConfigUpgrade.cpp // Extra header for QvConfigUpgrade.cpp
QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root); 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() inline void ExitQv2ray()
{ {
isExiting = true; isExiting = true;
QApplication::quit(); QApplication::quit();
} }
} } // namespace Qv2ray

View File

@ -2,8 +2,8 @@
// Qv2ray build features. // Qv2ray build features.
// //
// Always use libgRPC++ on windows platform. // Always use libgRPC++ on windows platform.
#ifndef WITH_LIB_GRPCPP #ifdef BACKEND_LIBQVB
# ifdef _WIN32 #ifdef _WIN32
# define WITH_LIB_GRPCPP #error "libQvb is not supported on Windows Platform"
# endif #endif
#endif #endif

View File

@ -1,5 +1,8 @@
#include "Qv2rayLog.hpp" #include "Qv2rayLog.hpp"
#include "GlobalInstances.hpp"
#include "Qv2rayBase.hpp"
#include <iostream>
namespace Qv2ray::base namespace Qv2ray::base
{ {
@ -11,42 +14,48 @@ 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 = "[" + module + "]: " + log; auto logString = QString("[" % module % "]: " % log);
auto funcPrepend = QString::fromStdString(func + ":" + to_string(line) + " "); auto funcPrepend = QString::fromStdString(func + ":" + to_string(line) + " ");
if (isDebugBuild) { #ifdef QT_DEBUG
// Debug build version, we only print info for DEBUG logs and print ALL info when debugLog presents, // Debug build version, we only print info for DEBUG logs and print
if (type == QV2RAY_LOG_DEBUG || StartupOption.debugLog) { // ALL info when debugLog presents,
logString = logString.prepend(funcPrepend); if (type == QV2RAY_LOG_DEBUG || StartupOption.debugLog)
{
logString.prepend(funcPrepend);
}
#else
// We only process DEBUG log in Release mode
if (type == QV2RAY_LOG_DEBUG)
{
if (StartupOption.debugLog)
{
logString.prepend(funcPrepend);
} }
} else { else
// We only process DEBUG log in Release mode {
if (type == QV2RAY_LOG_DEBUG) { // Discard debug log in non-debug Qv2ray version with
if (StartupOption.debugLog) { // no-debugLog mode.
logString = logString.prepend(funcPrepend); return;
} else {
// Discard debug log in non-debug Qv2ray version with no-debugLog mode.
return;
}
} }
} }
#endif
cout << logString.toStdString() << endl; cout << logString.toStdString() << endl;
{ {
QMutexLocker _(&__loggerMutex); QMutexLocker _(&__loggerMutex);
__loggerBuffer->append(logString + NEWLINE); __loggerBuffer->append(logString + NEWLINE);
} }
} } // namespace Qv2ray::base
const QString readLastLog() QString readLastLog()
{ {
QMutexLocker _(&__purgerMutex); QMutexLocker _(&__purgerMutex);
{ {
QMutexLocker _(&__loggerMutex); QMutexLocker locker(&__loggerMutex);
__loggerBuffer.swap(__purgerBuffer); __loggerBuffer.swap(__purgerBuffer);
} }
auto result = __purgerBuffer->join(""); auto result = __purgerBuffer->join("");
__purgerBuffer->clear(); __purgerBuffer->clear();
return result; return result;
} }
} } // namespace Qv2ray::base

View File

@ -1,28 +1,27 @@
#pragma once #pragma once
#include <iostream> #include <QString>
#include <QtDebug>
#include <QBuffer>
using namespace std; using namespace std;
/* /*
* Tiny log module. * Tiny log module.
*/ */
namespace Qv2ray::base namespace Qv2ray::base
{ {
void __QV2RAY_LOG_FUNC__(int type, const std::string &func, int line, const QString &module, const QString &log); void __QV2RAY_LOG_FUNC__(int type, const std::string &func, int line, const QString &module, const QString &log);
const QString readLastLog(); QString readLastLog();
} } // namespace Qv2ray::base
#define NEWLINE "\r\n" #define NEWLINE "\r\n"
#define QV2RAY_LOG_NORMAL 0 #define QV2RAY_LOG_NORMAL 0
#define QV2RAY_LOG_DEBUG 1 #define QV2RAY_LOG_DEBUG 1
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
#define Qv2ray_PRETTY_FUNCTION __PRETTY_FUNCTION__ #define Qv2ray_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else #else
#define Qv2ray_PRETTY_FUNCTION __FUNCSIG__ #define Qv2ray_PRETTY_FUNCTION __FUNCSIG__
#endif #endif
#define __LOG_IMPL(LEVEL, MODULE, MSG) __QV2RAY_LOG_FUNC__(LEVEL, Qv2ray_PRETTY_FUNCTION, __LINE__, MODULE, MSG); #define __LOG_IMPL(LEVEL, MODULE, MSG) __QV2RAY_LOG_FUNC__(LEVEL, Qv2ray_PRETTY_FUNCTION, __LINE__, MODULE, MSG);
@ -31,21 +30,23 @@ namespace Qv2ray::base
#define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG)); #define DEBUG(MODULE, MSG) __LOG_IMPL(QV2RAY_LOG_DEBUG, (MODULE), (MSG));
// Log modules used by Qv2ray // Log modules used by Qv2ray
const inline QString INIT = "INIT" ; const inline QString MODULE_INIT = "INIT";
const inline QString MESSAGING = "BASE-MESSAGING" ; const inline QString MODULE_MESSAGING = "BASE-MESSAGING";
const inline QString UI = "CORE-UI" ; const inline QString MODULE_UI = "CORE-UI";
const inline QString GRAPH = "CORE-UI-GRAPH" ; const inline QString MODULE_GRAPH = "CORE-UI-GRAPH";
const inline QString SETTINGS = "CORE-SETTINGS" ; const inline QString MODULE_SETTINGS = "CORE-SETTINGS";
const inline QString VCORE = "CORE-VCORE" ; const inline QString MODULE_VCORE = "CORE-VCORE";
// //
const inline QString CONNECTION = "CORE-CONNECTION" ; const inline QString MODULE_CONNECTION = "CORE-CONNECTION";
const inline QString SUBSCRIPTION = "CORE-SUBSCRIPTION" ; const inline QString MODULE_SUBSCRIPTION = "CORE-SUBSCRIPTION";
const inline QString IMPORT = "CORE-IMPORT" ; const inline QString MODULE_IMPORT = "CORE-IMPORT";
const inline QString EXPORT = "CORE-EXPORT" ; const inline QString MODULE_EXPORT = "CORE-EXPORT";
// //
const inline QString NETWORK = "COMMON-NETWORK" ; const inline QString MODULE_NETWORK = "COMMON-NETWORK";
const inline QString FILEIO = "COMMON-FILEIO" ; const inline QString MODULE_FILEIO = "COMMON-FILEIO";
// //
const inline QString PROXY = "COMPONENT-PROXY" ; const inline QString MODULE_PROXY = "COMPONENT-PROXY";
const inline QString UPDATE = "COMPONENT-UPDATE" ; const inline QString MODULE_UPDATE = "COMPONENT-UPDATE";
const inline QString PLUGIN = "COMPONENT-PLUGIN" ; const inline QString MODULE_PLUGIN = "COMPONENT-PLUGIN";
// ================================================================
const inline QString MODULE_CORE_HANDLER = "QV2RAY-CORE";

View File

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

View File

@ -1,56 +1,50 @@
#pragma once #pragma once
#include "3rdparty/x2struct/x2struct.hpp"
#include <QString> #include <QString>
#include <QtCore> #include <QtCore>
#include "3rdparty/x2struct/x2struct.hpp"
namespace Qv2ray::base namespace Qv2ray::base
{ {
struct ConnectionIdentifier { using namespace std::chrono;
QString subscriptionName; // Common struct for Groups and Subscriptions
QString connectionName; struct GroupObject_Config
ConnectionIdentifier() { }; {
bool isEmpty() QString displayName;
QList<QString> connections;
int64_t importDate;
GroupObject_Config() : displayName(), connections(), importDate()
{ {
return connectionName.isEmpty();
} }
ConnectionIdentifier(QString connectionName) XTOSTRUCT(O(displayName, connections, importDate))
{
this->connectionName = connectionName;
}
ConnectionIdentifier(QString connectionName, QString subscriptionName)
{
this->connectionName = connectionName;
this->subscriptionName = subscriptionName;
}
const QString IdentifierString() const
{
return connectionName + (subscriptionName.isEmpty() ? "" : " (" + subscriptionName + ")");
}
friend bool operator==(ConnectionIdentifier &left, ConnectionIdentifier &right)
{
return left.subscriptionName == right.subscriptionName && left.connectionName == right.connectionName;
}
friend bool operator!=(ConnectionIdentifier &left, ConnectionIdentifier &right)
{
return !(left == right);
}
friend bool operator==(ConnectionIdentifier &left, QString &right)
{
return left.IdentifierString() == right;
}
friend bool operator!=(ConnectionIdentifier &left, QString &right)
{
return !(left.IdentifierString() == right);
}
// To make QMap happy
friend bool operator<(const ConnectionIdentifier left, const ConnectionIdentifier right)
{
return left.IdentifierString() < right.IdentifierString();
}
friend bool operator>(const ConnectionIdentifier left, const ConnectionIdentifier right)
{
return left.IdentifierString() > right.IdentifierString();
}
XTOSTRUCT(O(subscriptionName, connectionName))
}; };
}
Q_DECLARE_METATYPE(Qv2ray::base::ConnectionIdentifier); struct SubscriptionObject_Config : GroupObject_Config
{
//
QString address;
int64_t lastUpdated;
float updateInterval;
SubscriptionObject_Config() : address(""), lastUpdated(system_clock::to_time_t(system_clock::now())), updateInterval(10)
{
}
XTOSTRUCT(O(lastUpdated, updateInterval, address, connections, displayName, importDate))
};
struct ConnectionObject_Config
{
QString displayName;
int64_t importDate;
int64_t lastConnected;
int64_t latency;
int64_t upLinkData;
int64_t downLinkData;
ConnectionObject_Config()
: displayName(), importDate(system_clock::to_time_t(system_clock::now())), lastConnected(), latency(0), upLinkData(0),
downLinkData(0)
{
}
XTOSTRUCT(O(displayName, importDate, lastConnected, latency, upLinkData, downLinkData))
};
} // namespace Qv2ray::base
using namespace Qv2ray::base;

View File

@ -1,184 +0,0 @@
#pragma once
#include "3rdparty/x2struct/x2struct.hpp"
#include "base/models/CoreObjectModels.hpp"
#include "base/models/QvConfigIdentifier.hpp"
#include <chrono>
const int QV2RAY_CONFIG_VERSION = 8;
namespace Qv2ray::base
{
namespace config
{
struct QvBarLine {
QString Family;
bool Bold;
bool Italic;
int ColorA;
int ColorR;
int ColorG;
int 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 Qv2raySubscriptionConfig {
time_t lastUpdated;
float updateInterval;
QString address;
Qv2raySubscriptionConfig() : lastUpdated(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())), updateInterval(5), address("") { }
XTOSTRUCT(O(lastUpdated, updateInterval, address))
};
struct Qv2rayPACConfig {
bool enablePAC;
int port;
QString localIP;
bool useSocksProxy;
Qv2rayPACConfig() : enablePAC(false), port(8989), useSocksProxy(false) { }
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
};
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("username"), password("password")
{ }
XTOSTRUCT(O(enableForwardProxy, type, serverAddress, port, useAuth, username, password))
};
struct Qv2rayInboundsConfig {
QString listenip;
bool setSystemProxy;
Qv2rayPACConfig pacConfig;
// 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;
Qv2rayInboundsConfig():
listenip("127.0.0.1"), setSystemProxy(false), pacConfig(),
useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true), socksLocalIP("127.0.0.1"), socksAccount(),
useHTTP(true), http_port(8888), http_useAuth(false), httpAccount() {}
XTOSTRUCT(O(setSystemProxy, pacConfig, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP, http_port, http_useAuth, httpAccount))
};
struct Qv2rayUIConfig {
QString theme;
QString language;
bool useDarkTheme;
bool useDarkTrayIcon;
int maximumLogLines;
Qv2rayUIConfig() : theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500) { }
XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon, maximumLogLines))
};
struct Qv2rayConnectionConfig {
bool bypassCN;
bool enableProxy;
bool withLocalDNS;
QList<QString> dnsList;
Qv2rayForwardProxyConfig forwardProxyConfig;
Qv2rayConnectionConfig() : bypassCN(true), enableProxy(true), withLocalDNS(false), dnsList(QStringList() << "8.8.4.4" << "1.1.1.1") { }
XTOSTRUCT(O(bypassCN, enableProxy, withLocalDNS, dnsList, forwardProxyConfig))
};
struct Qv2rayAPIConfig {
bool enableAPI;
int statsPort;
Qv2rayAPIConfig(): enableAPI(true), statsPort(15490) { }
XTOSTRUCT(O(enableAPI, statsPort))
};
struct Qv2rayConfig {
int config_version;
bool tProxySupport;
int logLevel;
//
QString v2CorePath;
QString v2AssetsPath;
ConnectionIdentifier autoStartConfig;
QString ignoredVersion;
//
QList<QString> configs;
QMap<QString, Qv2raySubscriptionConfig> subscriptions;
//
Qv2rayUIConfig uiConfig;
Qv2rayAPIConfig apiConfig;
Qv2rayInboundsConfig inboundConfig;
Qv2rayConnectionConfig connectionConfig;
Qv2rayToolBarConfig toolBarConfig;
Qv2rayConfig():
config_version(QV2RAY_CONFIG_VERSION),
tProxySupport(false),
logLevel(),
v2CorePath(),
v2AssetsPath(),
autoStartConfig(),
ignoredVersion(),
configs(),
subscriptions(),
uiConfig(),
apiConfig(),
inboundConfig(),
connectionConfig(),
toolBarConfig() { }
XTOSTRUCT(O(config_version,
ignoredVersion,
tProxySupport,
logLevel,
autoStartConfig,
v2CorePath, v2AssetsPath,
configs,
uiConfig,
subscriptions, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
};
}
}

View File

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

View File

@ -1,17 +1,27 @@
#pragma once #pragma once
#include <QJsonObject>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject>
#define SAFE_TYPEDEF(Base, name) \ #define SAFE_TYPEDEF_EXTRA(Base, name, extra) \
class name : public Base { \ class name : public Base \
public: \ { \
template <class... Args> \ public: \
explicit name (Args... args) : Base(args...) {} \ template<class... Args> \
const Base& raw() const { return *this; } \ explicit name(Args... args) : Base(args...) \
{ \
} \
const Base &raw() const \
{ \
return *this; \
} \
extra \
}; };
#define 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
@ -22,10 +32,10 @@ namespace Qv2ray::base::safetype
SAFE_TYPEDEF(QJsonObject, CONFIGROOT) SAFE_TYPEDEF(QJsonObject, CONFIGROOT)
SAFE_TYPEDEF(QJsonObject, PROXYSETTING) SAFE_TYPEDEF(QJsonObject, PROXYSETTING)
// //
SAFE_TYPEDEF(QJsonArray, ROUTERULELIST)
SAFE_TYPEDEF(QJsonArray, INOUTLIST) SAFE_TYPEDEF(QJsonArray, INOUTLIST)
SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
SAFE_TYPEDEF(QJsonObject, ROUTING) SAFE_TYPEDEF(QJsonObject, ROUTING)
SAFE_TYPEDEF(QJsonObject, ROUTERULE) SAFE_TYPEDEF(QJsonObject, ROUTERULE)
SAFE_TYPEDEF(QJsonArray, ROUTERULELIST) SAFE_TYPEDEF(INOUTLIST, OUTBOUNDS)
} SAFE_TYPEDEF(INOUTLIST, INBOUNDS)
} // namespace Qv2ray::base::safetype

View File

@ -0,0 +1,209 @@
#pragma once
#include "3rdparty/x2struct/x2struct.hpp"
#include "base/models/CoreObjectModels.hpp"
#include "base/models/QvConfigIdentifier.hpp"
#include <chrono>
const int QV2RAY_CONFIG_VERSION = 10;
namespace Qv2ray::base::config
{
struct QvBarLine
{
QString Family;
bool Bold, Italic;
int ColorA, ColorR, ColorG, ColorB;
int ContentType;
double Size;
QString Message;
QvBarLine()
: Family("Consolas"), Bold(true), Italic(false), ColorA(255), ColorR(255), ColorG(255), ColorB(255), ContentType(0), Size(9),
Message("")
{
}
XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
};
struct QvBarPage
{
int OffsetYpx;
QList<QvBarLine> Lines;
QvBarPage() : OffsetYpx(5)
{
}
XTOSTRUCT(O(OffsetYpx, Lines))
};
struct Qv2rayToolBarConfig
{
QList<QvBarPage> Pages;
XTOSTRUCT(O(Pages))
};
struct Qv2rayPACConfig
{
bool enablePAC;
int port;
QString localIP;
bool useSocksProxy;
Qv2rayPACConfig() : enablePAC(false), port(8989), useSocksProxy(false)
{
}
XTOSTRUCT(O(enablePAC, port, localIP, useSocksProxy))
};
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;
Qv2rayPACConfig pacConfig;
// 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;
Qv2rayInboundsConfig()
: listenip("127.0.0.1"), setSystemProxy(true), pacConfig(), useSocks(true), socks_port(1088), socks_useAuth(false), socksUDP(true),
socksLocalIP("127.0.0.1"), socksAccount(), useHTTP(true), http_port(8888), http_useAuth(false), httpAccount()
{
}
XTOSTRUCT(O(setSystemProxy, pacConfig, listenip, useSocks, useHTTP, socks_port, socks_useAuth, socksAccount, socksUDP, socksLocalIP,
http_port, http_useAuth, httpAccount))
};
struct Qv2rayUIConfig
{
QString theme;
QString language;
bool useDarkTheme;
bool useDarkTrayIcon;
int maximumLogLines;
Qv2rayUIConfig() : theme("Fusion"), language("en_US"), useDarkTheme(false), useDarkTrayIcon(true), maximumLogLines(500)
{
}
XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon, maximumLogLines))
};
struct Qv2rayConnectionConfig
{
bool bypassCN;
bool enableProxy;
bool withLocalDNS;
QList<QString> dnsList;
Qv2rayForwardProxyConfig forwardProxyConfig;
Qv2rayConnectionConfig() : bypassCN(true), enableProxy(true), withLocalDNS(false), dnsList(QStringList{ "8.8.4.4", "1.1.1.1" })
{
}
XTOSTRUCT(O(bypassCN, enableProxy, withLocalDNS, dnsList, forwardProxyConfig))
};
struct Qv2rayAPIConfig
{
bool enableAPI;
int statsPort;
Qv2rayAPIConfig() : enableAPI(true), statsPort(15490)
{
}
XTOSTRUCT(O(enableAPI, statsPort))
};
struct Qv2rayKernelConfig
{
QString v2CorePath_linux;
QString v2AssetsPath_linux;
QString v2CorePath_macx;
QString v2AssetsPath_macx;
QString v2CorePath_win;
QString v2AssetsPath_win; //
Qv2rayKernelConfig()
: v2CorePath_linux(), v2AssetsPath_linux(), //
v2CorePath_macx(), v2AssetsPath_macx(), //
v2CorePath_win(), v2AssetsPath_win() //
{
}
//
#ifdef Q_OS_LINUX
#define _VARNAME_VCOREPATH_ v2CorePath_linux
#define _VARNAME_VASSETSPATH_ v2AssetsPath_linux
#elif defined(Q_OS_MACOS)
#define _VARNAME_VCOREPATH_ v2CorePath_macx
#define _VARNAME_VASSETSPATH_ v2AssetsPath_macx
#elif defined(Q_OS_WIN)
#define _VARNAME_VCOREPATH_ v2CorePath_win
#define _VARNAME_VASSETSPATH_ v2AssetsPath_win
#endif
inline const QString KernelPath(const QString &path = "")
{
return path.isEmpty() ? _VARNAME_VCOREPATH_ : _VARNAME_VCOREPATH_ = path;
}
inline const QString AssetsPath(const QString &path = "")
{
return path.isEmpty() ? _VARNAME_VASSETSPATH_ : _VARNAME_VASSETSPATH_ = path;
}
#undef _VARNAME_VCOREPATH_
#undef _VARNAME_VASSETSPATH_
XTOSTRUCT(O(v2CorePath_linux, v2AssetsPath_linux, v2CorePath_macx, v2AssetsPath_macx, v2CorePath_win, v2AssetsPath_win))
};
struct Qv2rayConfig
{
int config_version;
bool tProxySupport;
int logLevel;
//
QString ignoredVersion;
QString autoStartId;
//
// Key = groupId, connectionId
QMap<QString, GroupObject_Config> groups;
QMap<QString, SubscriptionObject_Config> subscriptions;
/// Connections are used privately.
QMap<QString, ConnectionObject_Config> connections;
//
Qv2rayUIConfig uiConfig;
Qv2rayAPIConfig apiConfig;
Qv2rayKernelConfig kernelConfig;
Qv2rayToolBarConfig toolBarConfig;
Qv2rayInboundsConfig inboundConfig;
Qv2rayConnectionConfig connectionConfig;
Qv2rayConfig()
: config_version(QV2RAY_CONFIG_VERSION), tProxySupport(false), logLevel(), ignoredVersion(), autoStartId("null"), groups(),
subscriptions(), connections(), uiConfig(), apiConfig(), kernelConfig(), toolBarConfig(), inboundConfig(), connectionConfig()
{
}
XTOSTRUCT(O(config_version, ignoredVersion, tProxySupport, logLevel, uiConfig, kernelConfig, groups, connections, subscriptions,
autoStartId, inboundConfig, connectionConfig, toolBarConfig, apiConfig))
};
} // namespace Qv2ray::base::config

View File

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

View File

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

View File

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

View File

@ -1,11 +1,13 @@
#include "HTTPRequestHelper.hpp" #include "HTTPRequestHelper.hpp"
#include "base/Qv2rayBase.hpp"
#include <QByteArray> #include <QByteArray>
#include <QNetworkProxy> #include <QNetworkProxy>
#include "base/Qv2rayBase.hpp"
namespace Qv2ray::common namespace Qv2ray::common
{ {
QvHttpRequestHelper::QvHttpRequestHelper() : reply() QvHttpRequestHelper::QvHttpRequestHelper(QObject *parent) : QObject(parent), reply()
{ {
} }
@ -18,8 +20,9 @@ namespace Qv2ray::common
{ {
QUrl qUrl = QUrl(url); QUrl qUrl = QUrl(url);
if (!qUrl.isValid()) { if (!qUrl.isValid())
LOG(NETWORK, "Provided URL is invalid: " + url) {
LOG(MODULE_NETWORK, "Provided URL is invalid: " + url)
return false; return false;
} }
@ -29,7 +32,7 @@ namespace Qv2ray::common
void QvHttpRequestHelper::setHeader(const QByteArray &key, const QByteArray &value) void QvHttpRequestHelper::setHeader(const QByteArray &key, const QByteArray &value)
{ {
DEBUG(NETWORK, "Adding HTTP request header: " + key + ":" + value) DEBUG(MODULE_NETWORK, "Adding HTTP request header: " + key + ":" + value)
request.setRawHeader(key, value); request.setRawHeader(key, value);
} }
@ -37,17 +40,22 @@ namespace Qv2ray::common
{ {
this->setUrl(url); this->setUrl(url);
if (useProxy) { if (useProxy)
{
auto proxy = QNetworkProxyFactory::systemProxyForQuery(); auto proxy = QNetworkProxyFactory::systemProxyForQuery();
accessManager.setProxy(proxy.first()); accessManager.setProxy(proxy.first());
} else { LOG(MODULE_NETWORK, "Sync get is using system proxy settings")
}
else
{
accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy)); accessManager.setProxy(QNetworkProxy(QNetworkProxy::ProxyType::NoProxy));
} }
LOG(NETWORK, "Sync get is using system proxy settings")
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Mozilla/5.0 (rv:71.0) Gecko/20100101 Firefox/71.0");
reply = accessManager.get(request); reply = accessManager.get(request);
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished); connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
// //
QEventLoop loop; QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
@ -60,28 +68,34 @@ namespace Qv2ray::common
void QvHttpRequestHelper::get(const QString &url) void QvHttpRequestHelper::get(const QString &url)
{ {
this->setUrl(url); this->setUrl(url);
// request.setRawHeader("Content-Type", "application/x-www-form-urlencoded"); // request.setRawHeader("Content-Type",
// "application/x-www-form-urlencoded");
reply = accessManager.get(request); reply = accessManager.get(request);
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished); connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead); connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
} }
//void QvHttpRequestHelper::post(const QString &url, const QByteArray &data) // void QvHttpRequestHelper::post(const QString &url, const QByteArray
// &data)
//{ //{
// this->setUrl(url); // this->setUrl(url);
// request.setRawHeader("Content-Type", "application/json"); // request.setRawHeader("Content-Type", "application/json");
// reply = accessManager.post(request, data); // reply = accessManager.post(request, data);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished); // connect(reply, &QNetworkReply::finished, this,
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead); // &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead);
//} //}
// void QvHttpRequestHelper::put(const QString &url, const QByteArray &data) // void QvHttpRequestHelper::put(const QString &url, const QByteArray
// &data)
// { // {
// this->setUrl(url); // this->setUrl(url);
// request.setRawHeader("Content-Type", "application/json"); // request.setRawHeader("Content-Type", "application/json");
// reply = accessManager.put(request, data); // reply = accessManager.put(request, data);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished); // connect(reply, &QNetworkReply::finished, this,
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead); // &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this,
// &QvHttpRequestHelper::onReadyRead);
// } // }
// void QvHttpRequestHelper::del(const QString &url) // void QvHttpRequestHelper::del(const QString &url)
@ -89,28 +103,46 @@ namespace Qv2ray::common
// this->setUrl(url); // this->setUrl(url);
// request.setRawHeader("Content-Type", "application/json"); // request.setRawHeader("Content-Type", "application/json");
// reply = accessManager.deleteResource(request); // reply = accessManager.deleteResource(request);
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished); // connect(reply, &QNetworkReply::finished, this,
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead); // &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this,
// &QvHttpRequestHelper::onReadyRead);
// } // }
// void QvHttpRequestHelper::login(const QString &url, const QByteArray &data) // void QvHttpRequestHelper::login(const QString &url, const QByteArray
// &data)
// { // {
// this->setUrl(url); // this->setUrl(url);
// request.setRawHeader("Content-Type", "application/x-www-form-urlencoded"); // request.setRawHeader("Content-Type",
// reply = accessManager.post(request, data); // "application/x-www-form-urlencoded"); reply =
// connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished); // accessManager.post(request, data); connect(reply,
// connect(reply, &QNetworkReply::readyRead, this, &QvHttpRequestHelper::onReadyRead); // &QNetworkReply::finished, this,
// &QvHttpRequestHelper::onRequestFinished); connect(reply,
// &QNetworkReply::readyRead, this,
// &QvHttpRequestHelper::onReadyRead);
// } // }
void QvHttpRequestHelper::onRequestFinished() void QvHttpRequestHelper::onRequestFinished_p()
{ {
LOG(NETWORK, "Network request errcode: " + QSTRN(reply->error())) if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool())
{
DEBUG(MODULE_NETWORK, "HTTP/2 was used.")
}
if (reply->error() != QNetworkReply::NoError)
{
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
LOG(MODULE_NETWORK, "Network request error string: " + error)
QByteArray empty;
emit httpRequestFinished(empty);
}
emit httpRequestFinished(this->data); emit httpRequestFinished(this->data);
} }
void QvHttpRequestHelper::onReadyRead() void QvHttpRequestHelper::onReadyRead()
{ {
DEBUG(NETWORK, "A request is now ready read") DEBUG(MODULE_NETWORK, "A request is now ready read")
this->data += reply->readAll(); this->data += reply->readAll();
} }
} } // namespace Qv2ray::common

View File

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

View File

@ -0,0 +1,111 @@
#include "JsonHighlighter.hpp"
#include "core/settings/SettingsBackend.hpp"
namespace Qv2ray::common
{
vCoreConfigJsonHighlighter::vCoreConfigJsonHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent)
{
QTextCharFormat keywordFormat;
keywordFormat.setForeground(GlobalConfig.uiConfig.useDarkTheme ? Qt::GlobalColor::magenta : Qt::darkMagenta);
keywordFormat.setFontWeight(QFont::Bold);
// It's holy a dirty hack here, we'll fully ultilize the vCoreConfig models.
auto keywordPatterns = { "inbounds",
"outbounds",
"routing",
"settings",
"transport",
"request",
"headers",
"ip",
"tag",
"protocol",
"listen",
"rules",
"port",
"reverse",
"dsSettings",
"httpSettings",
"kcpSettings",
"network",
"quicSettings",
"security",
"sockopt",
"tcpSettings",
"tlsSettings",
"wsSettings",
"streamSettings",
"mux",
"sendThrough",
"vnext",
"address",
"users",
"alterId",
"id",
"level",
"path",
"host",
"congestion",
"downlinkCapacity",
"header",
"type",
"mtu",
"readBufferSize",
"tti",
"uplinkCapacity",
"writeBufferSize",
"key",
"mark",
"tcpFastOpen",
"tproxy",
"allowInsecure",
"alpn",
"disableSystemRoot",
"certificates",
"serverName",
"QV2RAY_RULE_ENABLED",
"QV2RAY_RULE_TAG",
"QV2RAY_RULE_USE_BALANCER" };
int i = 0;
for (const QString &pattern : keywordPatterns)
{
SetRule(QString("00_KeyWord_%1").arg(i), "\"" + pattern + "\"", keywordFormat);
++i;
}
//
// Values
QTextCharFormat valueFormat, classFormat;
valueFormat.setForeground(Qt::blue);
SetRule("03_Values", "\\btrue\\b|\\bfalse\\b|\\b[0-9]+\\b", valueFormat);
//
// Single Line Comments
QTextCharFormat singleLineCommentFormat;
singleLineCommentFormat.setForeground(Qt::darkGreen);
SetRule("z2_SingleLineComments", "//[^\n]*", singleLineCommentFormat);
}
void vCoreConfigJsonHighlighter::SetRule(const QString &kind, const QString &pattern, QTextCharFormat format)
{
JsonHighlightingRule rule;
rule.name = kind;
rule.pattern = QRegularExpression(pattern);
rule.format = format;
highlightingRules.append(rule);
}
void vCoreConfigJsonHighlighter::highlightBlock(const QString &text)
{
for (const auto &rule : std::as_const(highlightingRules))
{
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext())
{
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
}
} // namespace Qv2ray::common

View File

@ -0,0 +1,29 @@
#pragma once
#include <QObject>
#include <QRegularExpression>
#include <QStringList>
#include <QSyntaxHighlighter>
#include <QVector>
namespace Qv2ray::common
{
struct JsonHighlightingRule
{
QString name;
QRegularExpression pattern;
QTextCharFormat format;
};
class vCoreConfigJsonHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
vCoreConfigJsonHighlighter(QTextDocument *parent = nullptr);
private:
QVector<JsonHighlightingRule> highlightingRules;
void SetRule(const QString &kind, const QString &pattern, QTextCharFormat format);
void highlightBlock(const QString &text) override;
};
} // namespace Qv2ray::common
using namespace Qv2ray::common;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,11 @@
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "libs/puresource/src/PureJson.hpp"
#include <QGraphicsEffect>
#include <QGraphicsProxyWidget>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QQueue> #include <QQueue>
namespace Qv2ray::common namespace Qv2ray::common
@ -8,7 +15,8 @@ namespace Qv2ray::common
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString randomString; QString randomString;
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i)
{
uint rand = QRandomGenerator::system()->generate(); uint rand = QRandomGenerator::system()->generate();
uint max = static_cast<uint>(possibleCharacters.length()); uint max = static_cast<uint>(possibleCharacters.length());
QChar nextChar = possibleCharacters[rand % max]; QChar nextChar = possibleCharacters[rand % max];
@ -26,21 +34,43 @@ namespace Qv2ray::common
QString StringFromFile(QFile *source) QString StringFromFile(QFile *source)
{ {
source->open(QFile::ReadOnly); bool wasOpened = source->isOpen();
QTextStream stream(source); if (!wasOpened)
QString str = stream.readAll(); source->open(QFile::ReadOnly);
source->close(); auto byteArray = source->readAll();
return str; if (!wasOpened)
source->close();
//
QTextCodec::ConverterState state;
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
const QString text = codec->toUnicode(byteArray.constData(), byteArray.size(), &state);
if (state.invalidChars > 0)
{
LOG(MODULE_FILEIO, "Not a valid UTF-8 sequence: " + source->fileName())
return source->readAll();
}
else
{
return text;
}
} }
bool StringToFile(const QString *text, QFile *targetFile) bool StringToFile(const QString &text, const QString &targetpath)
{ {
bool override = targetFile->exists(); auto file = QFile(targetpath);
targetFile->open(QFile::WriteOnly); return StringToFile(text, file);
QTextStream stream(targetFile); }
stream << *text << endl; bool StringToFile(const QString &text, QFile &targetFile)
stream.flush(); {
targetFile->close(); QFileInfo info(targetFile);
if (!info.dir().exists())
{
info.dir().mkpath(info.dir().path());
}
bool override = targetFile.exists();
targetFile.open(QFile::WriteOnly);
targetFile.write(text.toUtf8());
targetFile.close();
return override; return override;
} }
@ -50,14 +80,14 @@ namespace Qv2ray::common
return JsonFromString(json); return JsonFromString(json);
} }
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format) QString JsonToString(const QJsonObject &json, QJsonDocument::JsonFormat format)
{ {
QJsonDocument doc; QJsonDocument doc;
doc.setObject(json); doc.setObject(json);
return doc.toJson(format); return doc.toJson(format);
} }
QString JsonToString(QJsonArray array, QJsonDocument::JsonFormat format) QString JsonToString(const QJsonArray &array, QJsonDocument::JsonFormat format)
{ {
QJsonDocument doc; QJsonDocument doc;
doc.setArray(array); doc.setArray(array);
@ -70,27 +100,35 @@ namespace Qv2ray::common
QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error); QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error);
Q_UNUSED(doc) Q_UNUSED(doc)
if (error.error == QJsonParseError::NoError) { if (error.error == QJsonParseError::NoError)
{
return ""; return "";
} else { }
LOG(UI, "WARNING: Json parse returns: " + error.errorString()) else
{
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString())
return error.errorString(); return error.errorString();
} }
} }
QJsonObject JsonFromString(QString string) QJsonObject JsonFromString(const QString &string)
{ {
QJsonDocument doc = QJsonDocument::fromJson(string.toUtf8()); auto removeComment = RemoveComment(string.trimmed()).trimmed();
if (removeComment != string.trimmed())
{
LOG(MODULE_FILEIO, "Some comments have been removed from the json.")
}
QJsonDocument doc = QJsonDocument::fromJson(removeComment.toUtf8());
return doc.object(); return doc.object();
} }
QString Base64Encode(QString string) QString Base64Encode(const QString &string)
{ {
QByteArray ba = string.toUtf8(); QByteArray ba = string.toUtf8();
return ba.toBase64(); return ba.toBase64();
} }
QString Base64Decode(QString string) QString Base64Decode(const QString &string)
{ {
QByteArray ba = string.toUtf8(); QByteArray ba = string.toUtf8();
return QString(QByteArray::fromBase64(ba)); return QString(QByteArray::fromBase64(ba));
@ -105,50 +143,52 @@ namespace Qv2ray::common
{ {
list<string> list; list<string> list;
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) { for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts))
{
list.push_back(line.toStdString()); list.push_back(line.toStdString());
} }
return list; return list;
} }
QStringList GetFileList(QDir dir) QStringList GetFileList(const QDir &dir)
{ {
return dir.entryList(QStringList() << "*" << "*.*", QDir::Hidden | QDir::Files); return dir.entryList(QStringList{ "*", "*.*" }, QDir::Hidden | QDir::Files);
} }
bool FileExistsIn(QDir dir, QString fileName) bool FileExistsIn(const QDir &dir, const QString &fileName)
{ {
return GetFileList(dir).contains(fileName); return GetFileList(dir).contains(fileName);
} }
void QvMessageBoxWarn(QWidget *parent, QString title, QString text) void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text)
{ {
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0); QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
} }
void QvMessageBoxInfo(QWidget *parent, QString title, QString text) void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text)
{ {
QMessageBox::information(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0); QMessageBox::information(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
} }
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons) 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); return QMessageBox::question(parent, title, text, QMessageBox::Yes | QMessageBox::No | extraButtons);
} }
QString FormatBytes(long long bytes) QString FormatBytes(const int64_t b)
{ {
auto _bytes = b;
char str[64]; char str[64];
const char *sizes[5] = { "B", "KB", "MB", "GB", "TB" }; const char *sizes[5] = { "B", "KB", "MB", "GB", "TB" };
int i; int i;
double dblByte = bytes; double dblByte = _bytes;
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024) for (i = 0; i < 5 && _bytes >= 1024; i++, _bytes /= 1024) dblByte = _bytes / 1024.0;
dblByte = bytes / 1024.0;
sprintf(str, "%.2f", dblByte); sprintf(str, "%.2f", dblByte);
return strcat(strcat(str, " "), sizes[i]); return QString(str) + " " + QString(sizes[i]);
} }
bool IsValidFileName(const QString &fileName) bool IsValidFileName(const QString &fileName)
@ -160,9 +200,8 @@ namespace Qv2ray::common
QString RemoveInvalidFileName(const QString &fileName) QString RemoveInvalidFileName(const QString &fileName)
{ {
std::string _name = fileName.toStdString(); std::string _name = fileName.toStdString();
std::replace_if(_name.begin(), _name.end(), [](char c) { std::replace_if(
return std::string::npos != string(R"("/\?%&^*;:|><)").find(c); _name.begin(), _name.end(), [](char c) { return std::string::npos != string(R"("/\?%&^*;:|><)").find(c); }, '_');
}, '_');
return QString::fromStdString(_name); return QString::fromStdString(_name);
} }
@ -171,42 +210,54 @@ namespace Qv2ray::common
{ {
int i = 1; int i = 1;
if (!QDir(baseDir).exists()) { if (!QDir(baseDir).exists())
{
QDir(baseDir).mkpath(baseDir); QDir(baseDir).mkpath(baseDir);
LOG(FILEIO, "Making path: " + baseDir) LOG(MODULE_FILEIO, "Making path: " + baseDir)
} }
while (true) { while (true)
if (!QFile(baseDir + "/" + fileName + "_" + QSTRN(i) + extension).exists()) { {
if (!QFile(baseDir + "/" + fileName + "_" + QSTRN(i) + extension).exists())
{
*fileName = *fileName + "_" + QSTRN(i); *fileName = *fileName + "_" + QSTRN(i);
return; return;
} else { }
DEBUG(FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists") else
{
DEBUG(MODULE_FILEIO, "File with name: " + *fileName + "_" + QSTRN(i) + extension + " already exists")
} }
i++; i++;
} }
} }
QStringList ConvertQStringList(const QList<string> &stdListString) QPixmap BlurImage(const QPixmap &pixmap, const double rad)
{ {
QStringList listQt; QGraphicsView view;
listQt.reserve(stdListString.size()); QGraphicsScene scene;
QGraphicsBlurEffect pBlur;
for (const std::string &s : stdListString) { //
listQt.append(QString::fromStdString(s)); view.setScene(&scene);
} scene.setSceneRect(pixmap.rect());
pBlur.setBlurRadius(rad);
return listQt; QGraphicsPixmapItem *p = view.scene()->addPixmap(pixmap);
p->setGraphicsEffect(&pBlur);
return view.grab();
} }
std::list<string> ConvertStdStringList(const QStringList &qStringList)
QPixmap ColorizeImage(const QPixmap &pixmap, const QColor &color, const qreal factor)
{ {
std::list<string> stdList; QGraphicsView view;
QGraphicsScene scene;
for (auto &s : qStringList) { QGraphicsColorizeEffect pColor;
stdList.push_back(s.toStdString()); pColor.setColor(color);
} pColor.setStrength(factor);
//
return stdList; view.setScene(&scene);
scene.setSceneRect(pixmap.rect());
QGraphicsPixmapItem *p = view.scene()->addPixmap(pixmap);
p->setGraphicsEffect(&pColor);
return view.grab();
} }
} } // namespace Qv2ray::common

View File

@ -1,50 +1,61 @@
#pragma once #pragma once
#include "base/Qv2rayBase.hpp" #include "base/Qv2rayBase.hpp"
#include <QMessageBox> #include <QMessageBox>
#define REGEX_IPV6_ADDR R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])" #define REGEX_IPV6_ADDR \
#define REGEX_IPV4_ADDR R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))" R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])"
#define REGEX_IPV4_ADDR \
R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))"
#define REGEX_PORT_NUMBER R"(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])*)" #define REGEX_PORT_NUMBER R"(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])*)"
namespace Qv2ray::common namespace Qv2ray::common
{ {
QStringList GetFileList(QDir dir); QStringList GetFileList(const QDir &dir);
QString Base64Encode(QString string); QString Base64Encode(const QString &string);
QString Base64Decode(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(QDir dir, 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, QString title, QString text); void QvMessageBoxWarn(QWidget *parent, const QString &title, const QString &text);
void QvMessageBoxInfo(QWidget *parent, QString title, QString text); void QvMessageBoxInfo(QWidget *parent, const QString &title, const QString &text);
QMessageBox::StandardButton QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons = QMessageBox::NoButton); 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);
// //
QJsonObject JsonFromString(QString string); QJsonObject JsonFromString(const QString &string);
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented); QString JsonToString(const QJsonObject &json, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
QString JsonToString(QJsonArray array, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented); QString JsonToString(const QJsonArray &array, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
QString VerifyJsonString(const QString &source); QString VerifyJsonString(const QString &source);
// //
QString FormatBytes(long long 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);
QStringList ConvertQStringList(const QList<string> &stdListString); //
std::list<string> ConvertStdStringList(const QStringList &qStringList); 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);
inline QString GenerateUuid()
{
return GenerateRandomString().toLower();
// return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
// //
template <typename TYPE> template<typename TYPE>
QString StructToJsonString(const TYPE t) QString StructToJsonString(const TYPE t)
{ {
return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' ')); return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' '));
} }
// //
template <typename TYPE> template<typename TYPE>
TYPE StructFromJsonString(const QString &str) TYPE StructFromJsonString(const QString &str)
{ {
TYPE v; TYPE v;
@ -59,68 +70,43 @@ namespace Qv2ray::common
return JsonFromString(json); return JsonFromString(json);
} }
inline bool IsIPv4Address(const QString &addr) inline QString TruncateString(const QString &str, int limit = -1, const QString &suffix = "...")
{ {
return QRegularExpression(REGEX_IPV4_ADDR "$").match(addr).hasMatch(); QString t = str;
t.truncate(limit);
return (limit == -1 || str.length() < limit) ? str : (t + suffix);
} }
inline bool IsIPv6Address(const QString &addr) namespace validation
{ {
return QRegularExpression(REGEX_IPV6_ADDR "$").match(addr).hasMatch(); const inline QRegularExpression __regex_ipv4_full(REGEX_IPV4_ADDR "$");
} const inline QRegularExpression __regex_ipv6_full(REGEX_IPV6_ADDR "$");
inline bool IsValidIPAddress(const QString &addr) inline bool IsIPv4Address(const QString &addr)
{ {
return IsIPv4Address(addr) || IsIPv6Address(addr); return __regex_ipv4_full.match(addr).hasMatch();
} }
/* inline bool IsIPv6Address(const QString &addr)
* Generic function to find if an element of any type exists in list {
*/ return __regex_ipv6_full.match(addr).hasMatch();
template<typename T> }
bool contains(std::list<T> &listOfElements, const T &element)
{ inline bool IsValidIPAddress(const QString &addr)
// Find the iterator if element in list {
auto it = std::find(listOfElements.begin(), listOfElements.end(), element); return IsIPv4Address(addr) || IsIPv6Address(addr);
//return if iterator points to end or not. It points to end then it means element }
// does not exists in list } // namespace validation
return it != listOfElements.end();
}
inline QString timeToString(const time_t &t) inline QString timeToString(const time_t &t)
{ {
auto _tm = std::localtime(&t); auto _tm = std::localtime(&t);
char MY_TIME[128]; char MY_TIME[128];
setlocale(1, "3");
// using strftime to display time // using strftime to display time
strftime(MY_TIME, sizeof(MY_TIME), "%x - %I:%M%p", _tm); strftime(MY_TIME, sizeof(MY_TIME), "%x - %I:%M%p", _tm);
return QString(MY_TIME); return QString(MY_TIME);
} }
} // namespace Qv2ray::common
template<typename myMap>
std::vector<typename myMap::key_type> Keys(const myMap &m)
{
std::vector<typename myMap::key_type> r;
r.reserve(m.size());
for (const auto &kvp : m) {
r.push_back(kvp.first);
}
return r;
}
template<typename myMap>
std::vector<typename myMap::mapped_type> Values(const myMap &m)
{
std::vector<typename myMap::mapped_type> r;
r.reserve(m.size());
for (const auto &kvp : m) {
r.push_back(kvp.second);
}
return r;
}
}
using namespace Qv2ray::common; using namespace Qv2ray::common;

View File

@ -0,0 +1,93 @@
#include "QvTranslator.hpp"
#include "base/Qv2rayLog.hpp"
#include "common/QvHelpers.hpp"
#include <QApplication>
#include <QDir>
#include <QStandardPaths>
#include <QString>
#include <QStringBuilder>
#include <QTranslator>
#include <memory>
using namespace Qv2ray::base;
// path searching list.
QStringList getLanguageSearchPaths()
{
// Configuration Path
QStringList list;
list << QV2RAY_CONFIG_DIR + "lang";
//
#ifdef EMBED_TRANSLATIONS
// If the translations have been embedded.
list << QString(":/translations/");
#endif
//
//
#ifdef QV2RAY_TRANSLATION_PATH
// Platform-specific dir, if specified.
list << QString(QV2RAY_TRANSLATION_PATH);
#endif
//
//
#ifdef Q_OS_LINUX
// Linux platform directories.
list << QString("/usr/share/qv2ray/lang/");
list << QString("/usr/local/share/qv2ray/lang/");
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, "lang", QStandardPaths::LocateDirectory);
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, "lang", QStandardPaths::LocateDirectory);
#elif defined(Q_OS_MAC)
// macOS platform directories.
list << QDir(QApplication::applicationDirPath() + "/../Resources/lang").absolutePath();
#else
// This is the default behavior on Windows
list << QApplication::applicationDirPath() + "/lang";
#endif
return list;
};
namespace Qv2ray::common
{
QvTranslator::QvTranslator()
{
DEBUG(MODULE_UI, "QvTranslator constructor.")
GetAvailableLanguages();
}
QStringList QvTranslator::GetAvailableLanguages()
{
languages.clear();
for (auto path : getLanguageSearchPaths())
{
languages << QDir(path).entryList(QStringList{ "*.qm" }, QDir::Hidden | QDir::Files);
}
std::transform(languages.begin(), languages.end(), languages.begin(), [](QString &fileName) { return fileName.replace(".qm", ""); });
languages.removeDuplicates();
DEBUG(MODULE_UI, "Found translations: " + languages.join(" "))
return languages;
}
bool QvTranslator::InstallTranslation(const QString &code)
{
for (auto path : getLanguageSearchPaths())
{
if (FileExistsIn(QDir(path), code + ".qm"))
{
LOG(MODULE_UI, "Found " + code + " in folder: " + path)
QTranslator *translatorNew = new QTranslator();
translatorNew->load(code + ".qm", path);
if (pTranslator)
{
LOG(MODULE_INIT, "Removed translations")
qApp->removeTranslator(pTranslator.get());
}
this->pTranslator.reset(translatorNew);
qApp->installTranslator(pTranslator.get());
return true;
}
}
return false;
}
} // namespace Qv2ray::common

View File

@ -2,20 +2,30 @@
#include <QString> #include <QString>
#include <QTranslator> #include <QTranslator>
#include <memory> #include <memory>
#include <optional>
namespace Qv2ray::common namespace Qv2ray::common
{ {
class QvTranslator class QvTranslator
{ {
public: public:
QvTranslator(const QString &lang) explicit QvTranslator();
{
QTranslator *translator = new QTranslator();
translator->load(lang + ".qm", ":/translations/");
this->pTranslator.reset(translator);
}
public: public:
std::unique_ptr<QTranslator> pTranslator; /**
* @brief get the available languages.
* @return (if available) languages (zh_CN, en_US, ...)
*/
QStringList GetAvailableLanguages();
/**
* @brief reload the translation from file
* @param code eg: en_US, zh_CN, ...
*/
bool InstallTranslation(const QString &);
private:
QStringList languages;
std::unique_ptr<QTranslator> pTranslator;
}; };
inline std::unique_ptr<common::QvTranslator> Qv2rayTranslator;
} // namespace Qv2ray::common } // namespace Qv2ray::common

View File

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

View File

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

View File

@ -0,0 +1,34 @@
#include "DarkmodeDetector.hpp"
#include <QtGlobal>
#ifdef Q_OS_LINUX
#include <QApplication>
#include <QStyle>
#elif defined(Q_OS_WIN32)
#include <QSettings>
#else
// TODO: macOS headers.
#endif
namespace Qv2ray::components::darkmode
{
// Referenced from github.com/keepassxreboot/keepassxc. Licensed under GPL2/3.
// Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
bool isDarkMode()
{
#if defined(Q_OS_LINUX)
if (!qApp || !qApp->style())
{
return false;
}
return qApp->style()->standardPalette().color(QPalette::Window).toHsl().lightness() < 110;
#elif defined(Q_OS_WIN32)
QSettings settings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", QSettings::NativeFormat);
return settings.value("AppsUseLightTheme", 1).toInt() == 0;
#elif defined(Q_OS_DARWIN)
// TODO: expand this stub
return false;
#endif
}
} // namespace Qv2ray::components::darkmode

View File

@ -0,0 +1,6 @@
#pragma once
namespace Qv2ray::components::darkmode
{
bool isDarkMode();
}

View File

@ -1,20 +1,22 @@
#include "QvGeositeReader.hpp" #include "QvGeositeReader.hpp"
#include "libs/gen/v2ray_geosite.pb.h"
#include "v2ray_geosite.pb.h"
namespace Qv2ray::components::geosite namespace Qv2ray::components::geosite
{ {
QStringList ReadGeoSiteFromFile(QString filepath) QStringList ReadGeoSiteFromFile(QString filepath)
{ {
QStringList list; QStringList list;
LOG(FILEIO, "Reading geosites from: " + filepath) LOG(MODULE_FILEIO, "Reading geosites from: " + filepath)
// //
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
// //
QFile f(filepath); QFile f(filepath);
bool opened = f.open(QFile::OpenModeFlag::ReadOnly); bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
if (!opened) { if (!opened)
LOG(FILEIO, "File cannot be opened: " + filepath) {
LOG(MODULE_FILEIO, "File cannot be opened: " + filepath)
return list; return list;
} }
@ -24,14 +26,15 @@ namespace Qv2ray::components::geosite
GeoSiteList sites; GeoSiteList sites;
sites.ParseFromArray(content.data(), content.size()); sites.ParseFromArray(content.data(), content.size());
for (auto e : sites.entry()) { for (auto e : sites.entry())
{
// We want to use lower string. // We want to use lower string.
list << QString::fromStdString(e.country_code()).toLower(); list << QString::fromStdString(e.country_code()).toLower();
} }
LOG(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();
return list; return list;
} }
} } // namespace Qv2ray::components::geosite

View File

@ -0,0 +1,52 @@
#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

View File

@ -0,0 +1,34 @@
#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

View File

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

View File

@ -1,79 +1,82 @@
#include "QvPACHandler.hpp" #include "QvPACHandler.hpp"
#include "qhttprequest.h"
#include "qhttpresponse.h" #include "3rdparty/cpp-httplib/httplib.h"
#include "core/CoreUtils.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "core/CoreUtils.hpp"
namespace Qv2ray::components::pac namespace Qv2ray::components::pac
{ {
PACServer::PACServer() : QObject(), pacServer(this) PACServer::PACServer() : QThread()
{ {
connect(&pacServer, &QHttpServer::newRequest, this, &PACServer::onNewRequest); pacServer = new httplib::Server();
} }
PACServer::~PACServer() PACServer::~PACServer()
{ {
if (isStarted) { StopServer();
pacServer.close(); delete pacServer;
}
} }
void PACServer::SetProxyString(const QString &proxyString) void PACServer::SetProxyString(const QString &proxyString)
{ {
DEBUG(PROXY, "Setting new PAC proxy string: " + proxyString) DEBUG(MODULE_PROXY, "Setting new PAC proxy string: " + proxyString)
this->proxyString = proxyString; this->proxyString = proxyString;
} }
void PACServer::StartListen() void PACServer::run()
{ {
LOG(PROXY, "Starting PAC listener") LOG(MODULE_PROXY, "Starting PAC listener")
// //
auto address = GlobalConfig.inboundConfig.listenip; auto address = GlobalConfig.inboundConfig.listenip;
auto port = GlobalConfig.inboundConfig.pacConfig.port; auto port = GlobalConfig.inboundConfig.pacConfig.port;
// //
DEBUG(PROXY, "PAC Listening local endpoint: " + address + ":" + QSTRN(port)) DEBUG(MODULE_PROXY, "PAC Listening local endpoint: " + address + ":" + QSTRN(port))
// //
QString gfwContent = StringFromFile(QV2RAY_RULES_GFWLIST_PATH); QString gfwContent = StringFromFile(QV2RAY_RULES_GFWLIST_PATH);
pacContent = ConvertGFWToPAC(gfwContent, proxyString); pacContent = ConvertGFWToPAC(gfwContent, proxyString);
// //
auto result = pacServer.listen(QHostAddress(address), static_cast<ushort>(port)); pacServer->Get("/pac", onNewRequest);
auto result = pacServer->listen(address.toStdString().c_str(), static_cast<ushort>(port));
if (result) { if (result)
isStarted = true; {
DEBUG(PROXY, "Started PAC handler") DEBUG(MODULE_PROXY, "PAC handler stopped.")
} else { }
LOG(PROXY, "Failed to listen on port " + QSTRN(port) + ", possible permission denied.") else
{
LOG(MODULE_PROXY, "Failed to listen on port " + QSTRN(port) + ", possible permission denied.")
QvMessageBoxWarn(nullptr, tr("PAC Handler"), tr("Failed to listen PAC request on this port, please verify the permissions")); QvMessageBoxWarn(nullptr, tr("PAC Handler"), tr("Failed to listen PAC request on this port, please verify the permissions"));
} }
} }
void PACServer::StopServer() void PACServer::StopServer()
{ {
if (isStarted) { if (pacServer->is_running())
pacServer.close(); {
DEBUG(PROXY, "PAC Handler stopped.") pacServer->stop();
isStarted = false;
} }
} }
void PACServer::onNewRequest(QHttpRequest *req, QHttpResponse *rsp) void PACServer::onNewRequest(const httplib::Request &req, httplib::Response &rsp)
{ {
rsp->setHeader("Server", "Qv2ray/" QV2RAY_VERSION_STRING " PAC_Handler"); rsp.set_header("Server", "Qv2ray/" QV2RAY_VERSION_STRING " PAC_Handler");
if (req.method == "GET")
if (req->method() == QHttpRequest::HTTP_GET) { {
// if (req.path == "/pac")
if (req->path() == "/pac") { {
DEBUG(PROXY, "Serving PAC file request.") DEBUG(MODULE_PROXY, "Serving PAC file request.")
// //
rsp->setHeader("Content-Type", "application/javascript; charset=utf-8"); rsp.status = 200;
rsp->writeHead(QHttpResponse::StatusCode::STATUS_OK); rsp.set_content(pacContent.toStdString(), "application/javascript; charset=utf-8");
rsp->end(pacContent.toUtf8()); DEBUG(MODULE_PROXY, "Serving a pac file...")
DEBUG(PROXY, "Serving a pac file...")
} else {
rsp->writeHead(QHttpResponse::StatusCode::STATUS_NOT_FOUND);
rsp->end("NOT FOUND");
} }
} else { else
rsp->writeHead(QHttpResponse::StatusCode::STATUS_METHOD_NOT_ALLOWED); {
rsp->end("PAC ONLY SUPPORT GET"); rsp.status = 404;
rsp.set_content("NOT FOUND", "text/plain; charset=utf-8");
}
}
else
{
rsp.status = 405;
rsp.set_content("PAC ONLY SUPPORT GET", "text/plain; charset=utf-8");
} }
} }
} } // namespace Qv2ray::components::pac

View File

@ -1,33 +1,44 @@
#pragma once #pragma once
#include "qhttpserver.h"
#include <QObject> #include <QObject>
#include <QThread>
#include <memory> #include <memory>
namespace httplib
{
class Server;
struct Request;
struct Response;
} // namespace httplib
namespace Qv2ray::components::pac namespace Qv2ray::components::pac
{ {
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString); QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString);
class PACServer : public QObject class PACServer : public QThread
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit PACServer(); explicit PACServer();
~PACServer(); ~PACServer();
void SetProxyString(const QString &proxyString); void SetProxyString(const QString &proxyString);
void StartListen(); void StartListen()
void StopServer(); {
start();
}
void StopServer();
QString gfwFilePath; QString gfwFilePath;
public slots: private:
void onNewRequest(QHttpRequest *request, QHttpResponse *response); void run() override;
httplib::Server *pacServer;
QString proxyString;
private: private:
bool isStarted; static void onNewRequest(const httplib::Request &req, httplib::Response &rsp);
QHttpServer pacServer; static inline QString pacContent;
QString pacContent;
QString proxyString;
}; };
} } // namespace Qv2ray::components::pac
using namespace Qv2ray::components; using namespace Qv2ray::components;
using namespace Qv2ray::components::pac; using namespace Qv2ray::components::pac;

View File

@ -1,7 +1,9 @@
#include <QThread> #include "components/plugins/toolbar/QvToolbar.hpp"
#include "ui/w_MainWindow.hpp"
#include "components/plugins/toolbar/QvToolbar.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "core/handler/ConfigHandler.hpp"
#include <QThread>
namespace Qv2ray::components::plugins namespace Qv2ray::components::plugins
{ {
@ -30,129 +32,148 @@ namespace Qv2ray::components::plugins
} }
QString GetAnswerToRequest(const QString &pchRequest) QString GetAnswerToRequest(const QString &pchRequest)
{ {
auto instance = MainWindow::mwInstance;
if (instance == nullptr || instance->vinstance == nullptr) {
LOG(PLUGIN, "MainWindow != nullptr Assertion failed!")
return "{}";
}
auto vinstance = instance->vinstance;
//
auto req = pchRequest.trimmed(); auto req = pchRequest.trimmed();
QString reply = "{}"; QString reply = "{}";
if (req == "START") { if (req == "START")
emit instance->Connect(); {
} else if (req == "STOP") { emit ConnectionManager->RestartConnection();
emit instance->DisConnect(); }
} else if (req == "RESTART") { else if (req == "STOP")
emit instance->ReConnect(); {
emit ConnectionManager->StopConnection();
}
else if (req == "RESTART")
{
emit ConnectionManager->RestartConnection();
} }
auto BarConfig = GlobalConfig.toolBarConfig; auto BarConfig = GlobalConfig.toolBarConfig;
for (auto i = 0; i < BarConfig.Pages.size(); i++) { for (auto i = 0; i < BarConfig.Pages.size(); i++)
for (auto j = 0; j < BarConfig.Pages[i].Lines.size(); j++) { {
for (auto j = 0; j < BarConfig.Pages[i].Lines.size(); j++)
{
#define CL BarConfig.Pages[i].Lines[j] #define CL BarConfig.Pages[i].Lines[j]
switch (CL.ContentType) { switch (CL.ContentType)
case 0: { {
case 0:
{
// Custom Text // Custom Text
// We do nothing... // We do nothing...
break; break;
} }
case 101: { case 101:
{
// Current Time // Current Time
CL.Message = QTime().currentTime().toString("hh:mm:ss"); CL.Message = QTime().currentTime().toString("hh:mm:ss");
break; break;
} }
case 102: { case 102:
{
// Current Date // Current Date
CL.Message = QDate().currentDate().toString("yyyy-MM-dd"); CL.Message = QDate().currentDate().toString("yyyy-MM-dd");
break; break;
} }
case 103: { case 103:
{
// Current Qv2ray Version // Current Qv2ray Version
CL.Message = QV2RAY_VERSION_STRING; CL.Message = QV2RAY_VERSION_STRING;
break; break;
} }
case 104: { case 104:
{
// Current Connection Name // Current Connection Name
CL.Message = instance->GetCurrentConnectedConfigName(); CL.Message = GetDisplayName(ConnectionManager->CurrentConnection());
break; break;
} }
case 105: { case 105:
{
// Current Connection Status // Current Connection Status
CL.Message = instance->vinstance->KernelStarted CL.Message = ConnectionManager->CurrentConnection() == NullConnectionId ? QObject::tr("Not connected") :
? QObject::tr("Connected") QObject::tr("Connected");
: QObject::tr("Disconnected");
break; break;
} }
case 201: { // case 201:
// Total upload speed; //{
CL.Message = FormatBytes(vinstance->getAllSpeedUp()) + "/s"; // // Total upload speed;
break; // CL.Message = FormatBytes(get<0>(GetConnectionUsageAmount())) + "/s";
} // break;
//}
//
// case 202:
//{
// // Total download speed;
// CL.Message = FormatBytes(vinstance->getAllSpeedDown()) + "/s";
// break;
//}
//
// case 203:
//{
// // Upload speed for tag
// CL.Message = FormatBytes(vinstance->getTagSpeedUp(CL.Message)) + "/s";
// break;
//}
//
// case 204:
//{
// // Download speed for tag
// CL.Message = FormatBytes(vinstance->getTagSpeedDown(CL.Message)) + "/s";
// break;
//}
case 202: { case 301:
// Total download speed; {
CL.Message = FormatBytes(vinstance->getAllSpeedDown()) + "/s";
break;
}
case 203: {
// Upload speed for tag
CL.Message = FormatBytes(vinstance->getTagSpeedUp(CL.Message)) + "/s";
break;
}
case 204: {
// Download speed for tag
CL.Message = FormatBytes(vinstance->getTagSpeedDown(CL.Message)) + "/s";
break;
}
case 301: {
// Total Upload // Total Upload
CL.Message = FormatBytes(vinstance->getAllDataUp()); CL.Message = FormatBytes(get<0>(GetConnectionUsageAmount(ConnectionManager->CurrentConnection())));
break; break;
} }
case 302: { case 302:
{
// Total download // Total download
CL.Message = FormatBytes(vinstance->getAllDataDown()); CL.Message = FormatBytes(get<1>(GetConnectionUsageAmount(ConnectionManager->CurrentConnection())));
break; break;
} }
case 303: { // case 303:
// Upload for tag //{
CL.Message = FormatBytes(vinstance->getTagDataUp(CL.Message)); // // Upload for tag
// CL.Message = FormatBytes(vinstance->getTagDataUp(CL.Message));
// break;
//}
//
// case 304:
//{
// // Download for tag
// CL.Message = FormatBytes(vinstance->getTagDataDown(CL.Message));
// break;
//}
case 305:
{
// Connection latency
CL.Message = QSTRN(GetConnectionLatency(ConnectionManager->CurrentConnection())) + " ms";
break; break;
} }
default:
case 304: { {
// Download for tag CL.Message = "Not Implemented";
CL.Message = FormatBytes(vinstance->getTagDataDown(CL.Message));
break;
}
default: {
CL.Message = "Not Supported?";
break; break;
} }
} }
} }
} }
#undef CL
reply = StructToJsonString(BarConfig); reply = StructToJsonString(BarConfig);
return reply; return reply;
} }
} } // namespace Toolbar
} } // namespace Qv2ray::components::plugins

View File

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

View File

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

View File

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

View File

@ -1,8 +1,10 @@
#include "QvProxyConfigurator.hpp" #include "QvProxyConfigurator.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include "wininet.h" #include <WinInet.h>
#include <windows.h>
#include <Windows.h>
#endif #endif
namespace Qv2ray::components::proxy namespace Qv2ray::components::proxy
@ -13,30 +15,33 @@ namespace Qv2ray::components::proxy
{ {
QProcess p; QProcess p;
p.setProgram("/usr/sbin/networksetup"); p.setProgram("/usr/sbin/networksetup");
p.setArguments(QStringList() << "-listallnetworkservices"); p.setArguments(QStringList{ "-listallnetworkservices" });
p.start(); p.start();
p.waitForStarted(); p.waitForStarted();
p.waitForFinished(); p.waitForFinished();
LOG(PROXY, p.errorString()) LOG(MODULE_PROXY, p.errorString())
auto str = p.readAllStandardOutput(); auto str = p.readAllStandardOutput();
auto lines = SplitLines(str); auto lines = SplitLines(str);
QStringList result; QStringList result;
// Start from 1 since first line is unneeded. // Start from 1 since first line is unneeded.
for (auto i = 1; i < lines.count(); i++) { for (auto i = 1; i < lines.count(); i++)
{
// * means disabled. // * means disabled.
if (!lines[i].contains("*")) { if (!lines[i].contains("*"))
result << (lines[i].contains(" ") ? "\"" + lines[i] + "\"" : lines[i]); {
result << (lines[i].contains(" ") ? "\"" + lines[i] + "\"" : lines[i]);
} }
} }
LOG(PROXY, "Found " + QSTRN(result.size()) + " network services: " + result.join(";")) LOG(MODULE_PROXY, "Found " + QSTRN(result.size()) + " network services: " + result.join(";"))
return result; return result;
} }
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#define NO_CONST(expr) const_cast<wchar_t *>(expr) #define NO_CONST(expr) const_cast<wchar_t *>(expr)
//static auto DEFAULT_CONNECTION_NAME = NO_CONST(L"DefaultConnectionSettings"); // static auto DEFAULT_CONNECTION_NAME =
// NO_CONST(L"DefaultConnectionSettings");
/// ///
/// INTERNAL FUNCTION /// INTERNAL FUNCTION
bool __QueryProxyOptions() bool __QueryProxyOptions()
@ -52,58 +57,69 @@ namespace Qv2ray::components::proxy
Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER; Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
// //
List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
List.pszConnection = nullptr;// NO_CONST(DEFAULT_CONNECTION_NAME); List.pszConnection = nullptr; // NO_CONST(DEFAULT_CONNECTION_NAME);
List.dwOptionCount = 5; List.dwOptionCount = 5;
List.dwOptionError = 0; List.dwOptionError = 0;
List.pOptions = Option; List.pOptions = Option;
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) { if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
LOG(PROXY, "InternetQueryOption failed, GLE=" + QSTRN(GetLastError())) {
LOG(MODULE_PROXY, "InternetQueryOption failed, GLE=" + QSTRN(GetLastError()))
} }
LOG(PROXY, "System default proxy info:") LOG(MODULE_PROXY, "System default proxy info:")
if (Option[0].Value.pszValue != nullptr) { if (Option[0].Value.pszValue != nullptr)
LOG(PROXY, QString::fromWCharArray(Option[0].Value.pszValue)) {
LOG(MODULE_PROXY, QString::fromWCharArray(Option[0].Value.pszValue))
} }
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL) { if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL)
LOG(PROXY, "PROXY_TYPE_AUTO_PROXY_URL") {
LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_PROXY_URL")
} }
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) { if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT)
LOG(PROXY, "PROXY_TYPE_AUTO_DETECT") {
LOG(MODULE_PROXY, "PROXY_TYPE_AUTO_DETECT")
} }
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) { if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT)
LOG(PROXY, "PROXY_TYPE_DIRECT") {
LOG(MODULE_PROXY, "PROXY_TYPE_DIRECT")
} }
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) { if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY)
LOG(PROXY, "PROXY_TYPE_PROXY") {
LOG(MODULE_PROXY, "PROXY_TYPE_PROXY")
} }
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) { if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
LOG(PROXY, "InternetQueryOption failed,GLE=" + QSTRN(GetLastError())) {
LOG(MODULE_PROXY, "InternetQueryOption failed,GLE=" + QSTRN(GetLastError()))
} }
if (Option[4].Value.pszValue != nullptr) { if (Option[4].Value.pszValue != nullptr)
LOG(PROXY, QString::fromStdWString(Option[4].Value.pszValue)) {
LOG(MODULE_PROXY, QString::fromStdWString(Option[4].Value.pszValue))
} }
INTERNET_VERSION_INFO Version; INTERNET_VERSION_INFO Version;
nSize = sizeof(INTERNET_VERSION_INFO); nSize = sizeof(INTERNET_VERSION_INFO);
InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize); InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize);
if (Option[0].Value.pszValue != nullptr) { if (Option[0].Value.pszValue != nullptr)
{
GlobalFree(Option[0].Value.pszValue); GlobalFree(Option[0].Value.pszValue);
} }
if (Option[3].Value.pszValue != nullptr) { if (Option[3].Value.pszValue != nullptr)
{
GlobalFree(Option[3].Value.pszValue); GlobalFree(Option[3].Value.pszValue);
} }
if (Option[4].Value.pszValue != nullptr) { if (Option[4].Value.pszValue != nullptr)
{
GlobalFree(Option[4].Value.pszValue); GlobalFree(Option[4].Value.pszValue);
} }
@ -112,21 +128,23 @@ namespace Qv2ray::components::proxy
bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC) bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC)
{ {
INTERNET_PER_CONN_OPTION_LIST list; INTERNET_PER_CONN_OPTION_LIST list;
BOOL bReturn; BOOL bReturn;
DWORD dwBufSize = sizeof(list); DWORD dwBufSize = sizeof(list);
// Fill the list structure. // Fill the list structure.
list.dwSize = sizeof(list); list.dwSize = sizeof(list);
// NULL == LAN, otherwise connectoid name. // NULL == LAN, otherwise connectoid name.
list.pszConnection = nullptr; list.pszConnection = nullptr;
if (isPAC) { if (isPAC)
LOG(PROXY, "Setting system proxy for PAC") {
LOG(MODULE_PROXY, "Setting system proxy for PAC")
// //
list.dwOptionCount = 2; list.dwOptionCount = 2;
list.pOptions = new INTERNET_PER_CONN_OPTION[2]; list.pOptions = new INTERNET_PER_CONN_OPTION[2];
// Ensure that the memory was allocated. // Ensure that the memory was allocated.
if (nullptr == list.pOptions) { if (nullptr == list.pOptions)
{
// Return FALSE if the memory wasn't allocated. // Return FALSE if the memory wasn't allocated.
return FALSE; return FALSE;
} }
@ -137,13 +155,16 @@ namespace Qv2ray::components::proxy
// Set proxy name. // Set proxy name.
list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
list.pOptions[1].Value.pszValue = proxy_full_addr; list.pOptions[1].Value.pszValue = proxy_full_addr;
} else { }
LOG(PROXY, "Setting system proxy for Global Proxy") else
{
LOG(MODULE_PROXY, "Setting system proxy for Global Proxy")
// //
list.dwOptionCount = 3; list.dwOptionCount = 3;
list.pOptions = new INTERNET_PER_CONN_OPTION[3]; list.pOptions = new INTERNET_PER_CONN_OPTION[3];
if (nullptr == list.pOptions) { if (nullptr == list.pOptions)
{
return false; return false;
} }
@ -161,7 +182,7 @@ namespace Qv2ray::components::proxy
// Set the options on the connection. // Set the options on the connection.
bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize); bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
delete [] list.pOptions; delete[] list.pOptions;
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0); InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0); InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
return bReturn; return bReturn;
@ -170,43 +191,54 @@ namespace Qv2ray::components::proxy
void SetSystemProxy(const QString &address, int httpPort, int socksPort, bool usePAC) void SetSystemProxy(const QString &address, int httpPort, int socksPort, bool usePAC)
{ {
LOG(MODULE_PROXY, "Setting up System Proxy")
bool hasHTTP = (httpPort != 0); bool hasHTTP = (httpPort != 0);
bool hasSOCKS = (socksPort != 0); bool hasSOCKS = (socksPort != 0);
if (!(hasHTTP || hasSOCKS || usePAC)) { if (!(hasHTTP || hasSOCKS || usePAC))
LOG(PROXY, "Nothing?") {
LOG(MODULE_PROXY, "Nothing?")
return; return;
} }
if (usePAC) { if (usePAC)
LOG(PROXY, "Qv2ray will set system proxy to use PAC file") {
} else { LOG(MODULE_PROXY, "Qv2ray will set system proxy to use PAC file")
if (hasHTTP) { }
LOG(PROXY, "Qv2ray will set system proxy to use HTTP") else
{
if (hasHTTP)
{
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use HTTP")
} }
if (hasSOCKS) { if (hasSOCKS)
LOG(PROXY, "Qv2ray will set system proxy to use SOCKS") {
LOG(MODULE_PROXY, "Qv2ray will set system proxy to use SOCKS")
} }
} }
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString __a; QString __a;
if (usePAC) { if (usePAC)
{
__a = address; __a = address;
} else { }
else
{
__a = (hasHTTP ? "http://" : "socks5://") + address + ":" + QSTRN(httpPort); __a = (hasHTTP ? "http://" : "socks5://") + address + ":" + QSTRN(httpPort);
} }
LOG(PROXY, "Windows proxy string: " + __a) LOG(MODULE_PROXY, "Windows proxy string: " + __a)
auto proxyStrW = new WCHAR[__a.length() + 1]; auto proxyStrW = new WCHAR[__a.length() + 1];
wcscpy(proxyStrW, __a.toStdWString().c_str()); wcscpy(proxyStrW, __a.toStdWString().c_str());
// //
__QueryProxyOptions(); __QueryProxyOptions();
if (!__SetProxyOptions(proxyStrW, usePAC)) { if (!__SetProxyOptions(proxyStrW, usePAC))
LOG(PROXY, "Failed to set proxy.") {
LOG(MODULE_PROXY, "Failed to set proxy.")
} }
__QueryProxyOptions(); __QueryProxyOptions();
@ -214,54 +246,104 @@ namespace Qv2ray::components::proxy
QStringList actions; QStringList actions;
auto proxyMode = usePAC ? "auto" : "manual"; auto proxyMode = usePAC ? "auto" : "manual";
actions << QString("gsettings set org.gnome.system.proxy mode '%1'").arg(proxyMode); actions << QString("gsettings set org.gnome.system.proxy mode '%1'").arg(proxyMode);
bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE";
if (usePAC) { if (isKDE)
{
LOG(MODULE_PROXY, "KDE detected")
}
//
if (usePAC)
{
actions << QString("gsettings set org.gnome.system.proxy autoconfig-url '%1'").arg(address); actions << QString("gsettings set org.gnome.system.proxy autoconfig-url '%1'").arg(address);
} else { if (isKDE)
if (hasHTTP) { {
actions << QString("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
"/kioslaverc --group \"Proxy Settings\" --key ProxyType 2");
actions << QString("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
"/kioslaverc --group \"Proxy Settings\" --key \"Proxy Config Script\" " + address);
}
}
else
{
if (isKDE)
{
actions << QString("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
"/kioslaverc --group \"Proxy Settings\" --key ProxyType 1");
}
if (hasHTTP)
{
actions << QString("gsettings set org.gnome.system.proxy.http host '%1'").arg(address); actions << QString("gsettings set org.gnome.system.proxy.http host '%1'").arg(address);
actions << QString("gsettings set org.gnome.system.proxy.http port %1").arg(httpPort); actions << QString("gsettings set org.gnome.system.proxy.http port %1").arg(httpPort);
// //
actions << QString("gsettings set org.gnome.system.proxy.https host '%1'").arg(address); actions << QString("gsettings set org.gnome.system.proxy.https host '%1'").arg(address);
actions << QString("gsettings set org.gnome.system.proxy.https port %1").arg(httpPort);; actions << QString("gsettings set org.gnome.system.proxy.https port %1").arg(httpPort);
if (isKDE)
{
// FTP here should be scheme: ftp://
for (auto protocol : { "http", "ftp", "https" })
{
auto str = QString("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
"/kioslaverc --group \"Proxy Settings\" --key %1Proxy \"http://%2 %3\"")
.arg(protocol)
.arg(address)
.arg(QSTRN(httpPort));
actions << str;
}
}
} }
if (hasSOCKS) { if (hasSOCKS)
{
actions << QString("gsettings set org.gnome.system.proxy.socks host '%1'").arg(address); actions << QString("gsettings set org.gnome.system.proxy.socks host '%1'").arg(address);
actions << QString("gsettings set org.gnome.system.proxy.socks port %1").arg(socksPort); actions << QString("gsettings set org.gnome.system.proxy.socks port %1").arg(socksPort);
if (isKDE)
{
actions << QString("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
"/kioslaverc --group \"Proxy Settings\" --key socksProxy \"socks://%1 %2\"")
.arg(address)
.arg(QSTRN(socksPort));
}
} }
} }
// note: do not use std::all_of / any_of / none_of, // note: do not use std::all_of / any_of / none_of,
// because those are short-circuit and cannot guarantee atomicity. // because those are short-circuit and cannot guarantee atomicity.
auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString & action) { auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString &action) {
DEBUG(PROXY, action) DEBUG(MODULE_PROXY, action)
return QProcess::execute(action) == QProcess::NormalExit; return QProcess::execute(action) == QProcess::NormalExit;
}) == actions.size(); }) == actions.size();
if (!result) { if (!result)
LOG(PROXY, "Something wrong happens when setting system proxy -> Gnome ONLY.") {
LOG(PROXY, "If you are using KDE Plasma and receiving this message, just simply ignore this.") LOG(MODULE_PROXY, "There was something wrong when setting proxies.")
LOG(MODULE_PROXY, "It may happen if you are using KDE with no gsettings support.")
} }
Q_UNUSED(result); Q_UNUSED(result);
#else #else
for (auto service : macOSgetNetworkServices()) { for (auto service : macOSgetNetworkServices())
LOG(PROXY, "Setting proxy for interface: " + service) {
LOG(MODULE_PROXY, "Setting proxy for interface: " + service)
if (usePAC) { if (usePAC)
{
QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " on"); QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setautoproxyurl " + service + " " + address); QProcess::execute("/usr/sbin/networksetup -setautoproxyurl " + service + " " + address);
} else { }
if (hasHTTP) { else
{
if (hasHTTP)
{
QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " on"); QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxystate " + service + " on"); QProcess::execute("/usr/sbin/networksetup -setsecurewebproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setwebproxy " + service + " " + address + " " + QSTRN(httpPort)); QProcess::execute("/usr/sbin/networksetup -setwebproxy " + service + " " + address + " " + QSTRN(httpPort));
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxy " + service + " " + address + " " + QSTRN(httpPort)); QProcess::execute("/usr/sbin/networksetup -setsecurewebproxy " + service + " " + address + " " + QSTRN(httpPort));
} }
if (hasSOCKS) { if (hasSOCKS)
{
QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxystate " + service + " on"); QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxystate " + service + " on");
QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxy " + service + " " + address + " " + QSTRN(socksPort)); QProcess::execute("/usr/sbin/networksetup -setsocksfirewallproxy " + service + " " + address + " " + QSTRN(socksPort));
} }
@ -273,8 +355,9 @@ namespace Qv2ray::components::proxy
void ClearSystemProxy() void ClearSystemProxy()
{ {
LOG(MODULE_PROXY, "Clearing System Proxy")
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
LOG(PROXY, "Cleaning system proxy settings.") LOG(MODULE_PROXY, "Cleaning system proxy settings.")
INTERNET_PER_CONN_OPTION_LIST list; INTERNET_PER_CONN_OPTION_LIST list;
BOOL bReturn; BOOL bReturn;
DWORD dwBufSize = sizeof(list); DWORD dwBufSize = sizeof(list);
@ -287,9 +370,10 @@ namespace Qv2ray::components::proxy
list.pOptions = new INTERNET_PER_CONN_OPTION[list.dwOptionCount]; list.pOptions = new INTERNET_PER_CONN_OPTION[list.dwOptionCount];
// Make sure the memory was allocated. // Make sure the memory was allocated.
if (nullptr == list.pOptions) { if (nullptr == list.pOptions)
{
// Return FALSE if the memory wasn't allocated. // Return FALSE if the memory wasn't allocated.
LOG(PROXY, "Failed to allocat memory in DisableConnectionProxy()") LOG(MODULE_PROXY, "Failed to allocat memory in DisableConnectionProxy()")
} }
// Set flags. // Set flags.
@ -298,15 +382,21 @@ namespace Qv2ray::components::proxy
// //
// Set the options on the connection. // Set the options on the connection.
bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize); bReturn = InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
delete [] list.pOptions; delete[] list.pOptions;
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0); InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0); InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
if (qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE")
{
QProcess::execute("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
"/kioslaverc --group \"Proxy Settings\" --key ProxyType 0");
}
QProcess::execute("gsettings set org.gnome.system.proxy mode 'none'"); QProcess::execute("gsettings set org.gnome.system.proxy mode 'none'");
#else #else
for (auto service : macOSgetNetworkServices()) { for (auto service : macOSgetNetworkServices())
LOG(PROXY, "Clearing proxy for interface: " + service) {
LOG(MODULE_PROXY, "Clearing proxy for interface: " + service)
QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " off"); QProcess::execute("/usr/sbin/networksetup -setautoproxystate " + service + " off");
QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " off"); QProcess::execute("/usr/sbin/networksetup -setwebproxystate " + service + " off");
QProcess::execute("/usr/sbin/networksetup -setsecurewebproxystate " + service + " off"); QProcess::execute("/usr/sbin/networksetup -setsecurewebproxystate " + service + " off");
@ -315,4 +405,4 @@ namespace Qv2ray::components::proxy
#endif #endif
} }
} } // namespace Qv2ray::components::proxy

View File

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

View File

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

View File

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

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