diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 8e94654..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-indent_size = 2
-insert_final_newline = true
-
-[*.rs]
-charset = utf-8
-end_of_line = lf
-indent_size = 4
-insert_final_newline = true
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 6749373..0000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: "[BUG]"
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Information**
- - OS: [e.g. macOS]
- - Clash Verge Version: [e.g. 1.3.4]
- - Clash Core: [e.g. Clash or Clash Meta]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 6269982..0000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: "[Feature]"
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml
deleted file mode 100644
index 91eeb6c..0000000
--- a/.github/workflows/alpha.yml
+++ /dev/null
@@ -1,93 +0,0 @@
-name: Alpha CI
-
-on:
- workflow_dispatch:
- inputs:
- debug:
- type: boolean
- default: false
-
-env:
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: short
-
-jobs:
- release:
- strategy:
- fail-fast: false
- matrix:
- os: [windows-latest, ubuntu-20.04, macos-latest]
- runs-on: ${{ matrix.os }}
- if: startsWith(github.repository, 'zzzgydi')
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: install Rust stable
- uses: dtolnay/rust-toolchain@stable
-
- - name: Rust Cache
- uses: Swatinem/rust-cache@v2
- with:
- workspaces: src-tauri
-
- - name: Install Node
- uses: actions/setup-node@v4
- with:
- node-version: "16"
- cache: "yarn"
-
- - name: Delete current release assets
- if: startsWith(matrix.os, 'ubuntu-')
- uses: mknejp/delete-release-assets@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- tag: alpha
- fail-if-no-assets: false
- fail-if-no-release: false
- assets: |
- *.zip
- *.gz
- *.AppImage
- *.deb
- *.dmg
- *.msi
- *.sig
- *.exe
-
- - name: Install Dependencies (ubuntu only)
- if: startsWith(matrix.os, 'ubuntu-')
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
-
- - name: Yarn install and check
- run: |
- yarn install --network-timeout 1000000 --frozen-lockfile
- yarn run check
-
- - name: Tauri build
- uses: tauri-apps/tauri-action@v0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- with:
- tagName: alpha
- releaseName: "Clash Verge Alpha"
- releaseBody: "Alpha Version (include debug)"
- releaseDraft: false
- prerelease: true
- includeDebug: ${{ github.event.inputs.debug }}
-
- - name: Portable Bundle
- if: startsWith(matrix.os, 'windows-')
- run: |
- yarn build
- yarn run portable
- env:
- TAG_NAME: alpha
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- VITE_WIN_PORTABLE: 1
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 1fce34f..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,98 +0,0 @@
-name: Release CI
-
-on:
- workflow_dispatch:
- push:
- tags:
- - v**
-
-env:
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: short
-
-jobs:
- release:
- strategy:
- matrix:
- os: [windows-latest, ubuntu-latest, macos-latest]
- runs-on: ${{ matrix.os }}
- if: startsWith(github.repository, 'zzzgydi')
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: install Rust stable
- uses: dtolnay/rust-toolchain@stable
-
- - name: Rust Cache
- uses: Swatinem/rust-cache@v2
- with:
- workspaces: src-tauri
-
- - name: Install Node
- uses: actions/setup-node@v4
- with:
- node-version: "16"
- cache: "yarn"
-
- - name: Install Dependencies (ubuntu only)
- if: startsWith(matrix.os, 'ubuntu-')
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
-
- - name: Yarn install and check
- run: |
- yarn install --network-timeout 1000000 --frozen-lockfile
- yarn run check
-
- - name: Tauri build
- uses: tauri-apps/tauri-action@v0
- # enable cache even though failed
- # continue-on-error: true
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- with:
- tagName: v__VERSION__
- releaseName: "Clash Verge v__VERSION__"
- releaseBody: "More new features are now supported."
- releaseDraft: false
- prerelease: true
-
- - name: Portable Bundle
- if: startsWith(matrix.os, 'windows-')
- # rebuild with env settings
- run: |
- yarn build
- yarn run portable
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- VITE_WIN_PORTABLE: 1
-
- release-update:
- needs: release
- runs-on: ubuntu-latest
- if: |
- startsWith(github.repository, 'zzzgydi') &&
- startsWith(github.ref, 'refs/tags/v')
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Install Node
- uses: actions/setup-node@v4
- with:
- node-version: "16"
- cache: "yarn"
-
- - name: Yarn install
- run: yarn install --network-timeout 1000000 --frozen-lockfile
-
- - name: Release updater file
- run: yarn run updater
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/compatible.yml b/.github/workflows/compatible.yml
deleted file mode 100644
index abbbbb6..0000000
--- a/.github/workflows/compatible.yml
+++ /dev/null
@@ -1,102 +0,0 @@
-name: Compatible CI
-
-on:
- workflow_dispatch:
- # push:
- # tags:
- # - v**
-
-env:
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: short
-
-jobs:
- build:
- strategy:
- fail-fast: false
- matrix:
- targets:
- - tag: macOS-10.15
- os: macos-10.15
- - tag: Ubuntu18
- os: ubuntu-18.04
- - tag: Ubuntu22
- os: ubuntu-22.04
-
- runs-on: ${{ matrix.targets.os }}
- if: startsWith(github.repository, 'zzzgydi')
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- - name: Install Rust
- uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- profile: minimal
- override: true
-
- - name: Rust Cache
- uses: Swatinem/rust-cache@v2
- with:
- workspaces: src-tauri
-
- - name: Install Node
- uses: actions/setup-node@v1
- with:
- node-version: 16
-
- # - name: Install Dependencies (ubuntu18 only)
- # if: matrix.targets.os == 'ubuntu-18.04'
- # run: |
- # sudo apt-get update
- # sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libappindicator3-dev librsvg2-dev libayatana-appindicator3-dev
-
- - name: Install Dependencies (ubuntu22 only)
- if: startsWith(matrix.targets.os, 'ubuntu-')
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
-
- - name: Get yarn cache dir path
- id: yarn-cache-dir-path
- run: echo "::set-output name=dir::$(yarn cache dir)"
-
- - name: Yarn Cache
- uses: actions/cache@v2
- id: yarn-cache
- with:
- path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-yarn-
-
- - name: Yarn install and check
- run: |
- yarn install --network-timeout 1000000
- yarn run check
-
- - name: Tauri build
- uses: tauri-apps/tauri-action@v0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- with:
- tagName: ${{ matrix.targets.tag }}
- releaseName: "Compatible For ${{ matrix.targets.tag }}"
- releaseBody: "More new features are now supported."
- releaseDraft: false
- prerelease: false
-
- # - name: Portable Bundle
- # if: matrix.os == 'windows-latest'
- # # rebuild with env settings
- # run: |
- # yarn build
- # yarn run portable
- # env:
- # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- # TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- # TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- # VITE_WIN_PORTABLE: 1
diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml
deleted file mode 100644
index a26d9f0..0000000
--- a/.github/workflows/meta.yml
+++ /dev/null
@@ -1,107 +0,0 @@
-name: Meta CI
-
-on:
- workflow_dispatch:
- push:
- tags:
- - v**
-
-env:
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: short
-
-jobs:
- release:
- strategy:
- fail-fast: false
- matrix:
- os: [windows-latest, ubuntu-latest, macos-latest]
- runs-on: ${{ matrix.os }}
- if: startsWith(github.repository, 'zzzgydi')
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- - name: Install Rust
- uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- profile: minimal
- override: true
-
- - name: Rust Cache
- uses: Swatinem/rust-cache@v2
- with:
- workspaces: src-tauri
-
- - name: Install Node
- uses: actions/setup-node@v1
- with:
- node-version: 16
-
- - name: Delete current release assets
- if: matrix.os == 'ubuntu-latest'
- uses: mknejp/delete-release-assets@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- tag: meta
- fail-if-no-assets: false
- fail-if-no-release: false
- assets: |
- *.zip
- *.gz
- *.AppImage
- *.deb
- *.dmg
- *.msi
- *.sig
-
- - name: Install Dependencies (ubuntu only)
- if: startsWith(matrix.os, 'ubuntu-')
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
-
- - name: Get yarn cache dir path
- id: yarn-cache-dir-path
- run: echo "::set-output name=dir::$(yarn cache dir)"
-
- - name: Yarn Cache
- uses: actions/cache@v2
- id: yarn-cache
- with:
- path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-yarn-
-
- - name: Yarn install and check
- run: |
- yarn install --network-timeout 1000000
- yarn run check
-
- - name: Tauri build
- uses: tauri-apps/tauri-action@v0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- with:
- tagName: meta
- releaseName: "Clash Verge Meta"
- releaseBody: ""
- releaseDraft: false
- prerelease: true
- args: -f default-meta
-
- - name: Portable Bundle
- if: matrix.os == 'windows-latest'
- run: |
- yarn build -f default-meta
- yarn run portable
- env:
- TAG_NAME: meta
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- VITE_WIN_PORTABLE: 1
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index 3576f5c..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-name: Test CI
-
-on:
- workflow_dispatch:
- inputs:
- os:
- description: "Runs on OS"
- required: true
- default: windows-latest
- type: choice
- options:
- - windows-latest
- - ubuntu-latest
- - macos-latest
- - ubuntu-18.04
- - ubuntu-20.04
- - ubuntu-22.04
- - macos-10.15
- - macos-11
- - macos-12
- - windows-2019
- - windows-2022
-
-env:
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: short
-
-jobs:
- release:
- runs-on: ${{ github.event.inputs.os }}
- if: startsWith(github.repository, 'zzzgydi')
- steps:
- - name: System Version
- run: |
- echo ${{ github.event.inputs.os }}
-
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: install Rust stable
- uses: dtolnay/rust-toolchain@stable
-
- - name: Rust Cache
- uses: Swatinem/rust-cache@v2
- with:
- workspaces: src-tauri
-
- - name: Install Node
- uses: actions/setup-node@v4
- with:
- node-version: "16"
- cache: "yarn"
-
- - name: Install Dependencies (ubuntu only)
- if: startsWith(github.event.inputs.os, 'ubuntu-')
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
-
- - name: Yarn install and check
- run: |
- yarn install --network-timeout 1000000 --frozen-lockfile
- yarn run check
-
- - name: Tauri build
- uses: tauri-apps/tauri-action@v0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
- TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- with:
- tagName: alpha
- releaseName: "Clash Verge Alpha"
- releaseBody: "Alpha Version (include debug)"
- releaseDraft: false
- includeUpdaterJson: false
diff --git a/.github/workflows/updater.yml b/.github/workflows/updater.yml
deleted file mode 100644
index 7c21078..0000000
--- a/.github/workflows/updater.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-name: Updater CI
-
-on: workflow_dispatch
-
-jobs:
- release-update:
- runs-on: ubuntu-latest
- if: startsWith(github.repository, 'zzzgydi')
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Install Node
- uses: actions/setup-node@v4
- with:
- node-version: "16"
- cache: "yarn"
-
- - name: Yarn install
- run: yarn install --network-timeout 1000000 --frozen-lockfile
-
- - name: Release updater file
- run: yarn run updater
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index c9e2fb9..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-node_modules
-.DS_Store
-dist
-dist-ssr
-*.local
-update.json
-scripts/_env.sh
-.vscode
diff --git a/.husky/pre-commit b/.husky/pre-commit
deleted file mode 100755
index f3a6796..0000000
--- a/.husky/pre-commit
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
-
-yarn pretty-quick --staged
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index f288702..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
- .
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
diff --git a/README.md b/README.md
index d78bc47..4c3e5e5 100644
--- a/README.md
+++ b/README.md
@@ -1,158 +1 @@
-
-
-
- Clash Verge
-
-
-
-
-
-## Features
-
-- Full `clash` config supported, Partial `clash premium` config supported.
-- Profiles management and enhancement (by yaml and Javascript). [Doc](https://github.com/zzzgydi/clash-verge/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97)
-- Simple UI and supports custom theme color.
-- Built-in support [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta) core.
-- System proxy setting and guard.
-
-## Promotion
-
-[狗狗加速 —— 技术流机场 Doggygo VPN](https://dg1.top)
-
-- High-performance overseas VPN, free trial, discounted packages, unlock streaming media, the world's first to support Hysteria protocol.
-- 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。
-- 使用 Clash Verge 专属邀请链接注册送 15 天,每天 1G 流量免费试用:https://panel.dg1.top/#/register?code=sFCDayZf
-
-
-Promotion Detail
-
-- Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份)
-- 优惠套餐每月仅需 15.8 元,160G 流量,年付 8 折
-- 海外团队,无跑路风险,高达 50% 返佣
-- 集群负载均衡设计,高速专线(兼容老客户端),极低延迟,无视晚高峰,4K 秒开
-- 全球首家 Hysteria 协议机场,将在今年 10 月上线更快的 `tuic` 协议(Clash Verge 客户端最佳搭配)
-- 解锁流媒体及 ChatGPT
-- 官网:https://dg1.top
-
-
-
-
-
-[EEVPN —— 海外运营机场 ※ 支持 ChatGPT](https://www.eejsq.net/#/register?code=yRr6qBO3)
-
-- 年付低至 9.99 元,价格低,速度不减
-
-
-Promotion Detail
-
-- 中国大陆 BGP 网络接入
-- IEPL 专线网络
-- 最高 2500Mbps 速率可用
-- 不限制在线客户端
-- 解锁流媒体及 ChatGPT
-- 海外运营 数据安全
-
-
-
-## Install
-
-Download from [release](https://github.com/zzzgydi/clash-verge/releases). Supports Windows x64, Linux x86_64 and macOS 11+
-
-- [Windows x64](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/Clash.Verge_1.3.8_x64_en-US.msi)
-- [macOS intel](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/Clash.Verge_1.3.8_x64.dmg)
-- [macOS arm](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/Clash.Verge_1.3.8_aarch64.dmg)
-- [Linux AppImage](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/clash-verge_1.3.8_amd64.AppImage)
-- [Linux deb](https://github.com/zzzgydi/clash-verge/releases/download/v1.3.8/clash-verge_1.3.8_amd64.deb)
-- [Fedora Linux](https://github.com/zzzgydi/clash-verge/issues/352)
-
-Or you can build it yourself. Supports Windows, Linux and macOS 10.15+
-
-Notes: If you could not start the app on Windows, please check that you have [Webview2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) installed.
-
-### FAQ
-
-#### 1. **macOS** "Clash Verge" is damaged and can't be opened
-
-open the terminal and run `sudo xattr -r -d com.apple.quarantine /Applications/Clash\ Verge.app`
-
-## Development
-
-You should install Rust and Nodejs, see [here](https://tauri.app/v1/guides/getting-started/prerequisites) for more details. Then install Nodejs packages.
-
-```shell
-yarn install
-```
-
-Then download the clash binary... Or you can download it from [clash premium release](https://github.com/Dreamacro/clash/releases/tag/premium) and rename it according to [tauri config](https://tauri.studio/docs/api/config/#tauri.bundle.externalBin).
-
-```shell
-# force update to latest version
-# yarn run check --force
-
-yarn run check
-```
-
-Then run
-
-```shell
-yarn dev
-
-# run it in another way if app instance exists
-yarn dev:diff
-```
-
-Or you can build it
-
-```shell
-yarn build
-```
-
-## Todos
-
-> This keng is a little big...
-
-## Screenshots
-
-
-
-### Custom Theme
-
-
-
-## Disclaimer
-
-This is a learning project for Rust practice.
-
-## Contributions
-
-Issue and PR welcome!
-
-## Acknowledgement
-
-Clash Verge was based on or inspired by these projects and so on:
-
-- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Build smaller, faster, and more secure desktop applications with a web frontend.
-- [Dreamacro/clash](https://github.com/Dreamacro/clash): A rule-based tunnel in Go.
-- [MetaCubeX/Clash.Meta](https://github.com/MetaCubeX/Clash.Meta): A rule-based tunnel in Go.
-- [Fndroid/clash_for_windows_pkg](https://github.com/Fndroid/clash_for_windows_pkg): A Windows/macOS GUI based on Clash.
-- [vitejs/vite](https://github.com/vitejs/vite): Next generation frontend tooling. It's fast!
-
-## License
-
-GPL-3.0 License. See [License here](./LICENSE) for details.
+Removed
diff --git a/UPDATELOG.md b/UPDATELOG.md
deleted file mode 100644
index a08a86e..0000000
--- a/UPDATELOG.md
+++ /dev/null
@@ -1,472 +0,0 @@
-## v1.3.8
-
-### Features
-
-- update clash meta core
-- add default valid keys
-- adjust the delay display interval and color
-
-### Bug Fixes
-
-- fix connections page undefined exception
-
----
-
-## v1.3.7
-
-### Features
-
-- update clash and clash meta core
-- profiles page add paste button
-- subscriptions url textfield use multi lines
-- set min window size
-- add check for updates buttons
-- add open dashboard to the hotkey list
-
-### Bug Fixes
-
-- fix profiles page undefined exception
-
----
-
-## v1.3.6
-
-### Features
-
-- add russian translation
-- support to show connection detail
-- support clash meta memory usage display
-- support proxy provider update ui
-- update geo data file from meta repo
-- adjust setting page
-
-### Bug Fixes
-
-- center the window when it is out of screen
-- use `sudo` when `pkexec` not found (Linux)
-- reconnect websocket when window focus
-
-### Notes
-
-- The current version of the Linux installation package is built by Ubuntu 20.04 (Github Action).
-
----
-
-## v1.3.5
-
-### Features
-
-- update clash core
-
-### Bug Fixes
-
-- fix blurry system tray icon (Windows)
-- fix v1.3.4 wintun.dll not found (Windows)
-- fix v1.3.4 clash core not found (macOS, Linux)
-
----
-
-## v1.3.4
-
-### Features
-
-- update clash and clash meta core
-- optimize traffic graph high CPU usage when window hidden
-- use polkit to elevate permission (Linux)
-- support app log level setting
-- support copy environment variable
-- overwrite resource file according to file modified
-- save window size and position
-
-### Bug Fixes
-
-- remove fallback group select status
-- enable context menu on editable element (Windows)
-
----
-
-## v1.3.3
-
-### Features
-
-- update clash and clash meta core
-- show tray icon variants in different system proxy status (Windows)
-- close all connections when mode changed
-
-### Bug Fixes
-
-- encode controller secret into uri
-- error boundary for each page
-
----
-
-## v1.3.2
-
-### Features
-
-- update clash and clash meta core
-
-### Bug Fixes
-
-- fix import url issue
-- fix profile undefined issue
-
----
-
-## v1.3.1
-
-### Features
-
-- update clash and clash meta core
-
-### Bug Fixes
-
-- fix open url issue
-- fix appimage path panic
-- fix grant root permission in macOS
-- fix linux system proxy default bypass
-
----
-
-## v1.3.0
-
-### Features
-
-- update clash and clash meta
-- support opening dir on tray
-- support updating all profiles with one click
-- support granting root permission to clash core(Linux, macOS)
-- support enable/disable clash fields filter, feel free to experience the latest features of Clash Meta
-
-### Bug Fixes
-
-- deb add openssl depend(Linux)
-- fix the AppImage auto launch path(Linux)
-- fix get the default network service(macOS)
-- remove the esc key listener in macOS, cmd+w instead(macOS)
-- fix infinite retry when websocket error
-
----
-
-## v1.2.3
-
-### Features
-
-- update clash
-- adjust macOS window style
-- profile supports UTF8 with BOM
-
-### Bug Fixes
-
-- fix selected proxy
-- fix error log
-
----
-
-## v1.2.2
-
-### Features
-
-- update clash meta
-- recover clash core after panic
-- use system window decorations(Linux)
-
-### Bug Fixes
-
-- flush system proxy settings(Windows)
-- fix parse log panic
-- fix ui bug
-
----
-
-## v1.2.1
-
-### Features
-
-- update clash version
-- proxy groups support multi columns
-- optimize ui
-
-### Bug Fixes
-
-- fix ui websocket connection
-- adjust delay check concurrency
-- avoid setting login item repeatedly(macOS)
-
----
-
-## v1.2.0
-
-### Features
-
-- update clash meta version
-- support to change external-controller
-- support to change default latency test URL
-- close all connections when proxy changed or profile changed
-- check the config by using the core
-- increase the robustness of the program
-- optimize windows service mode (need to reinstall)
-- optimize ui
-
-### Bug Fixes
-
-- invalid hotkey cause panic
-- invalid theme setting cause panic
-- fix some other glitches
-
----
-
-## v1.1.2
-
-### Features
-
-- the system tray follows i18n
-- change the proxy group ui of global mode
-- support to update profile with the system proxy/clash proxy
-- check the remote profile more strictly
-
-### Bug Fixes
-
-- use app version as default user agent
-- the clash not exit in service mode
-- reset the system proxy when quit the app
-- fix some other glitches
-
----
-
-## v1.1.1
-
-### Features
-
-- optimize clash config feedback
-- hide macOS dock icon
-- use clash meta compatible version (Linux)
-
-### Bug Fixes
-
-- fix some other glitches
-
----
-
-## v1.1.0
-
-### Features
-
-- add rule page
-- supports proxy providers delay check
-- add proxy delay check loading status
-- supports hotkey/shortcut management
-- supports displaying connections data in table layout(refer to yacd)
-
-### Bug Fixes
-
-- supports yaml merge key in clash config
-- detect the network interface and set the system proxy(macOS)
-- fix some other glitches
-
----
-
-## v1.0.6
-
-### Features
-
-- update clash and clash.meta
-
-### Bug Fixes
-
-- only script profile display console
-- automatic configuration update on demand at launch
-
----
-
-## v1.0.5
-
-### Features
-
-- reimplement profile enhanced mode with quick-js
-- optimize the runtime config generation process
-- support web ui management
-- support clash field management
-- support viewing the runtime config
-- adjust some pages style
-
-### Bug Fixes
-
-- fix silent start
-- fix incorrectly reset system proxy on exit
-
----
-
-## v1.0.4
-
-### Features
-
-- update clash core and clash meta version
-- support switch clash mode on system tray
-- theme mode support follows system
-
-### Bug Fixes
-
-- config load error on first use
-
----
-
-## v1.0.3
-
-### Features
-
-- save some states such as URL test, filter, etc
-- update clash core and clash-meta core
-- new icon for macOS
-
----
-
-## v1.0.2
-
-### Features
-
-- supports for switching clash core
-- supports release UI processes
-- supports script mode setting
-
-### Bug Fixes
-
-- fix service mode bug (Windows)
-
----
-
-## v1.0.1
-
-### Features
-
-- adjust default theme settings
-- reduce gpu usage of traffic graph when hidden
-- supports more remote profile response header setting
-- check remote profile data format when imported
-
-### Bug Fixes
-
-- service mode install and start issue (Windows)
-- fix launch panic (Some Windows)
-
----
-
-## v1.0.0
-
-### Features
-
-- update clash core
-- optimize traffic graph animation
-- supports interval update profiles
-- supports service mode (Windows)
-
-### Bug Fixes
-
-- reset system proxy when exit from dock (macOS)
-- adjust clash dns config process strategy
-
----
-
-## v0.0.29
-
-### Features
-
-- sort proxy node
-- custom proxy test url
-- logs page filter
-- connections page filter
-- default user agent for subscription
-- system tray add tun mode toggle
-- enable to change the config dir (Windows only)
-
----
-
-## v0.0.28
-
-### Features
-
-- enable to use clash config fields (UI)
-
-### Bug Fixes
-
-- remove the character
-- fix some icon color
-
----
-
-## v0.0.27
-
-### Features
-
-- supports custom theme color
-- tun mode setting control the final config
-
-### Bug Fixes
-
-- fix transition flickers (macOS)
-- reduce proxy page render
-
----
-
-## v0.0.26
-
-### Features
-
-- silent start
-- profile editor
-- profile enhance mode supports more fields
-- optimize profile enhance mode strategy
-
-### Bug Fixes
-
-- fix csp restriction on macOS
-- window controllers on Linux
-
----
-
-## v0.0.25
-
-### Features
-
-- update clash core version
-
-### Bug Fixes
-
-- app updater error
-- display window controllers on Linux
-
-### Notes
-
-If you can't update the app properly, please consider downloading the latest version from github release.
-
----
-
-## v0.0.24
-
-### Features
-
-- Connections page
-- add wintun.dll (Windows)
-- supports create local profile with selected file (Windows)
-- system tray enable set system proxy
-
-### Bug Fixes
-
-- open dir error
-- auto launch path (Windows)
-- fix some clash config error
-- reduce the impact of the enhanced mode
-
----
-
-## v0.0.23
-
-### Features
-
-- i18n supports
-- Remote profile User Agent supports
-
-### Bug Fixes
-
-- clash config file case ignore
-- clash `external-controller` only port
diff --git a/docs/color1.png b/docs/color1.png
deleted file mode 100644
index 9c24fb8..0000000
Binary files a/docs/color1.png and /dev/null differ
diff --git a/docs/color2.png b/docs/color2.png
deleted file mode 100644
index 8d6d935..0000000
Binary files a/docs/color2.png and /dev/null differ
diff --git a/docs/color3.png b/docs/color3.png
deleted file mode 100644
index 247b841..0000000
Binary files a/docs/color3.png and /dev/null differ
diff --git a/docs/color4.png b/docs/color4.png
deleted file mode 100644
index 3ecb750..0000000
Binary files a/docs/color4.png and /dev/null differ
diff --git a/docs/color5.png b/docs/color5.png
deleted file mode 100644
index 65e916a..0000000
Binary files a/docs/color5.png and /dev/null differ
diff --git a/docs/color6.png b/docs/color6.png
deleted file mode 100644
index 5067320..0000000
Binary files a/docs/color6.png and /dev/null differ
diff --git a/docs/demo1.png b/docs/demo1.png
deleted file mode 100644
index b18450f..0000000
Binary files a/docs/demo1.png and /dev/null differ
diff --git a/docs/demo2.png b/docs/demo2.png
deleted file mode 100644
index a2919b6..0000000
Binary files a/docs/demo2.png and /dev/null differ
diff --git a/docs/demo3.png b/docs/demo3.png
deleted file mode 100644
index 55267b5..0000000
Binary files a/docs/demo3.png and /dev/null differ
diff --git a/docs/demo4.png b/docs/demo4.png
deleted file mode 100644
index ef9b90a..0000000
Binary files a/docs/demo4.png and /dev/null differ
diff --git a/docs/demo5.png b/docs/demo5.png
deleted file mode 100644
index a7eac54..0000000
Binary files a/docs/demo5.png and /dev/null differ
diff --git a/docs/demo6.png b/docs/demo6.png
deleted file mode 100644
index fe53e2b..0000000
Binary files a/docs/demo6.png and /dev/null differ
diff --git a/package.json b/package.json
deleted file mode 100644
index 8249427..0000000
--- a/package.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "name": "clash-verge",
- "version": "1.3.8",
- "license": "GPL-3.0",
- "scripts": {
- "dev": "tauri dev",
- "dev:diff": "tauri dev -f verge-dev",
- "build": "tauri build",
- "tauri": "tauri",
- "web:dev": "vite",
- "web:build": "tsc && vite build",
- "web:serve": "vite preview",
- "aarch": "node scripts/aarch.mjs",
- "check": "node scripts/check.mjs",
- "updater": "node scripts/updater.mjs",
- "publish": "node scripts/publish.mjs",
- "portable": "node scripts/portable.mjs",
- "prepare": "husky install"
- },
- "dependencies": {
- "@emotion/react": "^11.10.5",
- "@emotion/styled": "^11.10.5",
- "@juggle/resize-observer": "^3.4.0",
- "@mui/icons-material": "^5.10.9",
- "@mui/material": "^5.10.13",
- "@mui/x-data-grid": "^5.17.11",
- "@tauri-apps/api": "^1.3.0",
- "ahooks": "^3.7.2",
- "axios": "^1.1.3",
- "dayjs": "1.11.5",
- "i18next": "^22.0.4",
- "lodash-es": "^4.17.21",
- "monaco-editor": "^0.34.1",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-error-boundary": "^3.1.4",
- "react-hook-form": "^7.39.5",
- "react-i18next": "^12.0.0",
- "react-router-dom": "^6.4.3",
- "react-virtuoso": "^3.1.3",
- "recoil": "^0.7.6",
- "snarkdown": "^2.0.0",
- "swr": "^1.3.0"
- },
- "devDependencies": {
- "@actions/github": "^5.0.3",
- "@tauri-apps/cli": "^1.3.1",
- "@types/fs-extra": "^9.0.13",
- "@types/js-cookie": "^3.0.2",
- "@types/lodash": "^4.14.180",
- "@types/lodash-es": "^4.17.7",
- "@types/react-dom": "^18.0.11",
- "@vitejs/plugin-react": "^2.0.1",
- "adm-zip": "^0.5.9",
- "cross-env": "^7.0.3",
- "fs-extra": "^10.0.0",
- "https-proxy-agent": "^5.0.1",
- "husky": "^7.0.0",
- "node-fetch": "^3.2.6",
- "prettier": "^2.7.1",
- "pretty-quick": "^3.1.3",
- "sass": "^1.54.0",
- "typescript": "^4.7.4",
- "vite": "^3.2.5",
- "vite-plugin-monaco-editor": "^1.1.0",
- "vite-plugin-svgr": "^2.2.1"
- },
- "prettier": {
- "tabWidth": 2,
- "semi": true,
- "singleQuote": false,
- "endOfLine": "lf"
- }
-}
diff --git a/scripts/aarch.mjs b/scripts/aarch.mjs
deleted file mode 100644
index 989e774..0000000
--- a/scripts/aarch.mjs
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Build and upload assets
- * for macOS(aarch)
- */
-import fs from "fs-extra";
-import path from "path";
-import { exit } from "process";
-import { execSync } from "child_process";
-import { createRequire } from "module";
-import { getOctokit, context } from "@actions/github";
-
-// to `meta` tag
-const META = process.argv.includes("--meta");
-// to `alpha` tag
-const ALPHA = process.argv.includes("--alpha");
-
-const require = createRequire(import.meta.url);
-
-async function resolve() {
- if (!process.env.GITHUB_TOKEN) {
- throw new Error("GITHUB_TOKEN is required");
- }
- if (!process.env.GITHUB_REPOSITORY) {
- throw new Error("GITHUB_REPOSITORY is required");
- }
- if (!process.env.TAURI_PRIVATE_KEY) {
- throw new Error("TAURI_PRIVATE_KEY is required");
- }
- if (!process.env.TAURI_KEY_PASSWORD) {
- throw new Error("TAURI_KEY_PASSWORD is required");
- }
-
- const { version } = require("../package.json");
-
- const tag = META ? "meta" : ALPHA ? "alpha" : `v${version}`;
- const buildCmd = META ? `yarn build -f default-meta` : `yarn build`;
-
- console.log(`[INFO]: Upload to tag "${tag}"`);
- console.log(`[INFO]: Building app. "${buildCmd}"`);
-
- execSync(buildCmd);
-
- const cwd = process.cwd();
- const bundlePath = path.join(cwd, "src-tauri/target/release/bundle");
- const join = (p) => path.join(bundlePath, p);
-
- const appPathList = [
- join("macos/Clash Verge.aarch64.app.tar.gz"),
- join("macos/Clash Verge.aarch64.app.tar.gz.sig"),
- ];
-
- for (const appPath of appPathList) {
- if (fs.pathExistsSync(appPath)) {
- fs.removeSync(appPath);
- }
- }
-
- fs.copyFileSync(join("macos/Clash Verge.app.tar.gz"), appPathList[0]);
- fs.copyFileSync(join("macos/Clash Verge.app.tar.gz.sig"), appPathList[1]);
-
- const options = { owner: context.repo.owner, repo: context.repo.repo };
- const github = getOctokit(process.env.GITHUB_TOKEN);
-
- const { data: release } = await github.rest.repos.getReleaseByTag({
- ...options,
- tag,
- });
-
- if (!release.id) throw new Error("failed to find the release");
-
- await uploadAssets(release.id, [
- join(`dmg/Clash Verge_${version}_aarch64.dmg`),
- ...appPathList,
- ]);
-}
-
-// From tauri-apps/tauri-action
-// https://github.com/tauri-apps/tauri-action/blob/dev/packages/action/src/upload-release-assets.ts
-async function uploadAssets(releaseId, assets) {
- const github = getOctokit(process.env.GITHUB_TOKEN);
-
- // Determine content-length for header to upload asset
- const contentLength = (filePath) => fs.statSync(filePath).size;
-
- for (const assetPath of assets) {
- const headers = {
- "content-type": "application/zip",
- "content-length": contentLength(assetPath),
- };
-
- const ext = path.extname(assetPath);
- const filename = path.basename(assetPath).replace(ext, "");
- const assetName = path.dirname(assetPath).includes(`target${path.sep}debug`)
- ? `${filename}-debug${ext}`
- : `${filename}${ext}`;
-
- console.log(`[INFO]: Uploading ${assetName}...`);
-
- try {
- await github.rest.repos.uploadReleaseAsset({
- headers,
- name: assetName,
- data: fs.readFileSync(assetPath),
- owner: context.repo.owner,
- repo: context.repo.repo,
- release_id: releaseId,
- });
- } catch (error) {
- console.log(error.message);
- }
- }
-}
-
-if (process.platform === "darwin" && process.arch === "arm64") {
- resolve();
-} else {
- console.error("invalid");
- exit(1);
-}
diff --git a/scripts/check.mjs b/scripts/check.mjs
deleted file mode 100644
index 5b7aceb..0000000
--- a/scripts/check.mjs
+++ /dev/null
@@ -1,332 +0,0 @@
-import fs from "fs-extra";
-import zlib from "zlib";
-import path from "path";
-import AdmZip from "adm-zip";
-import fetch from "node-fetch";
-import proxyAgent from "https-proxy-agent";
-import { execSync } from "child_process";
-
-const cwd = process.cwd();
-const TEMP_DIR = path.join(cwd, "node_modules/.verge");
-const FORCE = process.argv.includes("--force");
-
-const SIDECAR_HOST = execSync("rustc -vV")
- .toString()
- .match(/(?<=host: ).+(?=\s*)/g)[0];
-
-/* ======= clash ======= */
-const CLASH_STORAGE_PREFIX = "https://release.dreamacro.workers.dev/";
-const CLASH_URL_PREFIX =
- "https://github.com/Dreamacro/clash/releases/download/premium/";
-const CLASH_LATEST_DATE = "2023.08.17";
-
-const CLASH_MAP = {
- "win32-x64": "clash-windows-amd64",
- "darwin-x64": "clash-darwin-amd64",
- "darwin-arm64": "clash-darwin-arm64",
- "linux-x64": "clash-linux-amd64",
- "linux-arm64": "clash-linux-arm64",
-};
-
-/* ======= clash meta ======= */
-const META_URL_PREFIX = `https://github.com/MetaCubeX/Clash.Meta/releases/download/`;
-const META_VERSION = "v1.16.0";
-
-const META_MAP = {
- "win32-x64": "clash.meta-windows-amd64-compatible",
- "darwin-x64": "clash.meta-darwin-amd64",
- "darwin-arm64": "clash.meta-darwin-arm64",
- "linux-x64": "clash.meta-linux-amd64-compatible",
- "linux-arm64": "clash.meta-linux-arm64",
-};
-
-/**
- * check available
- */
-
-const { platform, arch } = process;
-if (!CLASH_MAP[`${platform}-${arch}`]) {
- throw new Error(`clash unsupported platform "${platform}-${arch}"`);
-}
-if (!META_MAP[`${platform}-${arch}`]) {
- throw new Error(`clash meta unsupported platform "${platform}-${arch}"`);
-}
-
-function clash() {
- const name = CLASH_MAP[`${platform}-${arch}`];
-
- const isWin = platform === "win32";
- const urlExt = isWin ? "zip" : "gz";
- const downloadURL = `${CLASH_URL_PREFIX}${name}-${CLASH_LATEST_DATE}.${urlExt}`;
- const exeFile = `${name}${isWin ? ".exe" : ""}`;
- const zipFile = `${name}.${urlExt}`;
-
- return {
- name: "clash",
- targetFile: `clash-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
- exeFile,
- zipFile,
- downloadURL,
- };
-}
-
-function clashS3() {
- const name = CLASH_MAP[`${platform}-${arch}`];
-
- const isWin = platform === "win32";
- const urlExt = isWin ? "zip" : "gz";
- const downloadURL = `${CLASH_STORAGE_PREFIX}${CLASH_LATEST_DATE}/${name}-${CLASH_LATEST_DATE}.${urlExt}`;
- const exeFile = `${name}${isWin ? ".exe" : ""}`;
- const zipFile = `${name}.${urlExt}`;
-
- return {
- name: "clash",
- targetFile: `clash-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
- exeFile,
- zipFile,
- downloadURL,
- };
-}
-
-function clashMeta() {
- const name = META_MAP[`${platform}-${arch}`];
- const isWin = platform === "win32";
- const urlExt = isWin ? "zip" : "gz";
- const downloadURL = `${META_URL_PREFIX}${META_VERSION}/${name}-${META_VERSION}.${urlExt}`;
- const exeFile = `${name}${isWin ? ".exe" : ""}`;
- const zipFile = `${name}-${META_VERSION}.${urlExt}`;
-
- return {
- name: "clash-meta",
- targetFile: `clash-meta-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
- exeFile,
- zipFile,
- downloadURL,
- };
-}
-
-/**
- * download sidecar and rename
- */
-async function resolveSidecar(binInfo) {
- const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
-
- const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
- const sidecarPath = path.join(sidecarDir, targetFile);
-
- await fs.mkdirp(sidecarDir);
- if (!FORCE && (await fs.pathExists(sidecarPath))) return;
-
- const tempDir = path.join(TEMP_DIR, name);
- const tempZip = path.join(tempDir, zipFile);
- const tempExe = path.join(tempDir, exeFile);
-
- await fs.mkdirp(tempDir);
- try {
- if (!(await fs.pathExists(tempZip))) {
- await downloadFile(downloadURL, tempZip);
- }
-
- if (zipFile.endsWith(".zip")) {
- const zip = new AdmZip(tempZip);
- zip.getEntries().forEach((entry) => {
- console.log(`[DEBUG]: "${name}" entry name`, entry.entryName);
- });
- zip.extractAllTo(tempDir, true);
- await fs.rename(tempExe, sidecarPath);
- console.log(`[INFO]: "${name}" unzip finished`);
- } else {
- // gz
- const readStream = fs.createReadStream(tempZip);
- const writeStream = fs.createWriteStream(sidecarPath);
- await new Promise((resolve, reject) => {
- const onError = (error) => {
- console.error(`[ERROR]: "${name}" gz failed:`, error.message);
- reject(error);
- };
- readStream
- .pipe(zlib.createGunzip().on("error", onError))
- .pipe(writeStream)
- .on("finish", () => {
- console.log(`[INFO]: "${name}" gunzip finished`);
- execSync(`chmod 755 ${sidecarPath}`);
- console.log(`[INFO]: "${name}" chmod binary finished`);
- resolve();
- })
- .on("error", onError);
- });
- }
- } catch (err) {
- // 需要删除文件
- await fs.remove(sidecarPath);
- throw err;
- } finally {
- // delete temp dir
- await fs.remove(tempDir);
- }
-}
-
-/**
- * prepare clash core
- * if the core version is not updated in time, use S3 storage as a backup.
- */
-async function resolveClash() {
- try {
- return await resolveSidecar(clash());
- } catch {
- console.log(`[WARN]: clash core needs to be updated`);
- return await resolveSidecar(clashS3());
- }
-}
-
-/**
- * only Windows
- * get the wintun.dll (not required)
- */
-async function resolveWintun() {
- const { platform } = process;
-
- if (platform !== "win32") return;
-
- const url = "https://www.wintun.net/builds/wintun-0.14.1.zip";
-
- const tempDir = path.join(TEMP_DIR, "wintun");
- const tempZip = path.join(tempDir, "wintun.zip");
-
- const wintunPath = path.join(tempDir, "wintun/bin/amd64/wintun.dll");
- const targetPath = path.join(cwd, "src-tauri/resources", "wintun.dll");
-
- if (!FORCE && (await fs.pathExists(targetPath))) return;
-
- await fs.mkdirp(tempDir);
-
- if (!(await fs.pathExists(tempZip))) {
- await downloadFile(url, tempZip);
- }
-
- // unzip
- const zip = new AdmZip(tempZip);
- zip.extractAllTo(tempDir, true);
-
- if (!(await fs.pathExists(wintunPath))) {
- throw new Error(`path not found "${wintunPath}"`);
- }
-
- await fs.rename(wintunPath, targetPath);
- await fs.remove(tempDir);
-
- console.log(`[INFO]: resolve wintun.dll finished`);
-}
-
-/**
- * download the file to the resources dir
- */
-async function resolveResource(binInfo) {
- const { file, downloadURL } = binInfo;
-
- const resDir = path.join(cwd, "src-tauri/resources");
- const targetPath = path.join(resDir, file);
-
- if (!FORCE && (await fs.pathExists(targetPath))) return;
-
- await fs.mkdirp(resDir);
- await downloadFile(downloadURL, targetPath);
-
- console.log(`[INFO]: ${file} finished`);
-}
-
-/**
- * download file and save to `path`
- */
-async function downloadFile(url, path) {
- const options = {};
-
- const httpProxy =
- process.env.HTTP_PROXY ||
- process.env.http_proxy ||
- process.env.HTTPS_PROXY ||
- process.env.https_proxy;
-
- if (httpProxy) {
- options.agent = proxyAgent(httpProxy);
- }
-
- const response = await fetch(url, {
- ...options,
- method: "GET",
- headers: { "Content-Type": "application/octet-stream" },
- });
- const buffer = await response.arrayBuffer();
- await fs.writeFile(path, new Uint8Array(buffer));
-
- console.log(`[INFO]: download finished "${url}"`);
-}
-
-/**
- * main
- */
-const SERVICE_URL =
- "https://github.com/zzzgydi/clash-verge-service/releases/download/latest";
-
-const resolveService = () =>
- resolveResource({
- file: "clash-verge-service.exe",
- downloadURL: `${SERVICE_URL}/clash-verge-service.exe`,
- });
-const resolveInstall = () =>
- resolveResource({
- file: "install-service.exe",
- downloadURL: `${SERVICE_URL}/install-service.exe`,
- });
-const resolveUninstall = () =>
- resolveResource({
- file: "uninstall-service.exe",
- downloadURL: `${SERVICE_URL}/uninstall-service.exe`,
- });
-const resolveMmdb = () =>
- resolveResource({
- file: "Country.mmdb",
- downloadURL: `https://github.com/Dreamacro/maxmind-geoip/releases/download/20230812/Country.mmdb`,
- });
-const resolveGeosite = () =>
- resolveResource({
- file: "geosite.dat",
- downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat`,
- });
-const resolveGeoIP = () =>
- resolveResource({
- file: "geoip.dat",
- downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`,
- });
-
-const tasks = [
- { name: "clash", func: resolveClash, retry: 5 },
- { name: "clash-meta", func: () => resolveSidecar(clashMeta()), retry: 5 },
- { name: "wintun", func: resolveWintun, retry: 5, winOnly: true },
- { name: "service", func: resolveService, retry: 5, winOnly: true },
- { name: "install", func: resolveInstall, retry: 5, winOnly: true },
- { name: "uninstall", func: resolveUninstall, retry: 5, winOnly: true },
- { name: "mmdb", func: resolveMmdb, retry: 5 },
- { name: "geosite", func: resolveGeosite, retry: 5 },
- { name: "geoip", func: resolveGeoIP, retry: 5 },
-];
-
-async function runTask() {
- const task = tasks.shift();
- if (!task) return;
- if (task.winOnly && process.platform !== "win32") return runTask();
-
- for (let i = 0; i < task.retry; i++) {
- try {
- await task.func();
- break;
- } catch (err) {
- console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message);
- if (i === task.retry - 1) throw err;
- }
- }
- return runTask();
-}
-
-runTask();
-runTask();
diff --git a/scripts/portable.mjs b/scripts/portable.mjs
deleted file mode 100644
index b523a50..0000000
--- a/scripts/portable.mjs
+++ /dev/null
@@ -1,59 +0,0 @@
-import fs from "fs-extra";
-import path from "path";
-import AdmZip from "adm-zip";
-import { createRequire } from "module";
-import { getOctokit, context } from "@actions/github";
-
-/// Script for ci
-/// 打包绿色版/便携版 (only Windows)
-async function resolvePortable() {
- if (process.platform !== "win32") return;
-
- const releaseDir = "./src-tauri/target/release";
-
- if (!(await fs.pathExists(releaseDir))) {
- throw new Error("could not found the release dir");
- }
-
- const zip = new AdmZip();
-
- zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
- zip.addLocalFile(path.join(releaseDir, "clash.exe"));
- zip.addLocalFile(path.join(releaseDir, "clash-meta.exe"));
- zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
-
- const require = createRequire(import.meta.url);
- const packageJson = require("../package.json");
- const { version } = packageJson;
-
- const zipFile = `Clash.Verge_${version}_x64_portable.zip`;
- zip.writeZip(zipFile);
-
- console.log("[INFO]: create portable zip successfully");
-
- // push release assets
- if (process.env.GITHUB_TOKEN === undefined) {
- throw new Error("GITHUB_TOKEN is required");
- }
-
- const options = { owner: context.repo.owner, repo: context.repo.repo };
- const github = getOctokit(process.env.GITHUB_TOKEN);
-
- console.log("[INFO]: upload to ", process.env.TAG_NAME || `v${version}`);
-
- const { data: release } = await github.rest.repos.getReleaseByTag({
- ...options,
- tag: process.env.TAG_NAME || `v${version}`,
- });
-
- console.log(release.name);
-
- await github.rest.repos.uploadReleaseAsset({
- ...options,
- release_id: release.id,
- name: zipFile,
- data: zip.toBuffer(),
- });
-}
-
-resolvePortable().catch(console.error);
diff --git a/scripts/publish.mjs b/scripts/publish.mjs
deleted file mode 100644
index 523ad18..0000000
--- a/scripts/publish.mjs
+++ /dev/null
@@ -1,53 +0,0 @@
-import fs from "fs-extra";
-import { createRequire } from "module";
-import { execSync } from "child_process";
-import { resolveUpdateLog } from "./updatelog.mjs";
-
-const require = createRequire(import.meta.url);
-
-// publish
-async function resolvePublish() {
- const flag = process.argv[2] ?? "patch";
- const packageJson = require("../package.json");
- const tauriJson = require("../src-tauri/tauri.conf.json");
-
- let [a, b, c] = packageJson.version.split(".").map(Number);
-
- if (flag === "major") {
- a += 1;
- b = 0;
- c = 0;
- } else if (flag === "minor") {
- b += 1;
- c = 0;
- } else if (flag === "patch") {
- c += 1;
- } else throw new Error(`invalid flag "${flag}"`);
-
- const nextVersion = `${a}.${b}.${c}`;
- packageJson.version = nextVersion;
- tauriJson.package.version = nextVersion;
-
- // 发布更新前先写更新日志
- const nextTag = `v${nextVersion}`;
- await resolveUpdateLog(nextTag);
-
- await fs.writeFile(
- "./package.json",
- JSON.stringify(packageJson, undefined, 2)
- );
- await fs.writeFile(
- "./src-tauri/tauri.conf.json",
- JSON.stringify(tauriJson, undefined, 2)
- );
-
- execSync("git add ./package.json");
- execSync("git add ./src-tauri/tauri.conf.json");
- execSync(`git commit -m "v${nextVersion}"`);
- execSync(`git tag -a v${nextVersion} -m "v${nextVersion}"`);
- execSync(`git push`);
- execSync(`git push origin v${nextVersion}`);
- console.log(`Publish Successfully...`);
-}
-
-resolvePublish();
diff --git a/scripts/updatelog.mjs b/scripts/updatelog.mjs
deleted file mode 100644
index fae7f62..0000000
--- a/scripts/updatelog.mjs
+++ /dev/null
@@ -1,44 +0,0 @@
-import fs from "fs-extra";
-import path from "path";
-
-const UPDATE_LOG = "UPDATELOG.md";
-
-// parse the UPDATELOG.md
-export async function resolveUpdateLog(tag) {
- const cwd = process.cwd();
-
- const reTitle = /^## v[\d\.]+/;
- const reEnd = /^---/;
-
- const file = path.join(cwd, UPDATE_LOG);
-
- if (!(await fs.pathExists(file))) {
- throw new Error("could not found UPDATELOG.md");
- }
-
- const data = await fs.readFile(file).then((d) => d.toString("utf8"));
-
- const map = {};
- let p = "";
-
- data.split("\n").forEach((line) => {
- if (reTitle.test(line)) {
- p = line.slice(3).trim();
- if (!map[p]) {
- map[p] = [];
- } else {
- throw new Error(`Tag ${p} dup`);
- }
- } else if (reEnd.test(line)) {
- p = "";
- } else if (p) {
- map[p].push(line);
- }
- });
-
- if (!map[tag]) {
- throw new Error(`could not found "${tag}" in UPDATELOG.md`);
- }
-
- return map[tag].join("\n").trim();
-}
diff --git a/scripts/updater.mjs b/scripts/updater.mjs
deleted file mode 100644
index 2a3a8ee..0000000
--- a/scripts/updater.mjs
+++ /dev/null
@@ -1,177 +0,0 @@
-import fetch from "node-fetch";
-import { getOctokit, context } from "@actions/github";
-import { resolveUpdateLog } from "./updatelog.mjs";
-
-const UPDATE_TAG_NAME = "updater";
-const UPDATE_JSON_FILE = "update.json";
-const UPDATE_JSON_PROXY = "update-proxy.json";
-
-/// generate update.json
-/// upload to update tag's release asset
-async function resolveUpdater() {
- if (process.env.GITHUB_TOKEN === undefined) {
- throw new Error("GITHUB_TOKEN is required");
- }
-
- const options = { owner: context.repo.owner, repo: context.repo.repo };
- const github = getOctokit(process.env.GITHUB_TOKEN);
-
- const { data: tags } = await github.rest.repos.listTags({
- ...options,
- per_page: 10,
- page: 1,
- });
-
- // get the latest publish tag
- const tag = tags.find((t) => t.name.startsWith("v"));
-
- console.log(tag);
- console.log();
-
- const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
- ...options,
- tag: tag.name,
- });
-
- const updateData = {
- name: tag.name,
- notes: await resolveUpdateLog(tag.name), // use updatelog.md
- pub_date: new Date().toISOString(),
- platforms: {
- win64: { signature: "", url: "" }, // compatible with older formats
- linux: { signature: "", url: "" }, // compatible with older formats
- darwin: { signature: "", url: "" }, // compatible with older formats
- "darwin-aarch64": { signature: "", url: "" },
- "darwin-intel": { signature: "", url: "" },
- "darwin-x86_64": { signature: "", url: "" },
- "linux-x86_64": { signature: "", url: "" },
- "windows-x86_64": { signature: "", url: "" },
- "windows-i686": { signature: "", url: "" }, // no supported
- },
- };
-
- const promises = latestRelease.assets.map(async (asset) => {
- const { name, browser_download_url } = asset;
-
- // win64 url
- if (name.endsWith(".msi.zip") && name.includes("en-US")) {
- updateData.platforms.win64.url = browser_download_url;
- updateData.platforms["windows-x86_64"].url = browser_download_url;
- }
- // win64 signature
- if (name.endsWith(".msi.zip.sig") && name.includes("en-US")) {
- const sig = await getSignature(browser_download_url);
- updateData.platforms.win64.signature = sig;
- updateData.platforms["windows-x86_64"].signature = sig;
- }
-
- // darwin url (intel)
- if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
- updateData.platforms.darwin.url = browser_download_url;
- updateData.platforms["darwin-intel"].url = browser_download_url;
- updateData.platforms["darwin-x86_64"].url = browser_download_url;
- }
- // darwin signature (intel)
- if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
- const sig = await getSignature(browser_download_url);
- updateData.platforms.darwin.signature = sig;
- updateData.platforms["darwin-intel"].signature = sig;
- updateData.platforms["darwin-x86_64"].signature = sig;
- }
-
- // darwin url (aarch)
- if (name.endsWith("aarch64.app.tar.gz")) {
- updateData.platforms["darwin-aarch64"].url = browser_download_url;
- }
- // darwin signature (aarch)
- if (name.endsWith("aarch64.app.tar.gz.sig")) {
- const sig = await getSignature(browser_download_url);
- updateData.platforms["darwin-aarch64"].signature = sig;
- }
-
- // linux url
- if (name.endsWith(".AppImage.tar.gz")) {
- updateData.platforms.linux.url = browser_download_url;
- updateData.platforms["linux-x86_64"].url = browser_download_url;
- }
- // linux signature
- if (name.endsWith(".AppImage.tar.gz.sig")) {
- const sig = await getSignature(browser_download_url);
- updateData.platforms.linux.signature = sig;
- updateData.platforms["linux-x86_64"].signature = sig;
- }
- });
-
- await Promise.allSettled(promises);
- console.log(updateData);
-
- // maybe should test the signature as well
- // delete the null field
- Object.entries(updateData.platforms).forEach(([key, value]) => {
- if (!value.url) {
- console.log(`[Error]: failed to parse release for "${key}"`);
- delete updateData.platforms[key];
- }
- });
-
- // 生成一个代理github的更新文件
- // 使用 https://hub.fastgit.xyz/ 做github资源的加速
- const updateDataNew = JSON.parse(JSON.stringify(updateData));
-
- Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
- if (value.url) {
- updateDataNew.platforms[key].url = "https://ghproxy.com/" + value.url;
- } else {
- console.log(`[Error]: updateDataNew.platforms.${key} is null`);
- }
- });
-
- // update the update.json
- const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
- ...options,
- tag: UPDATE_TAG_NAME,
- });
-
- // delete the old assets
- for (let asset of updateRelease.assets) {
- if (asset.name === UPDATE_JSON_FILE) {
- await github.rest.repos.deleteReleaseAsset({
- ...options,
- asset_id: asset.id,
- });
- }
-
- if (asset.name === UPDATE_JSON_PROXY) {
- await github.rest.repos
- .deleteReleaseAsset({ ...options, asset_id: asset.id })
- .catch(console.error); // do not break the pipeline
- }
- }
-
- // upload new assets
- await github.rest.repos.uploadReleaseAsset({
- ...options,
- release_id: updateRelease.id,
- name: UPDATE_JSON_FILE,
- data: JSON.stringify(updateData, null, 2),
- });
-
- await github.rest.repos.uploadReleaseAsset({
- ...options,
- release_id: updateRelease.id,
- name: UPDATE_JSON_PROXY,
- data: JSON.stringify(updateDataNew, null, 2),
- });
-}
-
-// get the signature file content
-async function getSignature(url) {
- const response = await fetch(url, {
- method: "GET",
- headers: { "Content-Type": "application/octet-stream" },
- });
-
- return response.text();
-}
-
-resolveUpdater().catch(console.error);
diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore
deleted file mode 100644
index 7b128ff..0000000
--- a/src-tauri/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Generated by Cargo
-# will have compiled files and executables
-/target/
-WixTools
-resources
-sidecar
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
deleted file mode 100644
index 9b1c0ec..0000000
--- a/src-tauri/Cargo.lock
+++ /dev/null
@@ -1,5658 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "ahash"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom 0.2.9",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "0.6.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "0.7.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "alloc-no-stdlib"
-version = "2.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
-
-[[package]]
-name = "alloc-stdlib"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
-dependencies = [
- "alloc-no-stdlib",
-]
-
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.71"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
-
-[[package]]
-name = "arc-swap"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
-
-[[package]]
-name = "async-channel"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
-dependencies = [
- "concurrent-queue",
- "event-listener",
- "futures-core",
-]
-
-[[package]]
-name = "async-executor"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb"
-dependencies = [
- "async-lock",
- "async-task",
- "concurrent-queue",
- "fastrand",
- "futures-lite",
- "slab",
-]
-
-[[package]]
-name = "async-fs"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
-dependencies = [
- "async-lock",
- "autocfg",
- "blocking",
- "futures-lite",
-]
-
-[[package]]
-name = "async-io"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
-dependencies = [
- "async-lock",
- "autocfg",
- "cfg-if",
- "concurrent-queue",
- "futures-lite",
- "log 0.4.17",
- "parking",
- "polling",
- "rustix",
- "slab",
- "socket2",
- "waker-fn",
-]
-
-[[package]]
-name = "async-lock"
-version = "2.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7"
-dependencies = [
- "event-listener",
-]
-
-[[package]]
-name = "async-net"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f"
-dependencies = [
- "async-io",
- "autocfg",
- "blocking",
- "futures-lite",
-]
-
-[[package]]
-name = "async-process"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
-dependencies = [
- "async-io",
- "async-lock",
- "autocfg",
- "blocking",
- "cfg-if",
- "event-listener",
- "futures-lite",
- "rustix",
- "signal-hook 0.3.15",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "async-task"
-version = "4.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
-
-[[package]]
-name = "async-trait"
-version = "0.1.68"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "atk"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd"
-dependencies = [
- "atk-sys",
- "bitflags",
- "glib",
- "libc",
-]
-
-[[package]]
-name = "atk-sys"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "atomic-waker"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
-
-[[package]]
-name = "attohttpc"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7"
-dependencies = [
- "flate2",
- "http",
- "log 0.4.17",
- "native-tls",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "url",
-]
-
-[[package]]
-name = "auto-launch"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471"
-dependencies = [
- "dirs 4.0.0",
- "thiserror",
- "winreg 0.10.1",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "base64"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
-
-[[package]]
-name = "base64"
-version = "0.21.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "block"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
-
-[[package]]
-name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "block-buffer"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "blocking"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65"
-dependencies = [
- "async-channel",
- "async-lock",
- "async-task",
- "atomic-waker",
- "fastrand",
- "futures-lite",
- "log 0.4.17",
-]
-
-[[package]]
-name = "brotli"
-version = "3.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
-dependencies = [
- "alloc-no-stdlib",
- "alloc-stdlib",
- "brotli-decompressor",
-]
-
-[[package]]
-name = "brotli-decompressor"
-version = "2.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744"
-dependencies = [
- "alloc-no-stdlib",
- "alloc-stdlib",
-]
-
-[[package]]
-name = "bstr"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5"
-dependencies = [
- "memchr",
- "serde",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
-
-[[package]]
-name = "bytemuck"
-version = "1.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
-
-[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
-name = "bytes"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "cairo-rs"
-version = "0.15.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc"
-dependencies = [
- "bitflags",
- "cairo-sys-rs",
- "glib",
- "libc",
- "thiserror",
-]
-
-[[package]]
-name = "cairo-sys-rs"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8"
-dependencies = [
- "glib-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "cargo_toml"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497049e9477329f8f6a559972ee42e117487d01d1e8c2cc9f836ea6fa23a9e1a"
-dependencies = [
- "serde",
- "toml 0.5.11",
-]
-
-[[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
-name = "cesu8"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
-
-[[package]]
-name = "cfb"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f"
-dependencies = [
- "byteorder",
- "fnv",
- "uuid",
-]
-
-[[package]]
-name = "cfg-expr"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "cfg-expr"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9"
-dependencies = [
- "smallvec",
- "target-lexicon",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "chrono"
-version = "0.4.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
-dependencies = [
- "iana-time-zone",
- "js-sys",
- "num-integer",
- "num-traits",
- "serde",
- "time 0.1.45",
- "wasm-bindgen",
- "winapi",
-]
-
-[[package]]
-name = "clash-verge"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "auto-launch",
- "chrono",
- "ctrlc",
- "deelevate",
- "delay_timer",
- "dirs 5.0.1",
- "dunce",
- "log 0.4.17",
- "log4rs",
- "nanoid",
- "once_cell",
- "open 4.1.0",
- "parking_lot",
- "port_scanner",
- "reqwest",
- "rquickjs",
- "runas",
- "serde",
- "serde_json",
- "serde_yaml 0.9.21",
- "sysinfo",
- "sysproxy",
- "tauri",
- "tauri-build",
- "tokio",
- "warp",
- "which",
- "window-shadows",
- "window-vibrancy",
- "windows-sys 0.48.0",
- "winreg 0.50.0",
- "wry",
-]
-
-[[package]]
-name = "cocoa"
-version = "0.24.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
-dependencies = [
- "bitflags",
- "block",
- "cocoa-foundation",
- "core-foundation",
- "core-graphics",
- "foreign-types",
- "libc",
- "objc",
-]
-
-[[package]]
-name = "cocoa-foundation"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6"
-dependencies = [
- "bitflags",
- "block",
- "core-foundation",
- "core-graphics-types",
- "foreign-types",
- "libc",
- "objc",
-]
-
-[[package]]
-name = "color_quant"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
-
-[[package]]
-name = "combine"
-version = "4.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
-dependencies = [
- "bytes",
- "memchr",
-]
-
-[[package]]
-name = "concat-idents"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fe0e1d9f7de897d18e590a7496b5facbe87813f746cf4b8db596ba77e07e832"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "concurrent-queue"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "convert_case"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
-
-[[package]]
-name = "core-foundation"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
-
-[[package]]
-name = "core-graphics"
-version = "0.22.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
-dependencies = [
- "bitflags",
- "core-foundation",
- "core-graphics-types",
- "foreign-types",
- "libc",
-]
-
-[[package]]
-name = "core-graphics-types"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
-dependencies = [
- "bitflags",
- "core-foundation",
- "foreign-types",
- "libc",
-]
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "crc32fast"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "cron_clock"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a8699d8ed16e3db689f8ae04d8dc3c6666a4ba7e724e5a157884b7cc385d16b"
-dependencies = [
- "chrono",
- "nom 7.1.3",
- "once_cell",
-]
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-deque"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
-dependencies = [
- "cfg-if",
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
-dependencies = [
- "autocfg",
- "cfg-if",
- "crossbeam-utils",
- "memoffset 0.8.0",
- "scopeguard",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "crypto-common"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-dependencies = [
- "generic-array",
- "typenum",
-]
-
-[[package]]
-name = "cssparser"
-version = "0.27.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
-dependencies = [
- "cssparser-macros",
- "dtoa-short",
- "itoa 0.4.8",
- "matches",
- "phf 0.8.0",
- "proc-macro2",
- "quote",
- "smallvec",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "cssparser-macros"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "ctor"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "ctrlc"
-version = "3.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7394a21d012ce5c850497fb774b167d81b99f060025fbf06ee92b9848bd97eb2"
-dependencies = [
- "nix 0.26.2",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "cty"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
-
-[[package]]
-name = "darling"
-version = "0.20.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
-dependencies = [
- "darling_core",
- "darling_macro",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.20.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.20.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
-dependencies = [
- "darling_core",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "dashmap"
-version = "4.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
-dependencies = [
- "cfg-if",
- "num_cpus",
-]
-
-[[package]]
-name = "deelevate"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c7397f8c48906dd9b5afc75001368c979418e5dff5575998a831eb2319b424e"
-dependencies = [
- "lazy_static 1.4.0",
- "pathsearch",
- "rand 0.8.5",
- "shared_library",
- "termwiz",
- "winapi",
-]
-
-[[package]]
-name = "delay_timer"
-version = "0.11.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46e3040b73d9397711697558109c983a2dc6fc63e98785ffbefd3ece57b46b67"
-dependencies = [
- "anyhow",
- "async-trait",
- "autocfg",
- "concat-idents",
- "cron_clock",
- "dashmap",
- "event-listener",
- "futures",
- "log 0.4.17",
- "lru",
- "once_cell",
- "rs-snowflake",
- "rustc_version 0.2.3",
- "smol",
- "thiserror",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "derivative"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "derive_more"
-version = "0.99.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
-dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "rustc_version 0.4.0",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "destructure_traitobject"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
-
-[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "digest"
-version = "0.10.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-dependencies = [
- "block-buffer 0.10.4",
- "crypto-common",
-]
-
-[[package]]
-name = "dirs"
-version = "4.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
-dependencies = [
- "dirs-sys 0.3.7",
-]
-
-[[package]]
-name = "dirs"
-version = "5.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
-dependencies = [
- "dirs-sys 0.4.1",
-]
-
-[[package]]
-name = "dirs-next"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
-dependencies = [
- "cfg-if",
- "dirs-sys-next",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
-dependencies = [
- "libc",
- "option-ext",
- "redox_users",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "dirs-sys-next"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "dispatch"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
-
-[[package]]
-name = "dtoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
-
-[[package]]
-name = "dtoa-short"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6"
-dependencies = [
- "dtoa",
-]
-
-[[package]]
-name = "dunce"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
-
-[[package]]
-name = "either"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
-
-[[package]]
-name = "embed_plist"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
-
-[[package]]
-name = "encoding_rs"
-version = "0.8.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "errno"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "event-listener"
-version = "2.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
-
-[[package]]
-name = "fastrand"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
-dependencies = [
- "instant",
-]
-
-[[package]]
-name = "fdeflate"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10"
-dependencies = [
- "simd-adler32",
-]
-
-[[package]]
-name = "field-offset"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535"
-dependencies = [
- "memoffset 0.8.0",
- "rustc_version 0.4.0",
-]
-
-[[package]]
-name = "filedescriptor"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e"
-dependencies = [
- "libc",
- "thiserror",
- "winapi",
-]
-
-[[package]]
-name = "filetime"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall 0.2.16",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "flate2"
-version = "1.0.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
-dependencies = [
- "crc32fast",
- "miniz_oxide",
-]
-
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "foreign-types"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-dependencies = [
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-
-[[package]]
-name = "form_urlencoded"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
-name = "futf"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
-dependencies = [
- "mac",
- "new_debug_unreachable",
-]
-
-[[package]]
-name = "futures"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-io",
- "futures-sink",
- "futures-task",
- "futures-util",
-]
-
-[[package]]
-name = "futures-channel"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
-dependencies = [
- "futures-core",
- "futures-sink",
-]
-
-[[package]]
-name = "futures-core"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
-
-[[package]]
-name = "futures-executor"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
-dependencies = [
- "futures-core",
- "futures-task",
- "futures-util",
-]
-
-[[package]]
-name = "futures-io"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
-
-[[package]]
-name = "futures-lite"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
-dependencies = [
- "fastrand",
- "futures-core",
- "futures-io",
- "memchr",
- "parking",
- "pin-project-lite",
- "waker-fn",
-]
-
-[[package]]
-name = "futures-macro"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "futures-sink"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
-
-[[package]]
-name = "futures-task"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
-
-[[package]]
-name = "futures-util"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-io",
- "futures-macro",
- "futures-sink",
- "futures-task",
- "memchr",
- "pin-project-lite",
- "pin-utils",
- "slab",
-]
-
-[[package]]
-name = "fxhash"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
-dependencies = [
- "byteorder",
-]
-
-[[package]]
-name = "gdk"
-version = "0.15.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "gdk-pixbuf",
- "gdk-sys",
- "gio",
- "glib",
- "libc",
- "pango",
-]
-
-[[package]]
-name = "gdk-pixbuf"
-version = "0.15.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a"
-dependencies = [
- "bitflags",
- "gdk-pixbuf-sys",
- "gio",
- "glib",
- "libc",
-]
-
-[[package]]
-name = "gdk-pixbuf-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7"
-dependencies = [
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gdk-sys"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88"
-dependencies = [
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pango-sys",
- "pkg-config",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gdkwayland-sys"
-version = "0.15.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2"
-dependencies = [
- "gdk-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pkg-config",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gdkx11-sys"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178"
-dependencies = [
- "gdk-sys",
- "glib-sys",
- "libc",
- "system-deps 6.1.0",
- "x11",
-]
-
-[[package]]
-name = "generator"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a"
-dependencies = [
- "cc",
- "libc",
- "log 0.4.17",
- "rustversion",
- "windows 0.48.0",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "gio"
-version = "0.15.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b"
-dependencies = [
- "bitflags",
- "futures-channel",
- "futures-core",
- "futures-io",
- "gio-sys",
- "glib",
- "libc",
- "once_cell",
- "thiserror",
-]
-
-[[package]]
-name = "gio-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
- "winapi",
-]
-
-[[package]]
-name = "glib"
-version = "0.15.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d"
-dependencies = [
- "bitflags",
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-task",
- "glib-macros",
- "glib-sys",
- "gobject-sys",
- "libc",
- "once_cell",
- "smallvec",
- "thiserror",
-]
-
-[[package]]
-name = "glib-macros"
-version = "0.15.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a"
-dependencies = [
- "anyhow",
- "heck 0.4.1",
- "proc-macro-crate",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "glib-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4"
-dependencies = [
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "glob"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
-
-[[package]]
-name = "globset"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
-dependencies = [
- "aho-corasick 0.7.20",
- "bstr",
- "fnv",
- "log 0.4.17",
- "regex 1.8.3",
-]
-
-[[package]]
-name = "gobject-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a"
-dependencies = [
- "glib-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gtk"
-version = "0.15.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0"
-dependencies = [
- "atk",
- "bitflags",
- "cairo-rs",
- "field-offset",
- "futures-channel",
- "gdk",
- "gdk-pixbuf",
- "gio",
- "glib",
- "gtk-sys",
- "gtk3-macros",
- "libc",
- "once_cell",
- "pango",
- "pkg-config",
-]
-
-[[package]]
-name = "gtk-sys"
-version = "0.15.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84"
-dependencies = [
- "atk-sys",
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gdk-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pango-sys",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "gtk3-macros"
-version = "0.15.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d"
-dependencies = [
- "anyhow",
- "proc-macro-crate",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "h2"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "handlebars"
-version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc"
-dependencies = [
- "lazy_static 0.2.11",
- "log 0.3.9",
- "pest 0.3.3",
- "quick-error",
- "regex 0.2.11",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-dependencies = [
- "ahash",
-]
-
-[[package]]
-name = "headers"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
-dependencies = [
- "base64 0.13.1",
- "bitflags",
- "bytes",
- "headers-core",
- "http",
- "httpdate",
- "mime",
- "sha1",
-]
-
-[[package]]
-name = "headers-core"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
-dependencies = [
- "http",
-]
-
-[[package]]
-name = "heck"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
-[[package]]
-name = "hermit-abi"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "html5ever"
-version = "0.25.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148"
-dependencies = [
- "log 0.4.17",
- "mac",
- "markup5ever",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "http"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
-dependencies = [
- "bytes",
- "fnv",
- "itoa 1.0.6",
-]
-
-[[package]]
-name = "http-body"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
-dependencies = [
- "bytes",
- "http",
- "pin-project-lite",
-]
-
-[[package]]
-name = "http-range"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
-
-[[package]]
-name = "httparse"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
-
-[[package]]
-name = "httpdate"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
-[[package]]
-name = "hyper"
-version = "0.14.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa 1.0.6",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper-rustls"
-version = "0.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7"
-dependencies = [
- "http",
- "hyper",
- "rustls",
- "tokio",
- "tokio-rustls",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
-dependencies = [
- "bytes",
- "hyper",
- "native-tls",
- "tokio",
- "tokio-native-tls",
-]
-
-[[package]]
-name = "iana-time-zone"
-version = "0.1.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "wasm-bindgen",
- "windows 0.48.0",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "ico"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae"
-dependencies = [
- "byteorder",
- "png",
-]
-
-[[package]]
-name = "ident_case"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
-
-[[package]]
-name = "idna"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "ignore"
-version = "0.4.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
-dependencies = [
- "crossbeam-utils",
- "globset",
- "lazy_static 1.4.0",
- "log 0.4.17",
- "memchr",
- "regex 1.8.3",
- "same-file",
- "thread_local 1.1.7",
- "walkdir",
- "winapi-util",
-]
-
-[[package]]
-name = "image"
-version = "0.24.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a"
-dependencies = [
- "bytemuck",
- "byteorder",
- "color_quant",
- "num-rational",
- "num-traits",
-]
-
-[[package]]
-name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
-dependencies = [
- "autocfg",
- "hashbrown",
- "serde",
-]
-
-[[package]]
-name = "infer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f178e61cdbfe084aa75a2f4f7a25a5bb09701a47ae1753608f194b15783c937a"
-dependencies = [
- "cfb",
-]
-
-[[package]]
-name = "infer"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a898e4b7951673fce96614ce5751d13c40fc5674bc2d759288e46c3ab62598b3"
-dependencies = [
- "cfb",
-]
-
-[[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "interfaces"
-version = "0.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec8f50a973916cac3da5057c986db05cd3346f38c78e9bc24f64cc9f6a3978f"
-dependencies = [
- "bitflags",
- "cc",
- "handlebars",
- "lazy_static 1.4.0",
- "libc",
- "nix 0.23.2",
- "serde",
- "serde_derive",
-]
-
-[[package]]
-name = "io-lifetimes"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
-dependencies = [
- "hermit-abi 0.3.1",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "ipnet"
-version = "2.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
-
-[[package]]
-name = "is-docker"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
-dependencies = [
- "once_cell",
-]
-
-[[package]]
-name = "is-wsl"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
-dependencies = [
- "is-docker",
- "once_cell",
-]
-
-[[package]]
-name = "itoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
-
-[[package]]
-name = "itoa"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
-
-[[package]]
-name = "javascriptcore-rs"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c"
-dependencies = [
- "bitflags",
- "glib",
- "javascriptcore-rs-sys",
-]
-
-[[package]]
-name = "javascriptcore-rs-sys"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 5.0.0",
-]
-
-[[package]]
-name = "jni"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
-dependencies = [
- "cesu8",
- "combine",
- "jni-sys",
- "log 0.4.17",
- "thiserror",
- "walkdir",
-]
-
-[[package]]
-name = "jni-sys"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
-
-[[package]]
-name = "js-sys"
-version = "0.3.63"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "json-patch"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3fa5a61630976fc4c353c70297f2e93f1930e3ccee574d59d618ccbd5154ce"
-dependencies = [
- "serde",
- "serde_json",
- "treediff 3.0.2",
-]
-
-[[package]]
-name = "json-patch"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f54898088ccb91df1b492cc80029a6fdf1c48ca0db7c6822a8babad69c94658"
-dependencies = [
- "serde",
- "serde_json",
- "thiserror",
- "treediff 4.0.2",
-]
-
-[[package]]
-name = "kuchiki"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358"
-dependencies = [
- "cssparser",
- "html5ever",
- "matches",
- "selectors",
-]
-
-[[package]]
-name = "lazy_static"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "libappindicator"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8"
-dependencies = [
- "glib",
- "gtk",
- "gtk-sys",
- "libappindicator-sys",
- "log 0.4.17",
-]
-
-[[package]]
-name = "libappindicator-sys"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa"
-dependencies = [
- "gtk-sys",
- "libloading",
- "once_cell",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.144"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
-
-[[package]]
-name = "libloading"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
-dependencies = [
- "cfg-if",
- "winapi",
-]
-
-[[package]]
-name = "line-wrap"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
-dependencies = [
- "safemem",
-]
-
-[[package]]
-name = "linked-hash-map"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
-
-[[package]]
-name = "lock_api"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
-[[package]]
-name = "log"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
-dependencies = [
- "log 0.4.17",
-]
-
-[[package]]
-name = "log"
-version = "0.4.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
- "serde",
-]
-
-[[package]]
-name = "log-mdc"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
-
-[[package]]
-name = "log4rs"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd"
-dependencies = [
- "anyhow",
- "arc-swap",
- "chrono",
- "derivative",
- "fnv",
- "humantime",
- "libc",
- "log 0.4.17",
- "log-mdc",
- "parking_lot",
- "serde",
- "serde-value",
- "serde_json",
- "serde_yaml 0.8.26",
- "thiserror",
- "thread-id",
- "typemap-ors",
- "winapi",
-]
-
-[[package]]
-name = "loom"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
-dependencies = [
- "cfg-if",
- "generator",
- "scoped-tls",
- "serde",
- "serde_json",
- "tracing",
- "tracing-subscriber",
-]
-
-[[package]]
-name = "lru"
-version = "0.7.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a"
-dependencies = [
- "hashbrown",
-]
-
-[[package]]
-name = "mac"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
-
-[[package]]
-name = "malloc_buf"
-version = "0.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "markup5ever"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
-dependencies = [
- "log 0.4.17",
- "phf 0.8.0",
- "phf_codegen 0.8.0",
- "string_cache",
- "string_cache_codegen",
- "tendril",
-]
-
-[[package]]
-name = "matchers"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
-dependencies = [
- "regex-automata",
-]
-
-[[package]]
-name = "matches"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
-
-[[package]]
-name = "memchr"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-
-[[package]]
-name = "memmem"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15"
-
-[[package]]
-name = "memoffset"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "memoffset"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
-[[package]]
-name = "mime_guess"
-version = "2.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
-dependencies = [
- "mime",
- "unicase",
-]
-
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
-name = "minisign-verify"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
-dependencies = [
- "adler",
- "simd-adler32",
-]
-
-[[package]]
-name = "mio"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
-dependencies = [
- "libc",
- "log 0.4.17",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "multer"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2"
-dependencies = [
- "bytes",
- "encoding_rs",
- "futures-util",
- "http",
- "httparse",
- "log 0.4.17",
- "memchr",
- "mime",
- "spin 0.9.8",
- "version_check",
-]
-
-[[package]]
-name = "nanoid"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8"
-dependencies = [
- "rand 0.8.5",
-]
-
-[[package]]
-name = "native-tls"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
-dependencies = [
- "lazy_static 1.4.0",
- "libc",
- "log 0.4.17",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
-[[package]]
-name = "ndk"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
-dependencies = [
- "bitflags",
- "jni-sys",
- "ndk-sys",
- "num_enum",
- "thiserror",
-]
-
-[[package]]
-name = "ndk-context"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
-
-[[package]]
-name = "ndk-sys"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97"
-dependencies = [
- "jni-sys",
-]
-
-[[package]]
-name = "new_debug_unreachable"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
-
-[[package]]
-name = "nix"
-version = "0.23.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
-dependencies = [
- "bitflags",
- "cc",
- "cfg-if",
- "libc",
- "memoffset 0.6.5",
-]
-
-[[package]]
-name = "nix"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
-dependencies = [
- "bitflags",
- "cfg-if",
- "libc",
- "static_assertions",
-]
-
-[[package]]
-name = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-
-[[package]]
-name = "nom"
-version = "5.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b"
-dependencies = [
- "memchr",
- "version_check",
-]
-
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
-name = "ntapi"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "nu-ansi-term"
-version = "0.46.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
-dependencies = [
- "overload",
- "winapi",
-]
-
-[[package]]
-name = "num-derive"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
-dependencies = [
- "autocfg",
- "num-traits",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "num_cpus"
-version = "1.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
-dependencies = [
- "hermit-abi 0.2.6",
- "libc",
-]
-
-[[package]]
-name = "num_enum"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
-dependencies = [
- "num_enum_derive",
-]
-
-[[package]]
-name = "num_enum_derive"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
-dependencies = [
- "proc-macro-crate",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "num_threads"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "objc"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
-dependencies = [
- "malloc_buf",
- "objc_exception",
-]
-
-[[package]]
-name = "objc-foundation"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
-dependencies = [
- "block",
- "objc",
- "objc_id",
-]
-
-[[package]]
-name = "objc_exception"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "objc_id"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
-dependencies = [
- "objc",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
-
-[[package]]
-name = "opaque-debug"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
-
-[[package]]
-name = "open"
-version = "3.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8"
-dependencies = [
- "pathdiff",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "open"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d16814a067484415fda653868c9be0ac5f2abd2ef5d951082a5f2fe1b3662944"
-dependencies = [
- "is-wsl",
- "pathdiff",
-]
-
-[[package]]
-name = "openssl"
-version = "0.10.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56"
-dependencies = [
- "bitflags",
- "cfg-if",
- "foreign-types",
- "libc",
- "once_cell",
- "openssl-macros",
- "openssl-sys",
-]
-
-[[package]]
-name = "openssl-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "openssl-probe"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-
-[[package]]
-name = "openssl-src"
-version = "111.25.3+1.1.1t"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "openssl-sys"
-version = "0.9.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e"
-dependencies = [
- "cc",
- "libc",
- "openssl-src",
- "pkg-config",
- "vcpkg",
-]
-
-[[package]]
-name = "option-ext"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
-
-[[package]]
-name = "ordered-float"
-version = "2.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "os_pipe"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177"
-dependencies = [
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "overload"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
-
-[[package]]
-name = "pango"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f"
-dependencies = [
- "bitflags",
- "glib",
- "libc",
- "once_cell",
- "pango-sys",
-]
-
-[[package]]
-name = "pango-sys"
-version = "0.15.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "parking"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
-
-[[package]]
-name = "parking_lot"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
-dependencies = [
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.9.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall 0.2.16",
- "smallvec",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "pathdiff"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
-
-[[package]]
-name = "pathsearch"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da983bc5e582ab17179c190b4b66c7d76c5943a69c6d34df2a2b6bf8a2977b05"
-dependencies = [
- "anyhow",
- "libc",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
-
-[[package]]
-name = "pest"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
-
-[[package]]
-name = "pest"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70"
-dependencies = [
- "thiserror",
- "ucd-trie",
-]
-
-[[package]]
-name = "phf"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
-dependencies = [
- "phf_macros 0.8.0",
- "phf_shared 0.8.0",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "phf"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
-dependencies = [
- "phf_macros 0.10.0",
- "phf_shared 0.10.0",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "phf"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
-dependencies = [
- "phf_shared 0.11.1",
-]
-
-[[package]]
-name = "phf_codegen"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
-dependencies = [
- "phf_generator 0.8.0",
- "phf_shared 0.8.0",
-]
-
-[[package]]
-name = "phf_codegen"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
-dependencies = [
- "phf_generator 0.11.1",
- "phf_shared 0.11.1",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
-dependencies = [
- "phf_shared 0.8.0",
- "rand 0.7.3",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
-dependencies = [
- "phf_shared 0.10.0",
- "rand 0.8.5",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
-dependencies = [
- "phf_shared 0.11.1",
- "rand 0.8.5",
-]
-
-[[package]]
-name = "phf_macros"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
-dependencies = [
- "phf_generator 0.8.0",
- "phf_shared 0.8.0",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "phf_macros"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
-dependencies = [
- "phf_generator 0.10.0",
- "phf_shared 0.10.0",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
-dependencies = [
- "siphasher",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
-dependencies = [
- "siphasher",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
-dependencies = [
- "siphasher",
-]
-
-[[package]]
-name = "pin-project"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
-
-[[package]]
-name = "pin-utils"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
-
-[[package]]
-name = "plist"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
-dependencies = [
- "base64 0.21.2",
- "indexmap",
- "line-wrap",
- "quick-xml",
- "serde",
- "time 0.3.15",
-]
-
-[[package]]
-name = "png"
-version = "0.17.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa"
-dependencies = [
- "bitflags",
- "crc32fast",
- "fdeflate",
- "flate2",
- "miniz_oxide",
-]
-
-[[package]]
-name = "polling"
-version = "2.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
-dependencies = [
- "autocfg",
- "bitflags",
- "cfg-if",
- "concurrent-queue",
- "libc",
- "log 0.4.17",
- "pin-project-lite",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "port_scanner"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "325a6d2ac5dee293c3b2612d4993b98aec1dff096b0a2dae70ed7d95784a05da"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "precomputed-hash"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
-
-[[package]]
-name = "proc-macro-crate"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
-dependencies = [
- "once_cell",
- "toml_edit",
-]
-
-[[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.59"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quick-error"
-version = "1.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-
-[[package]]
-name = "quick-xml"
-version = "0.28.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
- "rand_pcg",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom 0.2.9",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-dependencies = [
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "rand_pcg"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
-dependencies = [
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "raw-window-handle"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a"
-dependencies = [
- "cty",
-]
-
-[[package]]
-name = "rayon"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
-dependencies = [
- "either",
- "rayon-core",
-]
-
-[[package]]
-name = "rayon-core"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
-dependencies = [
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-utils",
- "num_cpus",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "redox_users"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
-dependencies = [
- "getrandom 0.2.9",
- "redox_syscall 0.2.16",
- "thiserror",
-]
-
-[[package]]
-name = "regex"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
-dependencies = [
- "aho-corasick 0.6.10",
- "memchr",
- "regex-syntax 0.5.6",
- "thread_local 0.3.6",
- "utf8-ranges",
-]
-
-[[package]]
-name = "regex"
-version = "1.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
-dependencies = [
- "aho-corasick 1.0.1",
- "memchr",
- "regex-syntax 0.7.2",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-dependencies = [
- "regex-syntax 0.6.29",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
-dependencies = [
- "ucd-util",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
-
-[[package]]
-name = "regex-syntax"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
-
-[[package]]
-name = "reqwest"
-version = "0.11.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
-dependencies = [
- "base64 0.21.2",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-rustls",
- "hyper-tls",
- "ipnet",
- "js-sys",
- "log 0.4.17",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "tokio",
- "tokio-native-tls",
- "tokio-rustls",
- "tokio-util",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-streams",
- "web-sys",
- "webpki-roots",
- "winreg 0.10.1",
-]
-
-[[package]]
-name = "rfd"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
-dependencies = [
- "block",
- "dispatch",
- "glib-sys",
- "gobject-sys",
- "gtk-sys",
- "js-sys",
- "lazy_static 1.4.0",
- "log 0.4.17",
- "objc",
- "objc-foundation",
- "objc_id",
- "raw-window-handle",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "windows 0.37.0",
-]
-
-[[package]]
-name = "ring"
-version = "0.16.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
-dependencies = [
- "cc",
- "libc",
- "once_cell",
- "spin 0.5.2",
- "untrusted",
- "web-sys",
- "winapi",
-]
-
-[[package]]
-name = "rquickjs"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc022cc82b5de6f38b2f4ddb8ed9c49cdbd7ce112e650b181598e102157257de"
-dependencies = [
- "rquickjs-core",
-]
-
-[[package]]
-name = "rquickjs-core"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74fa1ecc1c84b31da87e5b26ce2b5218d36ffeb5c322141c78b79fa86a6ee3b9"
-dependencies = [
- "rquickjs-sys",
-]
-
-[[package]]
-name = "rquickjs-sys"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24311952af42d8252e399cf48e7d470cb413b1a11a1a5b7fab648cd2edec76c5"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "rs-snowflake"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e60ef3b82994702bbe4e134d98aadca4b49ed04440148985678d415c68127666"
-
-[[package]]
-name = "runas"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49535b7c73aec5596ae2c44a6d8a7a8f8592e5744564c327fd4846750413d921"
-dependencies = [
- "libc",
- "security-framework-sys",
- "which",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver 0.9.0",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
-dependencies = [
- "semver 1.0.17",
-]
-
-[[package]]
-name = "rustix"
-version = "0.37.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
-dependencies = [
- "bitflags",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rustls"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e"
-dependencies = [
- "log 0.4.17",
- "ring",
- "rustls-webpki",
- "sct",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
-dependencies = [
- "base64 0.21.2",
-]
-
-[[package]]
-name = "rustls-webpki"
-version = "0.100.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
-
-[[package]]
-name = "ryu"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
-
-[[package]]
-name = "safemem"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
-
-[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "schannel"
-version = "0.1.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
-dependencies = [
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "scoped-tls"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
-
-[[package]]
-name = "scopeguard"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-
-[[package]]
-name = "sct"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "security-framework"
-version = "2.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
-dependencies = [
- "bitflags",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "selectors"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
-dependencies = [
- "bitflags",
- "cssparser",
- "derive_more",
- "fxhash",
- "log 0.4.17",
- "matches",
- "phf 0.8.0",
- "phf_codegen 0.8.0",
- "precomputed-hash",
- "servo_arc",
- "smallvec",
- "thin-slice",
-]
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser 0.7.0",
-]
-
-[[package]]
-name = "semver"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
-dependencies = [
- "semver-parser 0.10.2",
-]
-
-[[package]]
-name = "semver"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
-[[package]]
-name = "semver-parser"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
-dependencies = [
- "pest 2.6.0",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.163"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde-value"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
-dependencies = [
- "ordered-float",
- "serde",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.163"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.96"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
-dependencies = [
- "itoa 1.0.6",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "serde_repr"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
-dependencies = [
- "form_urlencoded",
- "itoa 1.0.6",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "serde_with"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe"
-dependencies = [
- "base64 0.13.1",
- "chrono",
- "hex",
- "indexmap",
- "serde",
- "serde_json",
- "serde_with_macros",
- "time 0.3.15",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
-dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "serde_yaml"
-version = "0.8.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
-dependencies = [
- "indexmap",
- "ryu",
- "serde",
- "yaml-rust",
-]
-
-[[package]]
-name = "serde_yaml"
-version = "0.9.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c"
-dependencies = [
- "indexmap",
- "itoa 1.0.6",
- "ryu",
- "serde",
- "unsafe-libyaml",
-]
-
-[[package]]
-name = "serialize-to-javascript"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb"
-dependencies = [
- "serde",
- "serde_json",
- "serialize-to-javascript-impl",
-]
-
-[[package]]
-name = "serialize-to-javascript-impl"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "servo_arc"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
-dependencies = [
- "nodrop",
- "stable_deref_trait",
-]
-
-[[package]]
-name = "sha1"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest 0.10.7",
-]
-
-[[package]]
-name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
-version = "0.10.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest 0.10.7",
-]
-
-[[package]]
-name = "sharded-slab"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
-dependencies = [
- "lazy_static 1.4.0",
-]
-
-[[package]]
-name = "shared_child"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "shared_library"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
-dependencies = [
- "lazy_static 1.4.0",
- "libc",
-]
-
-[[package]]
-name = "signal-hook"
-version = "0.1.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
-
-[[package]]
-name = "signal-hook"
-version = "0.3.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
-
-[[package]]
-name = "signal-hook-registry"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "simd-adler32"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
-
-[[package]]
-name = "siphasher"
-version = "0.3.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
-
-[[package]]
-name = "slab"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
-
-[[package]]
-name = "smol"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
-dependencies = [
- "async-channel",
- "async-executor",
- "async-fs",
- "async-io",
- "async-lock",
- "async-net",
- "async-process",
- "blocking",
- "futures-lite",
-]
-
-[[package]]
-name = "socket2"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "soup2"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0"
-dependencies = [
- "bitflags",
- "gio",
- "glib",
- "libc",
- "once_cell",
- "soup2-sys",
-]
-
-[[package]]
-name = "soup2-sys"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf"
-dependencies = [
- "bitflags",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps 5.0.0",
-]
-
-[[package]]
-name = "spin"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
-
-[[package]]
-name = "spin"
-version = "0.9.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
-
-[[package]]
-name = "stable_deref_trait"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
-
-[[package]]
-name = "state"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b"
-dependencies = [
- "loom",
-]
-
-[[package]]
-name = "static_assertions"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-
-[[package]]
-name = "string_cache"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
-dependencies = [
- "new_debug_unreachable",
- "once_cell",
- "parking_lot",
- "phf_shared 0.10.0",
- "precomputed-hash",
- "serde",
-]
-
-[[package]]
-name = "string_cache_codegen"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
-dependencies = [
- "phf_generator 0.10.0",
- "phf_shared 0.10.0",
- "proc-macro2",
- "quote",
-]
-
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "sysinfo"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02f1dc6930a439cc5d154221b5387d153f8183529b07c19aca24ea31e0a167e1"
-dependencies = [
- "cfg-if",
- "core-foundation-sys",
- "libc",
- "ntapi",
- "once_cell",
- "rayon",
- "winapi",
-]
-
-[[package]]
-name = "sysproxy"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9707a79d3b95683aa5a9521e698ffd878b8fb289727c25a69157fb85d529ffff"
-dependencies = [
- "interfaces",
- "thiserror",
- "winapi",
- "winreg 0.10.1",
-]
-
-[[package]]
-name = "system-deps"
-version = "5.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e"
-dependencies = [
- "cfg-expr 0.9.1",
- "heck 0.3.3",
- "pkg-config",
- "toml 0.5.11",
- "version-compare 0.0.11",
-]
-
-[[package]]
-name = "system-deps"
-version = "6.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2"
-dependencies = [
- "cfg-expr 0.15.1",
- "heck 0.4.1",
- "pkg-config",
- "toml 0.7.4",
- "version-compare 0.1.1",
-]
-
-[[package]]
-name = "tao"
-version = "0.16.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6d198e01085564cea63e976ad1566c1ba2c2e4cc79578e35d9f05521505e31"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "cc",
- "cocoa",
- "core-foundation",
- "core-graphics",
- "crossbeam-channel",
- "dirs-next",
- "dispatch",
- "gdk",
- "gdk-pixbuf",
- "gdk-sys",
- "gdkwayland-sys",
- "gdkx11-sys",
- "gio",
- "glib",
- "glib-sys",
- "gtk",
- "image",
- "instant",
- "jni",
- "lazy_static 1.4.0",
- "libappindicator",
- "libc",
- "log 0.4.17",
- "ndk",
- "ndk-context",
- "ndk-sys",
- "objc",
- "once_cell",
- "parking_lot",
- "png",
- "raw-window-handle",
- "scopeguard",
- "serde",
- "tao-macros",
- "unicode-segmentation",
- "uuid",
- "windows 0.39.0",
- "windows-implement",
- "x11-dl",
-]
-
-[[package]]
-name = "tao-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b27a4bcc5eb524658234589bdffc7e7bfb996dbae6ce9393bfd39cb4159b445"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "tar"
-version = "0.4.38"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
-dependencies = [
- "filetime",
- "libc",
- "xattr",
-]
-
-[[package]]
-name = "target-lexicon"
-version = "0.12.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5"
-
-[[package]]
-name = "tauri"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d42ba3a2e8556722f31336a0750c10dbb6a81396a1c452977f515da83f69f842"
-dependencies = [
- "anyhow",
- "attohttpc",
- "base64 0.21.2",
- "bytes",
- "cocoa",
- "dirs-next",
- "embed_plist",
- "encoding_rs",
- "flate2",
- "futures-util",
- "glib",
- "glob",
- "gtk",
- "heck 0.4.1",
- "http",
- "ignore",
- "infer 0.9.0",
- "minisign-verify",
- "objc",
- "once_cell",
- "open 3.2.0",
- "os_pipe",
- "percent-encoding",
- "png",
- "rand 0.8.5",
- "raw-window-handle",
- "regex 1.8.3",
- "reqwest",
- "rfd",
- "semver 1.0.17",
- "serde",
- "serde_json",
- "serde_repr",
- "serialize-to-javascript",
- "shared_child",
- "state",
- "tar",
- "tauri-macros",
- "tauri-runtime",
- "tauri-runtime-wry",
- "tauri-utils",
- "tempfile",
- "thiserror",
- "time 0.3.15",
- "tokio",
- "url",
- "uuid",
- "webkit2gtk",
- "webview2-com",
- "windows 0.39.0",
- "zip",
-]
-
-[[package]]
-name = "tauri-build"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8807c85d656b2b93927c19fe5a5f1f1f348f96c2de8b90763b3c2d561511f9b4"
-dependencies = [
- "anyhow",
- "cargo_toml",
- "heck 0.4.1",
- "json-patch 0.2.7",
- "semver 1.0.17",
- "serde_json",
- "tauri-utils",
- "winres",
-]
-
-[[package]]
-name = "tauri-codegen"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5a2105f807c6f50b2fa2ce5abd62ef207bc6f14c9fcc6b8caec437f6fb13bde"
-dependencies = [
- "base64 0.21.2",
- "brotli",
- "ico",
- "json-patch 1.0.0",
- "plist",
- "png",
- "proc-macro2",
- "quote",
- "regex 1.8.3",
- "semver 1.0.17",
- "serde",
- "serde_json",
- "sha2 0.10.6",
- "tauri-utils",
- "thiserror",
- "time 0.3.15",
- "uuid",
- "walkdir",
-]
-
-[[package]]
-name = "tauri-macros"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8784cfe6f5444097e93c69107d1ac5e8f13d02850efa8d8f2a40fe79674cef46"
-dependencies = [
- "heck 0.4.1",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
- "tauri-codegen",
- "tauri-utils",
-]
-
-[[package]]
-name = "tauri-runtime"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3b80ea3fcd5fefb60739a3b577b277e8fc30434538a2f5bba82ad7d4368c422"
-dependencies = [
- "gtk",
- "http",
- "http-range",
- "rand 0.8.5",
- "raw-window-handle",
- "serde",
- "serde_json",
- "tauri-utils",
- "thiserror",
- "url",
- "uuid",
- "webview2-com",
- "windows 0.39.0",
-]
-
-[[package]]
-name = "tauri-runtime-wry"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1c396950b1ba06aee1b4ffe6c7cd305ff433ca0e30acbc5fa1a2f92a4ce70f1"
-dependencies = [
- "cocoa",
- "gtk",
- "percent-encoding",
- "rand 0.8.5",
- "raw-window-handle",
- "tauri-runtime",
- "tauri-utils",
- "uuid",
- "webkit2gtk",
- "webview2-com",
- "windows 0.39.0",
- "wry",
-]
-
-[[package]]
-name = "tauri-utils"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a6f9c2dafef5cbcf52926af57ce9561bd33bb41d7394f8bb849c0330260d864"
-dependencies = [
- "brotli",
- "ctor",
- "glob",
- "heck 0.4.1",
- "html5ever",
- "infer 0.12.0",
- "json-patch 1.0.0",
- "kuchiki",
- "memchr",
- "phf 0.10.1",
- "proc-macro2",
- "quote",
- "semver 1.0.17",
- "serde",
- "serde_json",
- "serde_with",
- "thiserror",
- "url",
- "walkdir",
- "windows 0.39.0",
-]
-
-[[package]]
-name = "tempfile"
-version = "3.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
-dependencies = [
- "cfg-if",
- "fastrand",
- "redox_syscall 0.3.5",
- "rustix",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "tendril"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
-dependencies = [
- "futf",
- "mac",
- "utf-8",
-]
-
-[[package]]
-name = "terminfo"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da31aef70da0f6352dbcb462683eb4dd2bfad01cf3fc96cf204547b9a839a585"
-dependencies = [
- "dirs 4.0.0",
- "fnv",
- "nom 5.1.3",
- "phf 0.11.1",
- "phf_codegen 0.11.1",
-]
-
-[[package]]
-name = "termios"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "termwiz"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31ef6892cc0348a9b3b8c377addba91e0f6365863d92354bf27559dca81ee8c5"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "bitflags",
- "cfg-if",
- "filedescriptor",
- "hex",
- "lazy_static 1.4.0",
- "libc",
- "log 0.4.17",
- "memmem",
- "num-derive",
- "num-traits",
- "ordered-float",
- "regex 1.8.3",
- "semver 0.11.0",
- "sha2 0.9.9",
- "signal-hook 0.1.17",
- "terminfo",
- "termios",
- "thiserror",
- "ucd-trie",
- "unicode-segmentation",
- "vtparse",
- "winapi",
-]
-
-[[package]]
-name = "thin-slice"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
-
-[[package]]
-name = "thiserror"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "thread-id"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ee93aa2b8331c0fec9091548843f2c90019571814057da3b783f9de09349d73"
-dependencies = [
- "libc",
- "redox_syscall 0.2.16",
- "winapi",
-]
-
-[[package]]
-name = "thread_local"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-dependencies = [
- "lazy_static 1.4.0",
-]
-
-[[package]]
-name = "thread_local"
-version = "1.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
-dependencies = [
- "cfg-if",
- "once_cell",
-]
-
-[[package]]
-name = "time"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
-dependencies = [
- "libc",
- "wasi 0.10.0+wasi-snapshot-preview1",
- "winapi",
-]
-
-[[package]]
-name = "time"
-version = "0.3.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c"
-dependencies = [
- "itoa 1.0.6",
- "libc",
- "num_threads",
- "serde",
-]
-
-[[package]]
-name = "tinyvec"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
-dependencies = [
- "tinyvec_macros",
-]
-
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
-[[package]]
-name = "tokio"
-version = "1.28.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
-dependencies = [
- "autocfg",
- "bytes",
- "libc",
- "mio",
- "num_cpus",
- "parking_lot",
- "pin-project-lite",
- "signal-hook-registry",
- "socket2",
- "tokio-macros",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "tokio-macros"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-rustls"
-version = "0.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5"
-dependencies = [
- "rustls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-stream"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
-dependencies = [
- "futures-core",
- "pin-project-lite",
- "tokio",
-]
-
-[[package]]
-name = "tokio-tungstenite"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
-dependencies = [
- "futures-util",
- "log 0.4.17",
- "tokio",
- "tungstenite",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "toml"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.19.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "winnow",
-]
-
-[[package]]
-name = "tower-service"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
-
-[[package]]
-name = "tracing"
-version = "0.1.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
-dependencies = [
- "cfg-if",
- "log 0.4.17",
- "pin-project-lite",
- "tracing-attributes",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-attributes"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
-dependencies = [
- "once_cell",
- "valuable",
-]
-
-[[package]]
-name = "tracing-log"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
-dependencies = [
- "lazy_static 1.4.0",
- "log 0.4.17",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-subscriber"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
-dependencies = [
- "matchers",
- "nu-ansi-term",
- "once_cell",
- "regex 1.8.3",
- "sharded-slab",
- "smallvec",
- "thread_local 1.1.7",
- "tracing",
- "tracing-core",
- "tracing-log",
-]
-
-[[package]]
-name = "treediff"
-version = "3.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff"
-dependencies = [
- "serde_json",
-]
-
-[[package]]
-name = "treediff"
-version = "4.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303"
-dependencies = [
- "serde_json",
-]
-
-[[package]]
-name = "try-lock"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
-
-[[package]]
-name = "tungstenite"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
-dependencies = [
- "base64 0.13.1",
- "byteorder",
- "bytes",
- "http",
- "httparse",
- "log 0.4.17",
- "rand 0.8.5",
- "sha1",
- "thiserror",
- "url",
- "utf-8",
-]
-
-[[package]]
-name = "typemap-ors"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867"
-dependencies = [
- "unsafe-any-ors",
-]
-
-[[package]]
-name = "typenum"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
-
-[[package]]
-name = "ucd-trie"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
-
-[[package]]
-name = "ucd-util"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003"
-
-[[package]]
-name = "unicase"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
-dependencies = [
- "version_check",
-]
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
-dependencies = [
- "tinyvec",
-]
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
-
-[[package]]
-name = "unsafe-any-ors"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad"
-dependencies = [
- "destructure_traitobject",
-]
-
-[[package]]
-name = "unsafe-libyaml"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6"
-
-[[package]]
-name = "untrusted"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
-
-[[package]]
-name = "url"
-version = "2.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
-dependencies = [
- "form_urlencoded",
- "idna",
- "percent-encoding",
- "serde",
-]
-
-[[package]]
-name = "utf-8"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
-
-[[package]]
-name = "utf8-ranges"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
-name = "uuid"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
-dependencies = [
- "getrandom 0.2.9",
-]
-
-[[package]]
-name = "valuable"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
-
-[[package]]
-name = "vcpkg"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
-
-[[package]]
-name = "version-compare"
-version = "0.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
-
-[[package]]
-name = "version-compare"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "vtparse"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "waker-fn"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
-
-[[package]]
-name = "walkdir"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
-dependencies = [
- "same-file",
- "winapi-util",
-]
-
-[[package]]
-name = "want"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
-dependencies = [
- "log 0.4.17",
- "try-lock",
-]
-
-[[package]]
-name = "warp"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-util",
- "headers",
- "http",
- "hyper",
- "log 0.4.17",
- "mime",
- "mime_guess",
- "multer",
- "percent-encoding",
- "pin-project",
- "rustls-pemfile",
- "scoped-tls",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "tokio",
- "tokio-stream",
- "tokio-tungstenite",
- "tokio-util",
- "tower-service",
- "tracing",
-]
-
-[[package]]
-name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
-
-[[package]]
-name = "wasi"
-version = "0.10.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
-dependencies = [
- "bumpalo",
- "log 0.4.17",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn 2.0.18",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.18",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
-
-[[package]]
-name = "wasm-streams"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078"
-dependencies = [
- "futures-util",
- "js-sys",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
-]
-
-[[package]]
-name = "web-sys"
-version = "0.3.63"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "webkit2gtk"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "gdk",
- "gdk-sys",
- "gio",
- "gio-sys",
- "glib",
- "glib-sys",
- "gobject-sys",
- "gtk",
- "gtk-sys",
- "javascriptcore-rs",
- "libc",
- "once_cell",
- "soup2",
- "webkit2gtk-sys",
-]
-
-[[package]]
-name = "webkit2gtk-sys"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3"
-dependencies = [
- "atk-sys",
- "bitflags",
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gdk-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "gtk-sys",
- "javascriptcore-rs-sys",
- "libc",
- "pango-sys",
- "pkg-config",
- "soup2-sys",
- "system-deps 6.1.0",
-]
-
-[[package]]
-name = "webpki"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "webpki-roots"
-version = "0.22.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
-dependencies = [
- "webpki",
-]
-
-[[package]]
-name = "webview2-com"
-version = "0.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178"
-dependencies = [
- "webview2-com-macros",
- "webview2-com-sys",
- "windows 0.39.0",
- "windows-implement",
-]
-
-[[package]]
-name = "webview2-com-macros"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "webview2-com-sys"
-version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7"
-dependencies = [
- "regex 1.8.3",
- "serde",
- "serde_json",
- "thiserror",
- "windows 0.39.0",
- "windows-bindgen",
- "windows-metadata",
-]
-
-[[package]]
-name = "which"
-version = "4.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
-dependencies = [
- "either",
- "libc",
- "once_cell",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "window-shadows"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d30320647cfc3dc45554c8ad825b84831def81f967a2f7589931328ff9b16d"
-dependencies = [
- "cocoa",
- "objc",
- "raw-window-handle",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "window-vibrancy"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f762d9cc392fb85e6b1b5eed1ef13d73fed5149a5cbb017a7137497d14ef612"
-dependencies = [
- "cocoa",
- "objc",
- "raw-window-handle",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "windows"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
-dependencies = [
- "windows_aarch64_msvc 0.37.0",
- "windows_i686_gnu 0.37.0",
- "windows_i686_msvc 0.37.0",
- "windows_x86_64_gnu 0.37.0",
- "windows_x86_64_msvc 0.37.0",
-]
-
-[[package]]
-name = "windows"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a"
-dependencies = [
- "windows-implement",
- "windows_aarch64_msvc 0.39.0",
- "windows_i686_gnu 0.39.0",
- "windows_i686_msvc 0.39.0",
- "windows_x86_64_gnu 0.39.0",
- "windows_x86_64_msvc 0.39.0",
-]
-
-[[package]]
-name = "windows"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
-dependencies = [
- "windows-targets 0.48.0",
-]
-
-[[package]]
-name = "windows-bindgen"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41"
-dependencies = [
- "windows-metadata",
- "windows-tokens",
-]
-
-[[package]]
-name = "windows-implement"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7"
-dependencies = [
- "syn 1.0.109",
- "windows-tokens",
-]
-
-[[package]]
-name = "windows-metadata"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278"
-
-[[package]]
-name = "windows-sys"
-version = "0.42.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
-]
-
-[[package]]
-name = "windows-tokens"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
-
-[[package]]
-name = "winnow"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "winreg"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winreg"
-version = "0.50.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
-dependencies = [
- "cfg-if",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "winres"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
-dependencies = [
- "toml 0.5.11",
-]
-
-[[package]]
-name = "wry"
-version = "0.24.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33748f35413c8a98d45f7a08832d848c0c5915501803d1faade5a4ebcd258cea"
-dependencies = [
- "base64 0.13.1",
- "block",
- "cocoa",
- "core-graphics",
- "crossbeam-channel",
- "dunce",
- "gdk",
- "gio",
- "glib",
- "gtk",
- "html5ever",
- "http",
- "kuchiki",
- "libc",
- "log 0.4.17",
- "objc",
- "objc_id",
- "once_cell",
- "serde",
- "serde_json",
- "sha2 0.10.6",
- "soup2",
- "tao",
- "thiserror",
- "url",
- "webkit2gtk",
- "webkit2gtk-sys",
- "webview2-com",
- "windows 0.39.0",
- "windows-implement",
-]
-
-[[package]]
-name = "x11"
-version = "2.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
-dependencies = [
- "libc",
- "pkg-config",
-]
-
-[[package]]
-name = "x11-dl"
-version = "2.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
-dependencies = [
- "libc",
- "once_cell",
- "pkg-config",
-]
-
-[[package]]
-name = "xattr"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "yaml-rust"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
-dependencies = [
- "linked-hash-map",
-]
-
-[[package]]
-name = "zip"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
-dependencies = [
- "byteorder",
- "crc32fast",
- "crossbeam-utils",
-]
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
deleted file mode 100644
index 440a398..0000000
--- a/src-tauri/Cargo.toml
+++ /dev/null
@@ -1,69 +0,0 @@
-[package]
-name = "clash-verge"
-version = "0.1.0"
-description = "clash verge"
-authors = ["zzzgydi"]
-license = "GPL-3.0"
-repository = "https://github.com/zzzgydi/clash-verge.git"
-default-run = "clash-verge"
-edition = "2021"
-build = "build.rs"
-
-[build-dependencies]
-tauri-build = { version = "1", features = [] }
-
-[dependencies]
-warp = "0.3"
-which = "4.2.2"
-anyhow = "1.0"
-dirs = "5.0.0"
-open = "4.0.1"
-log = "0.4.14"
-ctrlc = "3.2.3"
-dunce = "1.0.2"
-log4rs = "1.0.0"
-nanoid = "0.4.0"
-chrono = "0.4.19"
-sysinfo = "0.29"
-sysproxy = "0.3"
-rquickjs = "0.1.7"
-serde_json = "1.0"
-serde_yaml = "0.9"
-auto-launch = "0.5"
-once_cell = "1.14.0"
-port_scanner = "0.1.5"
-delay_timer = "0.11.1"
-parking_lot = "0.12.0"
-tokio = { version = "1", features = ["full"] }
-serde = { version = "1.0", features = ["derive"] }
-reqwest = { version = "0.11", features = ["json","rustls-tls"] }
-tauri = { version = "1.2.4", features = ["global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
-window-vibrancy = { version = "0.3.0" }
-window-shadows = { version = "0.2.0" }
-wry = { version = "0.24.3" }
-
-
-[target.'cfg(windows)'.dependencies]
-runas = "1.1.0"
-deelevate = "0.2.0"
-winreg = { version = "0.50", features = ["transactions"] }
-windows-sys = { version = "0.48", features = ["Win32_System_LibraryLoader", "Win32_System_SystemInformation"] }
-
-[target.'cfg(windows)'.dependencies.tauri]
-features = ["global-shortcut-all", "icon-png", "process-all", "shell-all", "system-tray", "updater", "window-all"]
-
-[target.'cfg(linux)'.dependencies.tauri]
-features = ["global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "native-tls-vendored", "reqwest-native-tls-vendored"]
-
-
-[features]
-default = ["custom-protocol"]
-custom-protocol = ["tauri/custom-protocol"]
-verge-dev = []
-default-meta = []
-
-[profile.release]
-panic = "abort"
-codegen-units = 1
-lto = true
-opt-level = "s"
diff --git a/src-tauri/build.rs b/src-tauri/build.rs
deleted file mode 100644
index d860e1e..0000000
--- a/src-tauri/build.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- tauri_build::build()
-}
diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png
deleted file mode 100644
index be2533a..0000000
Binary files a/src-tauri/icons/128x128.png and /dev/null differ
diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png
deleted file mode 100644
index 3245891..0000000
Binary files a/src-tauri/icons/128x128@2x.png and /dev/null differ
diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png
deleted file mode 100644
index 1a93685..0000000
Binary files a/src-tauri/icons/32x32.png and /dev/null differ
diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png
deleted file mode 100644
index 4240ea5..0000000
Binary files a/src-tauri/icons/Square107x107Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png
deleted file mode 100644
index 822b49b..0000000
Binary files a/src-tauri/icons/Square142x142Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png
deleted file mode 100644
index bb7e494..0000000
Binary files a/src-tauri/icons/Square150x150Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png
deleted file mode 100644
index 9b0ec9f..0000000
Binary files a/src-tauri/icons/Square284x284Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png
deleted file mode 100644
index 496a662..0000000
Binary files a/src-tauri/icons/Square30x30Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png
deleted file mode 100644
index c02df10..0000000
Binary files a/src-tauri/icons/Square310x310Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png
deleted file mode 100644
index 8ff531d..0000000
Binary files a/src-tauri/icons/Square44x44Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png
deleted file mode 100644
index 7829892..0000000
Binary files a/src-tauri/icons/Square71x71Logo.png and /dev/null differ
diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png
deleted file mode 100644
index 6b64990..0000000
Binary files a/src-tauri/icons/Square89x89Logo.png and /dev/null differ
diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png
deleted file mode 100644
index 15344c6..0000000
Binary files a/src-tauri/icons/StoreLogo.png and /dev/null differ
diff --git a/src-tauri/icons/icon-new.icns b/src-tauri/icons/icon-new.icns
deleted file mode 100644
index b66e74e..0000000
Binary files a/src-tauri/icons/icon-new.icns and /dev/null differ
diff --git a/src-tauri/icons/icon-shrink.png b/src-tauri/icons/icon-shrink.png
deleted file mode 100644
index 5ebfa38..0000000
Binary files a/src-tauri/icons/icon-shrink.png and /dev/null differ
diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns
deleted file mode 100644
index 88df4a0..0000000
Binary files a/src-tauri/icons/icon.icns and /dev/null differ
diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico
deleted file mode 100644
index e406a78..0000000
Binary files a/src-tauri/icons/icon.ico and /dev/null differ
diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png
deleted file mode 100644
index cf91cf6..0000000
Binary files a/src-tauri/icons/icon.png and /dev/null differ
diff --git a/src-tauri/icons/tray-icon.ico b/src-tauri/icons/tray-icon.ico
deleted file mode 100644
index 611c958..0000000
Binary files a/src-tauri/icons/tray-icon.ico and /dev/null differ
diff --git a/src-tauri/icons/tray-icon.png b/src-tauri/icons/tray-icon.png
deleted file mode 100644
index be2533a..0000000
Binary files a/src-tauri/icons/tray-icon.png and /dev/null differ
diff --git a/src-tauri/icons/win-tray-icon-activated.png b/src-tauri/icons/win-tray-icon-activated.png
deleted file mode 100644
index 441ff02..0000000
Binary files a/src-tauri/icons/win-tray-icon-activated.png and /dev/null differ
diff --git a/src-tauri/icons/win-tray-icon.png b/src-tauri/icons/win-tray-icon.png
deleted file mode 100644
index 29616c8..0000000
Binary files a/src-tauri/icons/win-tray-icon.png and /dev/null differ
diff --git a/src-tauri/rustfmt.toml b/src-tauri/rustfmt.toml
deleted file mode 100644
index 11eda88..0000000
--- a/src-tauri/rustfmt.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-max_width = 100
-hard_tabs = false
-tab_spaces = 4
-newline_style = "Auto"
-use_small_heuristics = "Default"
-reorder_imports = true
-reorder_modules = true
-remove_nested_parens = true
-edition = "2021"
-merge_derives = true
-use_try_shorthand = false
-use_field_init_shorthand = false
-force_explicit_abi = true
-imports_granularity = "Crate"
diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs
deleted file mode 100644
index 4b42ebe..0000000
--- a/src-tauri/src/cmds.rs
+++ /dev/null
@@ -1,280 +0,0 @@
-use crate::{
- config::*,
- core::*,
- feat,
- utils::{dirs, help},
-};
-use crate::{ret_err, wrap_err};
-use anyhow::{Context, Result};
-use serde_yaml::Mapping;
-use std::collections::{HashMap, VecDeque};
-use sysproxy::Sysproxy;
-
-type CmdResult = Result;
-
-#[tauri::command]
-pub fn get_profiles() -> CmdResult {
- Ok(Config::profiles().data().clone())
-}
-
-#[tauri::command]
-pub async fn enhance_profiles() -> CmdResult {
- wrap_err!(CoreManager::global().update_config().await)?;
- handle::Handle::refresh_clash();
- Ok(())
-}
-
-#[tauri::command]
-pub async fn import_profile(url: String, option: Option) -> CmdResult {
- let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
- wrap_err!(Config::profiles().data().append_item(item))
-}
-
-#[tauri::command]
-pub async fn create_profile(item: PrfItem, file_data: Option) -> CmdResult {
- let item = wrap_err!(PrfItem::from(item, file_data).await)?;
- wrap_err!(Config::profiles().data().append_item(item))
-}
-
-#[tauri::command]
-pub async fn update_profile(index: String, option: Option) -> CmdResult {
- wrap_err!(feat::update_profile(index, option).await)
-}
-
-#[tauri::command]
-pub async fn delete_profile(index: String) -> CmdResult {
- let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
- if should_update {
- wrap_err!(CoreManager::global().update_config().await)?;
- handle::Handle::refresh_clash();
- }
-
- Ok(())
-}
-
-/// 修改profiles的
-#[tauri::command]
-pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult {
- wrap_err!({ Config::profiles().draft().patch_config(profiles) })?;
-
- match CoreManager::global().update_config().await {
- Ok(_) => {
- handle::Handle::refresh_clash();
- Config::profiles().apply();
- wrap_err!(Config::profiles().data().save_file())?;
- Ok(())
- }
- Err(err) => {
- Config::profiles().discard();
- log::error!(target: "app", "{err}");
- Err(format!("{err}"))
- }
- }
-}
-
-/// 修改某个profile item的
-#[tauri::command]
-pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
- wrap_err!(Config::profiles().data().patch_item(index, profile))?;
- wrap_err!(timer::Timer::global().refresh())
-}
-
-#[tauri::command]
-pub fn view_profile(index: String) -> CmdResult {
- let file = {
- wrap_err!(Config::profiles().latest().get_item(&index))?
- .file
- .clone()
- .ok_or("the file field is null")
- }?;
-
- let path = wrap_err!(dirs::app_profiles_dir())?.join(file);
- if !path.exists() {
- ret_err!("the file not found");
- }
-
- wrap_err!(help::open_file(path))
-}
-
-#[tauri::command]
-pub fn read_profile_file(index: String) -> CmdResult {
- let profiles = Config::profiles();
- let profiles = profiles.latest();
- let item = wrap_err!(profiles.get_item(&index))?;
- let data = wrap_err!(item.read_file())?;
- Ok(data)
-}
-
-#[tauri::command]
-pub fn save_profile_file(index: String, file_data: Option) -> CmdResult {
- if file_data.is_none() {
- return Ok(());
- }
-
- let profiles = Config::profiles();
- let profiles = profiles.latest();
- let item = wrap_err!(profiles.get_item(&index))?;
- wrap_err!(item.save_file(file_data.unwrap()))
-}
-
-#[tauri::command]
-pub fn get_clash_info() -> CmdResult {
- Ok(Config::clash().latest().get_client_info())
-}
-
-#[tauri::command]
-pub fn get_runtime_config() -> CmdResult> {
- Ok(Config::runtime().latest().config.clone())
-}
-
-#[tauri::command]
-pub fn get_runtime_yaml() -> CmdResult {
- let runtime = Config::runtime();
- let runtime = runtime.latest();
- let config = runtime.config.as_ref();
- wrap_err!(config
- .ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
- .and_then(
- |config| serde_yaml::to_string(config).context("failed to convert config to yaml")
- ))
-}
-
-#[tauri::command]
-pub fn get_runtime_exists() -> CmdResult> {
- Ok(Config::runtime().latest().exists_keys.clone())
-}
-
-#[tauri::command]
-pub fn get_runtime_logs() -> CmdResult>> {
- Ok(Config::runtime().latest().chain_logs.clone())
-}
-
-#[tauri::command]
-pub async fn patch_clash_config(payload: Mapping) -> CmdResult {
- wrap_err!(feat::patch_clash(payload).await)
-}
-
-#[tauri::command]
-pub fn get_verge_config() -> CmdResult {
- Ok(Config::verge().data().clone())
-}
-
-#[tauri::command]
-pub async fn patch_verge_config(payload: IVerge) -> CmdResult {
- wrap_err!(feat::patch_verge(payload).await)
-}
-
-#[tauri::command]
-pub async fn change_clash_core(clash_core: Option) -> CmdResult {
- wrap_err!(CoreManager::global().change_core(clash_core).await)
-}
-
-/// restart the sidecar
-#[tauri::command]
-pub async fn restart_sidecar() -> CmdResult {
- wrap_err!(CoreManager::global().run_core().await)
-}
-
-#[tauri::command]
-pub fn grant_permission(core: String) -> CmdResult {
- #[cfg(any(target_os = "macos", target_os = "linux"))]
- return wrap_err!(manager::grant_permission(core));
-
- #[cfg(not(any(target_os = "macos", target_os = "linux")))]
- return Err("Unsupported target".into());
-}
-
-/// get the system proxy
-#[tauri::command]
-pub fn get_sys_proxy() -> CmdResult {
- let current = wrap_err!(Sysproxy::get_system_proxy())?;
-
- let mut map = Mapping::new();
- map.insert("enable".into(), current.enable.into());
- map.insert(
- "server".into(),
- format!("{}:{}", current.host, current.port).into(),
- );
- map.insert("bypass".into(), current.bypass.into());
-
- Ok(map)
-}
-
-#[tauri::command]
-pub fn get_clash_logs() -> CmdResult> {
- Ok(logger::Logger::global().get_log())
-}
-
-#[tauri::command]
-pub fn open_app_dir() -> CmdResult<()> {
- let app_dir = wrap_err!(dirs::app_home_dir())?;
- wrap_err!(open::that(app_dir))
-}
-
-#[tauri::command]
-pub fn open_core_dir() -> CmdResult<()> {
- let core_dir = wrap_err!(tauri::utils::platform::current_exe())?;
- let core_dir = core_dir.parent().ok_or(format!("failed to get core dir"))?;
- wrap_err!(open::that(core_dir))
-}
-
-#[tauri::command]
-pub fn open_logs_dir() -> CmdResult<()> {
- let log_dir = wrap_err!(dirs::app_logs_dir())?;
- wrap_err!(open::that(log_dir))
-}
-
-#[tauri::command]
-pub fn open_web_url(url: String) -> CmdResult<()> {
- wrap_err!(open::that(url))
-}
-
-#[tauri::command]
-pub async fn clash_api_get_proxy_delay(
- name: String,
- url: Option,
-) -> CmdResult {
- match clash_api::get_proxy_delay(name, url).await {
- Ok(res) => Ok(res),
- Err(err) => Err(format!("{}", err.to_string())),
- }
-}
-
-#[cfg(windows)]
-pub mod service {
- use super::*;
- use crate::core::win_service;
-
- #[tauri::command]
- pub async fn check_service() -> CmdResult {
- wrap_err!(win_service::check_service().await)
- }
-
- #[tauri::command]
- pub async fn install_service() -> CmdResult {
- wrap_err!(win_service::install_service().await)
- }
-
- #[tauri::command]
- pub async fn uninstall_service() -> CmdResult {
- wrap_err!(win_service::uninstall_service().await)
- }
-}
-
-#[cfg(not(windows))]
-pub mod service {
- use super::*;
-
- #[tauri::command]
- pub async fn check_service() -> CmdResult {
- Ok(())
- }
- #[tauri::command]
- pub async fn install_service() -> CmdResult {
- Ok(())
- }
- #[tauri::command]
- pub async fn uninstall_service() -> CmdResult {
- Ok(())
- }
-}
diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs
deleted file mode 100644
index 6a4cf5e..0000000
--- a/src-tauri/src/config/clash.rs
+++ /dev/null
@@ -1,262 +0,0 @@
-use crate::utils::{dirs, help};
-use anyhow::Result;
-use serde::{Deserialize, Serialize};
-use serde_yaml::{Mapping, Value};
-use std::{
- net::{IpAddr, Ipv4Addr, SocketAddr},
- str::FromStr,
-};
-
-#[derive(Default, Debug, Clone)]
-pub struct IClashTemp(pub Mapping);
-
-impl IClashTemp {
- pub fn new() -> Self {
- match dirs::clash_path().and_then(|path| help::read_merge_mapping(&path)) {
- Ok(map) => Self(Self::guard(map)),
- Err(err) => {
- log::error!(target: "app", "{err}");
- Self::template()
- }
- }
- }
-
- pub fn template() -> Self {
- let mut map = Mapping::new();
-
- map.insert(
- "mixed-port".into(),
- match cfg!(feature = "default-meta") {
- false => 7890.into(),
- true => 7898.into(),
- },
- );
- map.insert("log-level".into(), "info".into());
- map.insert("allow-lan".into(), false.into());
- map.insert("mode".into(), "rule".into());
- map.insert(
- "external-controller".into(),
- match cfg!(feature = "default-meta") {
- false => "127.0.0.1:9090".into(),
- true => "127.0.0.1:9098".into(),
- },
- );
- map.insert("secret".into(), "".into());
-
- Self(map)
- }
-
- fn guard(mut config: Mapping) -> Mapping {
- let port = Self::guard_mixed_port(&config);
- let ctrl = Self::guard_server_ctrl(&config);
-
- config.insert("mixed-port".into(), port.into());
- config.insert("external-controller".into(), ctrl.into());
- config
- }
-
- pub fn patch_config(&mut self, patch: Mapping) {
- for (key, value) in patch.into_iter() {
- self.0.insert(key, value);
- }
- }
-
- pub fn save_config(&self) -> Result<()> {
- help::save_yaml(
- &dirs::clash_path()?,
- &self.0,
- Some("# Generated by Clash Verge"),
- )
- }
-
- pub fn get_mixed_port(&self) -> u16 {
- Self::guard_mixed_port(&self.0)
- }
-
- pub fn get_client_info(&self) -> ClashInfo {
- let config = &self.0;
-
- ClashInfo {
- port: Self::guard_mixed_port(&config),
- server: Self::guard_client_ctrl(&config),
- secret: config.get("secret").and_then(|value| match value {
- Value::String(val_str) => Some(val_str.clone()),
- Value::Bool(val_bool) => Some(val_bool.to_string()),
- Value::Number(val_num) => Some(val_num.to_string()),
- _ => None,
- }),
- }
- }
-
- pub fn guard_mixed_port(config: &Mapping) -> u16 {
- let mut port = config
- .get("mixed-port")
- .and_then(|value| match value {
- Value::String(val_str) => val_str.parse().ok(),
- Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
- _ => None,
- })
- .unwrap_or(7890);
- if port == 0 {
- port = 7890;
- }
- port
- }
-
- pub fn guard_server_ctrl(config: &Mapping) -> String {
- config
- .get("external-controller")
- .and_then(|value| match value.as_str() {
- Some(val_str) => {
- let val_str = val_str.trim();
-
- let val = match val_str.starts_with(":") {
- true => format!("127.0.0.1{val_str}"),
- false => val_str.to_owned(),
- };
-
- SocketAddr::from_str(val.as_str())
- .ok()
- .map(|s| s.to_string())
- }
- None => None,
- })
- .unwrap_or("127.0.0.1:9090".into())
- }
-
- pub fn guard_client_ctrl(config: &Mapping) -> String {
- let value = Self::guard_server_ctrl(config);
- match SocketAddr::from_str(value.as_str()) {
- Ok(mut socket) => {
- if socket.ip().is_unspecified() {
- socket.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
- }
- socket.to_string()
- }
- Err(_) => "127.0.0.1:9090".into(),
- }
- }
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-pub struct ClashInfo {
- /// clash core port
- pub port: u16,
- /// same as `external-controller`
- pub server: String,
- /// clash secret
- pub secret: Option,
-}
-
-#[test]
-fn test_clash_info() {
- fn get_case, D: Into>(mp: T, ec: D) -> ClashInfo {
- let mut map = Mapping::new();
- map.insert("mixed-port".into(), mp.into());
- map.insert("external-controller".into(), ec.into());
-
- IClashTemp(IClashTemp::guard(map)).get_client_info()
- }
-
- fn get_result>(port: u16, server: S) -> ClashInfo {
- ClashInfo {
- port,
- server: server.into(),
- secret: None,
- }
- }
-
- assert_eq!(
- IClashTemp(IClashTemp::guard(Mapping::new())).get_client_info(),
- get_result(7890, "127.0.0.1:9090")
- );
-
- assert_eq!(get_case("", ""), get_result(7890, "127.0.0.1:9090"));
-
- assert_eq!(get_case(65537, ""), get_result(1, "127.0.0.1:9090"));
-
- assert_eq!(
- get_case(8888, "127.0.0.1:8888"),
- get_result(8888, "127.0.0.1:8888")
- );
-
- assert_eq!(
- get_case(8888, " :98888 "),
- get_result(8888, "127.0.0.1:9090")
- );
-
- assert_eq!(
- get_case(8888, "0.0.0.0:8080 "),
- get_result(8888, "127.0.0.1:8080")
- );
-
- assert_eq!(
- get_case(8888, "0.0.0.0:8080"),
- get_result(8888, "127.0.0.1:8080")
- );
-
- assert_eq!(
- get_case(8888, "[::]:8080"),
- get_result(8888, "127.0.0.1:8080")
- );
-
- assert_eq!(
- get_case(8888, "192.168.1.1:8080"),
- get_result(8888, "192.168.1.1:8080")
- );
-
- assert_eq!(
- get_case(8888, "192.168.1.1:80800"),
- get_result(8888, "127.0.0.1:9090")
- );
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClash {
- pub mixed_port: Option,
- pub allow_lan: Option,
- pub log_level: Option,
- pub ipv6: Option,
- pub mode: Option,
- pub external_controller: Option,
- pub secret: Option,
- pub dns: Option,
- pub tun: Option,
- pub interface_name: Option,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClashTUN {
- pub enable: Option,
- pub stack: Option,
- pub auto_route: Option,
- pub auto_detect_interface: Option,
- pub dns_hijack: Option>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClashDNS {
- pub enable: Option,
- pub listen: Option,
- pub default_nameserver: Option>,
- pub enhanced_mode: Option,
- pub fake_ip_range: Option,
- pub use_hosts: Option,
- pub fake_ip_filter: Option>,
- pub nameserver: Option>,
- pub fallback: Option>,
- pub fallback_filter: Option,
- pub nameserver_policy: Option>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct IClashFallbackFilter {
- pub geoip: Option,
- pub geoip_code: Option,
- pub ipcidr: Option>,
- pub domain: Option>,
-}
diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs
deleted file mode 100644
index e5af8e5..0000000
--- a/src-tauri/src/config/config.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
-use crate::{
- enhance,
- utils::{dirs, help},
-};
-use anyhow::{anyhow, Result};
-use once_cell::sync::OnceCell;
-use std::{env::temp_dir, path::PathBuf};
-
-pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
-pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
-
-pub struct Config {
- clash_config: Draft,
- verge_config: Draft,
- profiles_config: Draft,
- runtime_config: Draft,
-}
-
-impl Config {
- pub fn global() -> &'static Config {
- static CONFIG: OnceCell = OnceCell::new();
-
- CONFIG.get_or_init(|| Config {
- clash_config: Draft::from(IClashTemp::new()),
- verge_config: Draft::from(IVerge::new()),
- profiles_config: Draft::from(IProfiles::new()),
- runtime_config: Draft::from(IRuntime::new()),
- })
- }
-
- pub fn clash() -> Draft {
- Self::global().clash_config.clone()
- }
-
- pub fn verge() -> Draft {
- Self::global().verge_config.clone()
- }
-
- pub fn profiles() -> Draft {
- Self::global().profiles_config.clone()
- }
-
- pub fn runtime() -> Draft {
- Self::global().runtime_config.clone()
- }
-
- /// 初始化配置
- pub fn init_config() -> Result<()> {
- crate::log_err!(Self::generate());
- if let Err(err) = Self::generate_file(ConfigType::Run) {
- log::error!(target: "app", "{err}");
-
- let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
- // 如果不存在就将默认的clash文件拿过来
- if !runtime_path.exists() {
- help::save_yaml(
- &runtime_path,
- &Config::clash().latest().0,
- Some("# Clash Verge Runtime"),
- )?;
- }
- }
- Ok(())
- }
-
- /// 将配置丢到对应的文件中
- pub fn generate_file(typ: ConfigType) -> Result {
- let path = match typ {
- ConfigType::Run => dirs::app_home_dir()?.join(RUNTIME_CONFIG),
- ConfigType::Check => temp_dir().join(CHECK_CONFIG),
- };
-
- let runtime = Config::runtime();
- let runtime = runtime.latest();
- let config = runtime
- .config
- .as_ref()
- .ok_or(anyhow!("failed to get runtime config"))?;
-
- help::save_yaml(&path, &config, Some("# Generated by Clash Verge"))?;
- Ok(path)
- }
-
- /// 生成配置存好
- pub fn generate() -> Result<()> {
- let (config, exists_keys, logs) = enhance::enhance();
-
- *Config::runtime().draft() = IRuntime {
- config: Some(config),
- exists_keys,
- chain_logs: logs,
- };
-
- Ok(())
- }
-}
-
-#[derive(Debug)]
-pub enum ConfigType {
- Run,
- Check,
-}
diff --git a/src-tauri/src/config/draft.rs b/src-tauri/src/config/draft.rs
deleted file mode 100644
index 5876f1b..0000000
--- a/src-tauri/src/config/draft.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use super::{IClashTemp, IProfiles, IRuntime, IVerge};
-use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
-use std::sync::Arc;
-
-#[derive(Debug, Clone)]
-pub struct Draft {
- inner: Arc)>>,
-}
-
-macro_rules! draft_define {
- ($id: ident) => {
- impl Draft<$id> {
- #[allow(unused)]
- pub fn data(&self) -> MappedMutexGuard<$id> {
- MutexGuard::map(self.inner.lock(), |guard| &mut guard.0)
- }
-
- pub fn latest(&self) -> MappedMutexGuard<$id> {
- MutexGuard::map(self.inner.lock(), |inner| {
- if inner.1.is_none() {
- &mut inner.0
- } else {
- inner.1.as_mut().unwrap()
- }
- })
- }
-
- pub fn draft(&self) -> MappedMutexGuard<$id> {
- MutexGuard::map(self.inner.lock(), |inner| {
- if inner.1.is_none() {
- inner.1 = Some(inner.0.clone());
- }
-
- inner.1.as_mut().unwrap()
- })
- }
-
- pub fn apply(&self) -> Option<$id> {
- let mut inner = self.inner.lock();
-
- match inner.1.take() {
- Some(draft) => {
- let old_value = inner.0.to_owned();
- inner.0 = draft.to_owned();
- Some(old_value)
- }
- None => None,
- }
- }
-
- pub fn discard(&self) -> Option<$id> {
- let mut inner = self.inner.lock();
- inner.1.take()
- }
- }
-
- impl From<$id> for Draft<$id> {
- fn from(data: $id) -> Self {
- Draft {
- inner: Arc::new(Mutex::new((data, None))),
- }
- }
- }
- };
-}
-
-// draft_define!(IClash);
-draft_define!(IClashTemp);
-draft_define!(IProfiles);
-draft_define!(IRuntime);
-draft_define!(IVerge);
-
-#[test]
-fn test_draft() {
- let verge = IVerge {
- enable_auto_launch: Some(true),
- enable_tun_mode: Some(false),
- ..IVerge::default()
- };
-
- let draft = Draft::from(verge);
-
- assert_eq!(draft.data().enable_auto_launch, Some(true));
- assert_eq!(draft.data().enable_tun_mode, Some(false));
-
- assert_eq!(draft.draft().enable_auto_launch, Some(true));
- assert_eq!(draft.draft().enable_tun_mode, Some(false));
-
- let mut d = draft.draft();
- d.enable_auto_launch = Some(false);
- d.enable_tun_mode = Some(true);
- drop(d);
-
- assert_eq!(draft.data().enable_auto_launch, Some(true));
- assert_eq!(draft.data().enable_tun_mode, Some(false));
-
- assert_eq!(draft.draft().enable_auto_launch, Some(false));
- assert_eq!(draft.draft().enable_tun_mode, Some(true));
-
- assert_eq!(draft.latest().enable_auto_launch, Some(false));
- assert_eq!(draft.latest().enable_tun_mode, Some(true));
-
- assert!(draft.apply().is_some());
- assert!(draft.apply().is_none());
-
- assert_eq!(draft.data().enable_auto_launch, Some(false));
- assert_eq!(draft.data().enable_tun_mode, Some(true));
-
- assert_eq!(draft.draft().enable_auto_launch, Some(false));
- assert_eq!(draft.draft().enable_tun_mode, Some(true));
-
- let mut d = draft.draft();
- d.enable_auto_launch = Some(true);
- drop(d);
-
- assert_eq!(draft.data().enable_auto_launch, Some(false));
-
- assert_eq!(draft.draft().enable_auto_launch, Some(true));
-
- assert!(draft.discard().is_some());
-
- assert_eq!(draft.data().enable_auto_launch, Some(false));
-
- assert!(draft.discard().is_none());
-
- assert_eq!(draft.draft().enable_auto_launch, Some(false));
-}
diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs
deleted file mode 100644
index b246a76..0000000
--- a/src-tauri/src/config/mod.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-mod clash;
-mod config;
-mod draft;
-mod prfitem;
-mod profiles;
-mod runtime;
-mod verge;
-
-pub use self::clash::*;
-pub use self::config::*;
-pub use self::draft::*;
-pub use self::prfitem::*;
-pub use self::profiles::*;
-pub use self::runtime::*;
-pub use self::verge::*;
diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs
deleted file mode 100644
index 1e1d4a8..0000000
--- a/src-tauri/src/config/prfitem.rs
+++ /dev/null
@@ -1,374 +0,0 @@
-use crate::utils::{dirs, help, tmpl};
-use anyhow::{bail, Context, Result};
-use reqwest::StatusCode;
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::fs;
-use sysproxy::Sysproxy;
-
-use super::Config;
-
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct PrfItem {
- pub uid: Option,
-
- /// profile item type
- /// enum value: remote | local | script | merge
- #[serde(rename = "type")]
- pub itype: Option,
-
- /// profile name
- pub name: Option,
-
- /// profile file
- pub file: Option,
-
- /// profile description
- #[serde(skip_serializing_if = "Option::is_none")]
- pub desc: Option,
-
- /// source url
- #[serde(skip_serializing_if = "Option::is_none")]
- pub url: Option,
-
- /// selected information
- #[serde(skip_serializing_if = "Option::is_none")]
- pub selected: Option>,
-
- /// subscription user info
- #[serde(skip_serializing_if = "Option::is_none")]
- pub extra: Option,
-
- /// updated time
- pub updated: Option,
-
- /// some options of the item
- #[serde(skip_serializing_if = "Option::is_none")]
- pub option: Option,
-
- /// the file data
- #[serde(skip)]
- pub file_data: Option,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct PrfSelected {
- pub name: Option,
- pub now: Option,
-}
-
-#[derive(Default, Debug, Clone, Copy, Deserialize, Serialize)]
-pub struct PrfExtra {
- pub upload: usize,
- pub download: usize,
- pub total: usize,
- pub expire: usize,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-pub struct PrfOption {
- /// for `remote` profile's http request
- /// see issue #13
- #[serde(skip_serializing_if = "Option::is_none")]
- pub user_agent: Option,
-
- /// for `remote` profile
- /// use system proxy
- #[serde(skip_serializing_if = "Option::is_none")]
- pub with_proxy: Option,
-
- /// for `remote` profile
- /// use self proxy
- #[serde(skip_serializing_if = "Option::is_none")]
- pub self_proxy: Option,
-
- #[serde(skip_serializing_if = "Option::is_none")]
- pub update_interval: Option,
-}
-
-impl PrfOption {
- pub fn merge(one: Option, other: Option) -> Option {
- match (one, other) {
- (Some(mut a), Some(b)) => {
- a.user_agent = b.user_agent.or(a.user_agent);
- a.with_proxy = b.with_proxy.or(a.with_proxy);
- a.self_proxy = b.self_proxy.or(a.self_proxy);
- a.update_interval = b.update_interval.or(a.update_interval);
- Some(a)
- }
- t @ _ => t.0.or(t.1),
- }
- }
-}
-
-impl Default for PrfItem {
- fn default() -> Self {
- PrfItem {
- uid: None,
- itype: None,
- name: None,
- desc: None,
- file: None,
- url: None,
- selected: None,
- extra: None,
- updated: None,
- option: None,
- file_data: None,
- }
- }
-}
-
-impl PrfItem {
- /// From partial item
- /// must contain `itype`
- pub async fn from(item: PrfItem, file_data: Option) -> Result {
- if item.itype.is_none() {
- bail!("type should not be null");
- }
-
- match item.itype.unwrap().as_str() {
- "remote" => {
- if item.url.is_none() {
- bail!("url should not be null");
- }
- let url = item.url.as_ref().unwrap().as_str();
- let name = item.name;
- let desc = item.desc;
- PrfItem::from_url(url, name, desc, item.option).await
- }
- "local" => {
- let name = item.name.unwrap_or("Local File".into());
- let desc = item.desc.unwrap_or("".into());
- PrfItem::from_local(name, desc, file_data)
- }
- "merge" => {
- let name = item.name.unwrap_or("Merge".into());
- let desc = item.desc.unwrap_or("".into());
- PrfItem::from_merge(name, desc)
- }
- "script" => {
- let name = item.name.unwrap_or("Script".into());
- let desc = item.desc.unwrap_or("".into());
- PrfItem::from_script(name, desc)
- }
- typ @ _ => bail!("invalid profile item type \"{typ}\""),
- }
- }
-
- /// ## Local type
- /// create a new item from name/desc
- pub fn from_local(name: String, desc: String, file_data: Option) -> Result {
- let uid = help::get_uid("l");
- let file = format!("{uid}.yaml");
-
- Ok(PrfItem {
- uid: Some(uid),
- itype: Some("local".into()),
- name: Some(name),
- desc: Some(desc),
- file: Some(file),
- url: None,
- selected: None,
- extra: None,
- option: None,
- updated: Some(chrono::Local::now().timestamp() as usize),
- file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())),
- })
- }
-
- /// ## Remote type
- /// create a new item from url
- pub async fn from_url(
- url: &str,
- name: Option,
- desc: Option,
- option: Option,
- ) -> Result {
- let opt_ref = option.as_ref();
- let with_proxy = opt_ref.map_or(false, |o| o.with_proxy.unwrap_or(false));
- let self_proxy = opt_ref.map_or(false, |o| o.self_proxy.unwrap_or(false));
- let user_agent = opt_ref.map_or(None, |o| o.user_agent.clone());
-
- let mut builder = reqwest::ClientBuilder::new().use_rustls_tls().no_proxy();
-
- // 使用软件自己的代理
- if self_proxy {
- let port = Config::clash().data().get_mixed_port();
-
- let proxy_scheme = format!("http://127.0.0.1:{port}");
-
- if let Ok(proxy) = reqwest::Proxy::http(&proxy_scheme) {
- builder = builder.proxy(proxy);
- }
- if let Ok(proxy) = reqwest::Proxy::https(&proxy_scheme) {
- builder = builder.proxy(proxy);
- }
- if let Ok(proxy) = reqwest::Proxy::all(&proxy_scheme) {
- builder = builder.proxy(proxy);
- }
- }
- // 使用系统代理
- else if with_proxy {
- match Sysproxy::get_system_proxy() {
- Ok(p @ Sysproxy { enable: true, .. }) => {
- let proxy_scheme = format!("http://{}:{}", p.host, p.port);
-
- if let Ok(proxy) = reqwest::Proxy::http(&proxy_scheme) {
- builder = builder.proxy(proxy);
- }
- if let Ok(proxy) = reqwest::Proxy::https(&proxy_scheme) {
- builder = builder.proxy(proxy);
- }
- if let Ok(proxy) = reqwest::Proxy::all(&proxy_scheme) {
- builder = builder.proxy(proxy);
- }
- }
- _ => {}
- };
- }
-
- let version = unsafe { dirs::APP_VERSION };
- let version = format!("clash-verge/{version}");
- builder = builder.user_agent(user_agent.unwrap_or(version));
-
- let resp = builder.build()?.get(url).send().await?;
-
- let status_code = resp.status();
- if !StatusCode::is_success(&status_code) {
- bail!("failed to fetch remote profile with status {status_code}")
- }
-
- let header = resp.headers();
-
- // parse the Subscription UserInfo
- let extra = match header.get("Subscription-Userinfo") {
- Some(value) => {
- let sub_info = value.to_str().unwrap_or("");
-
- Some(PrfExtra {
- upload: help::parse_str(sub_info, "upload=").unwrap_or(0),
- download: help::parse_str(sub_info, "download=").unwrap_or(0),
- total: help::parse_str(sub_info, "total=").unwrap_or(0),
- expire: help::parse_str(sub_info, "expire=").unwrap_or(0),
- })
- }
- None => None,
- };
-
- // parse the Content-Disposition
- let filename = match header.get("Content-Disposition") {
- Some(value) => {
- let filename = value.to_str().unwrap_or("");
- help::parse_str::(filename, "filename=")
- }
- None => None,
- };
-
- // parse the profile-update-interval
- let option = match header.get("profile-update-interval") {
- Some(value) => match value.to_str().unwrap_or("").parse::() {
- Ok(val) => Some(PrfOption {
- update_interval: Some(val * 60), // hour -> min
- ..PrfOption::default()
- }),
- Err(_) => None,
- },
- None => None,
- };
-
- let uid = help::get_uid("r");
- let file = format!("{uid}.yaml");
- let name = name.unwrap_or(filename.unwrap_or("Remote File".into()));
- let data = resp.text_with_charset("utf-8").await?;
-
- // process the charset "UTF-8 with BOM"
- let data = data.trim_start_matches('\u{feff}');
-
- // check the data whether the valid yaml format
- let yaml = serde_yaml::from_str::(data)
- .context("the remote profile data is invalid yaml")?;
-
- if !yaml.contains_key("proxies") && !yaml.contains_key("proxy-providers") {
- bail!("profile does not contain `proxies` or `proxy-providers`");
- }
-
- Ok(PrfItem {
- uid: Some(uid),
- itype: Some("remote".into()),
- name: Some(name),
- desc,
- file: Some(file),
- url: Some(url.into()),
- selected: None,
- extra,
- option,
- updated: Some(chrono::Local::now().timestamp() as usize),
- file_data: Some(data.into()),
- })
- }
-
- /// ## Merge type (enhance)
- /// create the enhanced item by using `merge` rule
- pub fn from_merge(name: String, desc: String) -> Result {
- let uid = help::get_uid("m");
- let file = format!("{uid}.yaml");
-
- Ok(PrfItem {
- uid: Some(uid),
- itype: Some("merge".into()),
- name: Some(name),
- desc: Some(desc),
- file: Some(file),
- url: None,
- selected: None,
- extra: None,
- option: None,
- updated: Some(chrono::Local::now().timestamp() as usize),
- file_data: Some(tmpl::ITEM_MERGE.into()),
- })
- }
-
- /// ## Script type (enhance)
- /// create the enhanced item by using javascript quick.js
- pub fn from_script(name: String, desc: String) -> Result {
- let uid = help::get_uid("s");
- let file = format!("{uid}.js"); // js ext
-
- Ok(PrfItem {
- uid: Some(uid),
- itype: Some("script".into()),
- name: Some(name),
- desc: Some(desc),
- file: Some(file),
- url: None,
- selected: None,
- extra: None,
- option: None,
- updated: Some(chrono::Local::now().timestamp() as usize),
- file_data: Some(tmpl::ITEM_SCRIPT.into()),
- })
- }
-
- /// get the file data
- pub fn read_file(&self) -> Result {
- if self.file.is_none() {
- bail!("could not find the file");
- }
-
- let file = self.file.clone().unwrap();
- let path = dirs::app_profiles_dir()?.join(file);
- fs::read_to_string(path).context("failed to read the file")
- }
-
- /// save the file data
- pub fn save_file(&self, data: String) -> Result<()> {
- if self.file.is_none() {
- bail!("could not find the file");
- }
-
- let file = self.file.clone().unwrap();
- let path = dirs::app_profiles_dir()?.join(file);
- fs::write(path, data.as_bytes()).context("failed to save the file")
- }
-}
diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs
deleted file mode 100644
index 788386a..0000000
--- a/src-tauri/src/config/profiles.rs
+++ /dev/null
@@ -1,280 +0,0 @@
-use super::prfitem::PrfItem;
-use crate::utils::{dirs, help};
-use anyhow::{bail, Context, Result};
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::{fs, io::Write};
-
-/// Define the `profiles.yaml` schema
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IProfiles {
- /// same as PrfConfig.current
- pub current: Option,
-
- /// same as PrfConfig.chain
- pub chain: Option>,
-
- /// record valid fields for clash
- pub valid: Option>,
-
- /// profile list
- pub items: Option>,
-}
-
-macro_rules! patch {
- ($lv: expr, $rv: expr, $key: tt) => {
- if ($rv.$key).is_some() {
- $lv.$key = $rv.$key;
- }
- };
-}
-
-impl IProfiles {
- pub fn new() -> Self {
- match dirs::profiles_path().and_then(|path| help::read_yaml::(&path)) {
- Ok(mut profiles) => {
- if profiles.items.is_none() {
- profiles.items = Some(vec![]);
- }
- // compatible with the old old old version
- profiles.items.as_mut().map(|items| {
- for item in items.iter_mut() {
- if item.uid.is_none() {
- item.uid = Some(help::get_uid("d"));
- }
- }
- });
- profiles
- }
- Err(err) => {
- log::error!(target: "app", "{err}");
- Self::template()
- }
- }
- }
-
- pub fn template() -> Self {
- Self {
- valid: Some(vec!["dns".into(), "sub-rules".into(), "unified-delay".into()]),
- items: Some(vec![]),
- ..Self::default()
- }
- }
-
- pub fn save_file(&self) -> Result<()> {
- help::save_yaml(
- &dirs::profiles_path()?,
- self,
- Some("# Profiles Config for Clash Verge"),
- )
- }
-
- /// 只修改current,valid和chain
- pub fn patch_config(&mut self, patch: IProfiles) -> Result<()> {
- if self.items.is_none() {
- self.items = Some(vec![]);
- }
-
- if let Some(current) = patch.current {
- let items = self.items.as_ref().unwrap();
- let some_uid = Some(current);
-
- if items.iter().any(|e| e.uid == some_uid) {
- self.current = some_uid;
- }
- }
-
- if let Some(chain) = patch.chain {
- self.chain = Some(chain);
- }
-
- if let Some(valid) = patch.valid {
- self.valid = Some(valid);
- }
-
- Ok(())
- }
-
- pub fn get_current(&self) -> Option {
- self.current.clone()
- }
-
- /// get items ref
- pub fn get_items(&self) -> Option<&Vec> {
- self.items.as_ref()
- }
-
- /// find the item by the uid
- pub fn get_item(&self, uid: &String) -> Result<&PrfItem> {
- if let Some(items) = self.items.as_ref() {
- let some_uid = Some(uid.clone());
-
- for each in items.iter() {
- if each.uid == some_uid {
- return Ok(each);
- }
- }
- }
-
- bail!("failed to get the profile item \"uid:{uid}\"");
- }
-
- /// append new item
- /// if the file_data is some
- /// then should save the data to file
- pub fn append_item(&mut self, mut item: PrfItem) -> Result<()> {
- if item.uid.is_none() {
- bail!("the uid should not be null");
- }
-
- // save the file data
- // move the field value after save
- if let Some(file_data) = item.file_data.take() {
- if item.file.is_none() {
- bail!("the file should not be null");
- }
-
- let file = item.file.clone().unwrap();
- let path = dirs::app_profiles_dir()?.join(&file);
-
- fs::File::create(path)
- .with_context(|| format!("failed to create file \"{}\"", file))?
- .write(file_data.as_bytes())
- .with_context(|| format!("failed to write to file \"{}\"", file))?;
- }
-
- if self.items.is_none() {
- self.items = Some(vec![]);
- }
-
- self.items.as_mut().map(|items| items.push(item));
- self.save_file()
- }
-
- /// update the item value
- pub fn patch_item(&mut self, uid: String, item: PrfItem) -> Result<()> {
- let mut items = self.items.take().unwrap_or(vec![]);
-
- for each in items.iter_mut() {
- if each.uid == Some(uid.clone()) {
- patch!(each, item, itype);
- patch!(each, item, name);
- patch!(each, item, desc);
- patch!(each, item, file);
- patch!(each, item, url);
- patch!(each, item, selected);
- patch!(each, item, extra);
- patch!(each, item, updated);
- patch!(each, item, option);
-
- self.items = Some(items);
- return self.save_file();
- }
- }
-
- self.items = Some(items);
- bail!("failed to find the profile item \"uid:{uid}\"")
- }
-
- /// be used to update the remote item
- /// only patch `updated` `extra` `file_data`
- pub fn update_item(&mut self, uid: String, mut item: PrfItem) -> Result<()> {
- if self.items.is_none() {
- self.items = Some(vec![]);
- }
-
- // find the item
- let _ = self.get_item(&uid)?;
-
- if let Some(items) = self.items.as_mut() {
- let some_uid = Some(uid.clone());
-
- for each in items.iter_mut() {
- if each.uid == some_uid {
- each.extra = item.extra;
- each.updated = item.updated;
-
- // save the file data
- // move the field value after save
- if let Some(file_data) = item.file_data.take() {
- let file = each.file.take();
- let file =
- file.unwrap_or(item.file.take().unwrap_or(format!("{}.yaml", &uid)));
-
- // the file must exists
- each.file = Some(file.clone());
-
- let path = dirs::app_profiles_dir()?.join(&file);
-
- fs::File::create(path)
- .with_context(|| format!("failed to create file \"{}\"", file))?
- .write(file_data.as_bytes())
- .with_context(|| format!("failed to write to file \"{}\"", file))?;
- }
-
- break;
- }
- }
- }
-
- self.save_file()
- }
-
- /// delete item
- /// if delete the current then return true
- pub fn delete_item(&mut self, uid: String) -> Result {
- let current = self.current.as_ref().unwrap_or(&uid);
- let current = current.clone();
-
- let mut items = self.items.take().unwrap_or(vec![]);
- let mut index = None;
-
- // get the index
- for i in 0..items.len() {
- if items[i].uid == Some(uid.clone()) {
- index = Some(i);
- break;
- }
- }
-
- if let Some(index) = index {
- items.remove(index).file.map(|file| {
- let _ = dirs::app_profiles_dir().map(|path| {
- let path = path.join(file);
- if path.exists() {
- let _ = fs::remove_file(path);
- }
- });
- });
- }
-
- // delete the original uid
- if current == uid {
- self.current = match items.len() > 0 {
- true => items[0].uid.clone(),
- false => None,
- };
- }
-
- self.items = Some(items);
- self.save_file()?;
- Ok(current == uid)
- }
-
- /// 获取current指向的配置内容
- pub fn current_mapping(&self) -> Result {
- match (self.current.as_ref(), self.items.as_ref()) {
- (Some(current), Some(items)) => {
- if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) {
- let file_path = match item.file.as_ref() {
- Some(file) => dirs::app_profiles_dir()?.join(file),
- None => bail!("failed to get the file field"),
- };
- return Ok(help::read_merge_mapping(&file_path)?);
- }
- bail!("failed to find the current profile \"uid:{current}\"");
- }
- _ => Ok(Mapping::new()),
- }
- }
-}
diff --git a/src-tauri/src/config/runtime.rs b/src-tauri/src/config/runtime.rs
deleted file mode 100644
index cce376b..0000000
--- a/src-tauri/src/config/runtime.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::collections::HashMap;
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IRuntime {
- pub config: Option,
- // 记录在配置中(包括merge和script生成的)出现过的keys
- // 这些keys不一定都生效
- pub exists_keys: Vec,
- pub chain_logs: HashMap>,
-}
-
-impl IRuntime {
- pub fn new() -> Self {
- Self::default()
- }
-
- // 这里只更改 allow-lan | ipv6 | log-level
- pub fn patch_config(&mut self, patch: Mapping) {
- if let Some(config) = self.config.as_mut() {
- ["allow-lan", "ipv6", "log-level"]
- .into_iter()
- .for_each(|key| {
- if let Some(value) = patch.get(key).to_owned() {
- config.insert(key.into(), value.clone());
- }
- });
- }
- }
-}
diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs
deleted file mode 100644
index 961280e..0000000
--- a/src-tauri/src/config/verge.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-use crate::utils::{dirs, help};
-use anyhow::Result;
-use log::LevelFilter;
-use serde::{Deserialize, Serialize};
-
-/// ### `verge.yaml` schema
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IVerge {
- /// app listening port for app singleton
- pub app_singleton_port: Option,
-
- /// app log level
- /// silent | error | warn | info | debug | trace
- pub app_log_level: Option,
-
- // i18n
- pub language: Option,
-
- /// `light` or `dark` or `system`
- pub theme_mode: Option,
-
- /// enable blur mode
- /// maybe be able to set the alpha
- pub theme_blur: Option,
-
- /// enable traffic graph default is true
- pub traffic_graph: Option,
-
- /// show memory info (only for Clash Meta)
- pub enable_memory_usage: Option,
-
- /// clash tun mode
- pub enable_tun_mode: Option,
-
- /// windows service mode
- #[serde(skip_serializing_if = "Option::is_none")]
- pub enable_service_mode: Option,
-
- /// can the app auto startup
- pub enable_auto_launch: Option,
-
- /// not show the window on launch
- pub enable_silent_start: Option,
-
- /// set system proxy
- pub enable_system_proxy: Option,
-
- /// enable proxy guard
- pub enable_proxy_guard: Option,
-
- /// set system proxy bypass
- pub system_proxy_bypass: Option,
-
- /// proxy guard duration
- pub proxy_guard_duration: Option,
-
- /// theme setting
- pub theme_setting: Option,
-
- /// web ui list
- pub web_ui_list: Option>,
-
- /// clash core path
- #[serde(skip_serializing_if = "Option::is_none")]
- pub clash_core: Option,
-
- /// hotkey map
- /// format: {func},{key}
- pub hotkeys: Option>,
-
- /// 切换代理时自动关闭连接
- pub auto_close_connection: Option,
-
- /// 默认的延迟测试连接
- pub default_latency_test: Option,
-
- /// 支持关闭字段过滤,避免meta的新字段都被过滤掉,默认为真
- pub enable_clash_fields: Option,
-
- /// 是否使用内部的脚本支持,默认为真
- pub enable_builtin_enhanced: Option,
-
- /// proxy 页面布局 列数
- pub proxy_layout_column: Option,
-
- /// 日志清理
- /// 0: 不清理; 1: 7天; 2: 30天; 3: 90天
- pub auto_log_clean: Option,
-
- /// window size and position
- #[serde(skip_serializing_if = "Option::is_none")]
- pub window_size_position: Option>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct IVergeTheme {
- pub primary_color: Option,
- pub secondary_color: Option,
- pub primary_text: Option,
- pub secondary_text: Option,
-
- pub info_color: Option,
- pub error_color: Option,
- pub warning_color: Option,
- pub success_color: Option,
-
- pub font_family: Option,
- pub css_injection: Option,
-}
-
-impl IVerge {
- pub fn new() -> Self {
- match dirs::verge_path().and_then(|path| help::read_yaml::(&path)) {
- Ok(config) => config,
- Err(err) => {
- log::error!(target: "app", "{err}");
- Self::template()
- }
- }
- }
-
- pub fn template() -> Self {
- Self {
- clash_core: match cfg!(feature = "default-meta") {
- false => Some("clash".into()),
- true => Some("clash-meta".into()),
- },
- language: match cfg!(feature = "default-meta") {
- false => Some("en".into()),
- true => Some("zh".into()),
- },
- theme_mode: Some("system".into()),
- theme_blur: Some(false),
- traffic_graph: Some(true),
- enable_memory_usage: Some(true),
- enable_auto_launch: Some(false),
- enable_silent_start: Some(false),
- enable_system_proxy: Some(false),
- enable_proxy_guard: Some(false),
- proxy_guard_duration: Some(30),
- auto_close_connection: Some(true),
- enable_builtin_enhanced: Some(true),
- enable_clash_fields: Some(true),
- auto_log_clean: Some(3),
- ..Self::default()
- }
- }
-
- /// Save IVerge App Config
- pub fn save_file(&self) -> Result<()> {
- help::save_yaml(&dirs::verge_path()?, &self, Some("# Clash Verge Config"))
- }
-
- /// patch verge config
- /// only save to file
- pub fn patch_config(&mut self, patch: IVerge) {
- macro_rules! patch {
- ($key: tt) => {
- if patch.$key.is_some() {
- self.$key = patch.$key;
- }
- };
- }
-
- patch!(app_log_level);
- patch!(language);
- patch!(theme_mode);
- patch!(theme_blur);
- patch!(traffic_graph);
- patch!(enable_memory_usage);
-
- patch!(enable_tun_mode);
- patch!(enable_service_mode);
- patch!(enable_auto_launch);
- patch!(enable_silent_start);
- patch!(enable_system_proxy);
- patch!(enable_proxy_guard);
- patch!(system_proxy_bypass);
- patch!(proxy_guard_duration);
-
- patch!(theme_setting);
- patch!(web_ui_list);
- patch!(clash_core);
- patch!(hotkeys);
-
- patch!(auto_close_connection);
- patch!(default_latency_test);
- patch!(enable_builtin_enhanced);
- patch!(proxy_layout_column);
- patch!(enable_clash_fields);
- patch!(auto_log_clean);
- patch!(window_size_position);
- }
-
- /// 在初始化前尝试拿到单例端口的值
- pub fn get_singleton_port() -> u16 {
- #[cfg(not(feature = "verge-dev"))]
- const SERVER_PORT: u16 = 33331;
- #[cfg(feature = "verge-dev")]
- const SERVER_PORT: u16 = 11233;
-
- match dirs::verge_path().and_then(|path| help::read_yaml::(&path)) {
- Ok(config) => config.app_singleton_port.unwrap_or(SERVER_PORT),
- Err(_) => SERVER_PORT, // 这里就不log错误了
- }
- }
-
- /// 获取日志等级
- pub fn get_log_level(&self) -> LevelFilter {
- if let Some(level) = self.app_log_level.as_ref() {
- match level.to_lowercase().as_str() {
- "silent" => LevelFilter::Off,
- "error" => LevelFilter::Error,
- "warn" => LevelFilter::Warn,
- "info" => LevelFilter::Info,
- "debug" => LevelFilter::Debug,
- "trace" => LevelFilter::Trace,
- _ => LevelFilter::Info,
- }
- } else {
- LevelFilter::Info
- }
- }
-}
diff --git a/src-tauri/src/core/clash_api.rs b/src-tauri/src/core/clash_api.rs
deleted file mode 100644
index 0636b41..0000000
--- a/src-tauri/src/core/clash_api.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use crate::config::Config;
-use anyhow::{bail, Result};
-use reqwest::header::HeaderMap;
-use serde::{Deserialize, Serialize};
-use serde_yaml::Mapping;
-use std::collections::HashMap;
-
-/// PUT /configs
-/// path 是绝对路径
-pub async fn put_configs(path: &str) -> Result<()> {
- let (url, headers) = clash_client_info()?;
- let url = format!("{url}/configs");
-
- let mut data = HashMap::new();
- data.insert("path", path);
-
- let client = reqwest::ClientBuilder::new().no_proxy().build()?;
- let builder = client.put(&url).headers(headers).json(&data);
- let response = builder.send().await?;
-
- match response.status().as_u16() {
- 204 => Ok(()),
- status @ _ => {
- bail!("failed to put configs with status \"{status}\"")
- }
- }
-}
-
-/// PATCH /configs
-pub async fn patch_configs(config: &Mapping) -> Result<()> {
- let (url, headers) = clash_client_info()?;
- let url = format!("{url}/configs");
-
- let client = reqwest::ClientBuilder::new().no_proxy().build()?;
- let builder = client.patch(&url).headers(headers.clone()).json(config);
- builder.send().await?;
- Ok(())
-}
-
-#[derive(Default, Debug, Clone, Deserialize, Serialize)]
-pub struct DelayRes {
- delay: u64,
-}
-
-/// GET /proxies/{name}/delay
-/// 获取代理延迟
-pub async fn get_proxy_delay(name: String, test_url: Option) -> Result {
- let (url, headers) = clash_client_info()?;
- let url = format!("{url}/proxies/{name}/delay");
-
- let default_url = "http://www.gstatic.com/generate_204";
- let test_url = test_url
- .map(|s| if s.is_empty() { default_url.into() } else { s })
- .unwrap_or(default_url.into());
-
- let client = reqwest::ClientBuilder::new().no_proxy().build()?;
- let builder = client
- .get(&url)
- .headers(headers)
- .query(&[("timeout", "10000"), ("url", &test_url)]);
- let response = builder.send().await?;
-
- Ok(response.json::().await?)
-}
-
-/// 根据clash info获取clash服务地址和请求头
-fn clash_client_info() -> Result<(String, HeaderMap)> {
- let client = { Config::clash().data().get_client_info() };
-
- let server = format!("http://{}", client.server);
-
- let mut headers = HeaderMap::new();
- headers.insert("Content-Type", "application/json".parse()?);
-
- if let Some(secret) = client.secret {
- let secret = format!("Bearer {}", secret).parse()?;
- headers.insert("Authorization", secret);
- }
-
- Ok((server, headers))
-}
-
-/// 缩短clash的日志
-pub fn parse_log(log: String) -> String {
- if log.starts_with("time=") && log.len() > 33 {
- return (&log[33..]).to_owned();
- }
- if log.len() > 9 {
- return (&log[9..]).to_owned();
- }
- return log;
-}
-
-/// 缩短clash -t的错误输出
-/// 仅适配 clash p核 8-26、clash meta 1.13.1
-pub fn parse_check_output(log: String) -> String {
- let t = log.find("time=");
- let m = log.find("msg=");
- let mr = log.rfind('"');
-
- if let (Some(_), Some(m), Some(mr)) = (t, m, mr) {
- let e = match log.find("level=error msg=") {
- Some(e) => e + 17,
- None => m + 5,
- };
-
- if mr > m {
- return (&log[e..mr]).to_owned();
- }
- }
-
- let l = log.find("error=");
- let r = log.find("path=").or(Some(log.len()));
-
- if let (Some(l), Some(r)) = (l, r) {
- return (&log[(l + 6)..(r - 1)]).to_owned();
- }
-
- log
-}
-
-#[test]
-fn test_parse_check_output() {
- let str1 = r#"xxxx\n time="2022-11-18T20:42:58+08:00" level=error msg="proxy 0: 'alpn' expected type 'string', got unconvertible type '[]interface {}'""#;
- let str2 = r#"20:43:49 ERR [Config] configuration file test failed error=proxy 0: unsupport proxy type: hysteria path=xxx"#;
- let str3 = r#"
- "time="2022-11-18T21:38:01+08:00" level=info msg="Start initial configuration in progress"
- time="2022-11-18T21:38:01+08:00" level=error msg="proxy 0: 'alpn' expected type 'string', got unconvertible type '[]interface {}'"
- configuration file xxx\n
- "#;
-
- let res1 = parse_check_output(str1.into());
- let res2 = parse_check_output(str2.into());
- let res3 = parse_check_output(str3.into());
-
- println!("res1: {res1}");
- println!("res2: {res2}");
- println!("res3: {res3}");
-
- assert_eq!(res1, res3);
-}
diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs
deleted file mode 100644
index 6b3053b..0000000
--- a/src-tauri/src/core/core.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-use super::{clash_api, logger::Logger};
-use crate::log_err;
-use crate::{config::*, utils::dirs};
-use anyhow::{bail, Context, Result};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::{fs, io::Write, sync::Arc, time::Duration};
-use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt};
-use tauri::api::process::{Command, CommandChild, CommandEvent};
-use tokio::time::sleep;
-
-#[derive(Debug)]
-pub struct CoreManager {
- sidecar: Arc>>,
-
- #[allow(unused)]
- use_service_mode: Arc>,
-}
-
-impl CoreManager {
- pub fn global() -> &'static CoreManager {
- static CORE_MANAGER: OnceCell = OnceCell::new();
-
- CORE_MANAGER.get_or_init(|| CoreManager {
- sidecar: Arc::new(Mutex::new(None)),
- use_service_mode: Arc::new(Mutex::new(false)),
- })
- }
-
- pub fn init(&self) -> Result<()> {
- // kill old clash process
- let _ = dirs::clash_pid_path()
- .and_then(|path| fs::read(path).map(|p| p.to_vec()).context(""))
- .and_then(|pid| String::from_utf8_lossy(&pid).parse().context(""))
- .map(|pid| {
- let mut system = System::new();
- system.refresh_all();
- system.process(Pid::from_u32(pid)).map(|proc| {
- if proc.name().contains("clash") {
- log::debug!(target: "app", "kill old clash process");
- proc.kill();
- }
- });
- });
-
- tauri::async_runtime::spawn(async {
- // 启动clash
- log_err!(Self::global().run_core().await);
- });
-
- Ok(())
- }
-
- /// 检查配置是否正确
- pub fn check_config(&self) -> Result<()> {
- let config_path = Config::generate_file(ConfigType::Check)?;
- let config_path = dirs::path_to_str(&config_path)?;
-
- let clash_core = { Config::verge().latest().clash_core.clone() };
- let clash_core = clash_core.unwrap_or("clash".into());
-
- let app_dir = dirs::app_home_dir()?;
- let app_dir = dirs::path_to_str(&app_dir)?;
-
- let output = Command::new_sidecar(clash_core)?
- .args(["-t", "-d", app_dir, "-f", config_path])
- .output()?;
-
- if !output.status.success() {
- let error = clash_api::parse_check_output(output.stdout.clone());
- let error = match error.len() > 0 {
- true => error,
- false => output.stdout.clone(),
- };
- Logger::global().set_log(output.stdout);
- bail!("{error}");
- }
-
- Ok(())
- }
-
- /// 启动核心
- pub async fn run_core(&self) -> Result<()> {
- let config_path = Config::generate_file(ConfigType::Run)?;
-
- #[allow(unused_mut)]
- let mut should_kill = match self.sidecar.lock().take() {
- Some(child) => {
- log::debug!(target: "app", "stop the core by sidecar");
- let _ = child.kill();
- true
- }
- None => false,
- };
-
- #[cfg(target_os = "windows")]
- if *self.use_service_mode.lock() {
- log::debug!(target: "app", "stop the core by service");
- log_err!(super::win_service::stop_core_by_service().await);
- should_kill = true;
- }
-
- // 这里得等一会儿
- if should_kill {
- sleep(Duration::from_millis(500)).await;
- }
-
- #[cfg(target_os = "windows")]
- {
- use super::win_service;
-
- // 服务模式
- let enable = { Config::verge().latest().enable_service_mode.clone() };
- let enable = enable.unwrap_or(false);
-
- *self.use_service_mode.lock() = enable;
-
- if enable {
- // 服务模式启动失败就直接运行sidecar
- log::debug!(target: "app", "try to run core in service mode");
-
- match (|| async {
- win_service::check_service().await?;
- win_service::run_core_by_service(&config_path).await
- })()
- .await
- {
- Ok(_) => return Ok(()),
- Err(err) => {
- // 修改这个值,免得stop出错
- *self.use_service_mode.lock() = false;
- log::error!(target: "app", "{err}");
- }
- }
- }
- }
-
- let app_dir = dirs::app_home_dir()?;
- let app_dir = dirs::path_to_str(&app_dir)?;
-
- let clash_core = { Config::verge().latest().clash_core.clone() };
- let clash_core = clash_core.unwrap_or("clash".into());
- let is_clash = clash_core == "clash";
-
- let config_path = dirs::path_to_str(&config_path)?;
-
- // fix #212
- let args = match clash_core.as_str() {
- "clash-meta" => vec!["-m", "-d", app_dir, "-f", config_path],
- _ => vec!["-d", app_dir, "-f", config_path],
- };
-
- let cmd = Command::new_sidecar(clash_core)?;
- let (mut rx, cmd_child) = cmd.args(args).spawn()?;
-
- // 将pid写入文件中
- crate::log_err!((|| {
- let pid = cmd_child.pid();
- let path = dirs::clash_pid_path()?;
- fs::File::create(path)
- .context("failed to create the pid file")?
- .write(format!("{pid}").as_bytes())
- .context("failed to write pid to the file")?;
- >::Ok(())
- })());
-
- let mut sidecar = self.sidecar.lock();
- *sidecar = Some(cmd_child);
- drop(sidecar);
-
- tauri::async_runtime::spawn(async move {
- while let Some(event) = rx.recv().await {
- match event {
- CommandEvent::Stdout(line) => {
- if is_clash {
- let stdout = clash_api::parse_log(line.clone());
- log::info!(target: "app", "[clash]: {stdout}");
- } else {
- log::info!(target: "app", "[clash]: {line}");
- };
- Logger::global().set_log(line);
- }
- CommandEvent::Stderr(err) => {
- // let stdout = clash_api::parse_log(err.clone());
- log::error!(target: "app", "[clash]: {err}");
- Logger::global().set_log(err);
- }
- CommandEvent::Error(err) => {
- log::error!(target: "app", "[clash]: {err}");
- Logger::global().set_log(err);
- }
- CommandEvent::Terminated(_) => {
- log::info!(target: "app", "clash core terminated");
- let _ = CoreManager::global().recover_core();
- break;
- }
- _ => {}
- }
- }
- });
-
- Ok(())
- }
-
- /// 重启内核
- pub fn recover_core(&'static self) -> Result<()> {
- // 服务模式不管
- #[cfg(target_os = "windows")]
- if *self.use_service_mode.lock() {
- return Ok(());
- }
-
- // 清空原来的sidecar值
- if let Some(sidecar) = self.sidecar.lock().take() {
- let _ = sidecar.kill();
- }
-
- tauri::async_runtime::spawn(async move {
- // 6秒之后再查看服务是否正常 (时间随便搞的)
- // terminated 可能是切换内核 (切换内核已经有500ms的延迟)
- sleep(Duration::from_millis(6666)).await;
-
- if self.sidecar.lock().is_none() {
- log::info!(target: "app", "recover clash core");
-
- // 重新启动app
- if let Err(err) = self.run_core().await {
- log::error!(target: "app", "failed to recover clash core");
- log::error!(target: "app", "{err}");
-
- let _ = self.recover_core();
- }
- }
- });
-
- Ok(())
- }
-
- /// 停止核心运行
- pub fn stop_core(&self) -> Result<()> {
- #[cfg(target_os = "windows")]
- if *self.use_service_mode.lock() {
- log::debug!(target: "app", "stop the core by service");
- tauri::async_runtime::block_on(async move {
- log_err!(super::win_service::stop_core_by_service().await);
- });
- return Ok(());
- }
-
- let mut sidecar = self.sidecar.lock();
- if let Some(child) = sidecar.take() {
- log::debug!(target: "app", "stop the core by sidecar");
- let _ = child.kill();
- }
- Ok(())
- }
-
- /// 切换核心
- pub async fn change_core(&self, clash_core: Option) -> Result<()> {
- let clash_core = clash_core.ok_or(anyhow::anyhow!("clash core is null"))?;
-
- if &clash_core != "clash" && &clash_core != "clash-meta" {
- bail!("invalid clash core name \"{clash_core}\"");
- }
-
- log::debug!(target: "app", "change core to `{clash_core}`");
-
- Config::verge().draft().clash_core = Some(clash_core);
-
- // 更新配置
- Config::generate()?;
-
- self.check_config()?;
-
- // 清掉旧日志
- Logger::global().clear_log();
-
- match self.run_core().await {
- Ok(_) => {
- Config::verge().apply();
- Config::runtime().apply();
- log_err!(Config::verge().latest().save_file());
- Ok(())
- }
- Err(err) => {
- Config::verge().discard();
- Config::runtime().discard();
- Err(err)
- }
- }
- }
-
- /// 更新proxies那些
- /// 如果涉及端口和外部控制则需要重启
- pub async fn update_config(&self) -> Result<()> {
- log::debug!(target: "app", "try to update clash config");
-
- // 更新配置
- Config::generate()?;
-
- // 检查配置是否正常
- self.check_config()?;
-
- // 更新运行时配置
- let path = Config::generate_file(ConfigType::Run)?;
- let path = dirs::path_to_str(&path)?;
-
- // 发送请求 发送5次
- for i in 0..5 {
- match clash_api::put_configs(path).await {
- Ok(_) => break,
- Err(err) => {
- if i < 4 {
- log::info!(target: "app", "{err}");
- } else {
- bail!(err);
- }
- }
- }
- sleep(Duration::from_millis(250)).await;
- }
-
- Ok(())
- }
-}
diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs
deleted file mode 100644
index 5b46cea..0000000
--- a/src-tauri/src/core/handle.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use super::tray::Tray;
-use crate::log_err;
-use anyhow::{bail, Result};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::sync::Arc;
-use tauri::{AppHandle, Manager, Window};
-
-#[derive(Debug, Default, Clone)]
-pub struct Handle {
- pub app_handle: Arc>>,
-}
-
-impl Handle {
- pub fn global() -> &'static Handle {
- static HANDLE: OnceCell = OnceCell::new();
-
- HANDLE.get_or_init(|| Handle {
- app_handle: Arc::new(Mutex::new(None)),
- })
- }
-
- pub fn init(&self, app_handle: AppHandle) {
- *self.app_handle.lock() = Some(app_handle);
- }
-
- pub fn get_window(&self) -> Option {
- self.app_handle
- .lock()
- .as_ref()
- .map_or(None, |a| a.get_window("main"))
- }
-
- pub fn refresh_clash() {
- if let Some(window) = Self::global().get_window() {
- log_err!(window.emit("verge://refresh-clash-config", "yes"));
- }
- }
-
- pub fn refresh_verge() {
- if let Some(window) = Self::global().get_window() {
- log_err!(window.emit("verge://refresh-verge-config", "yes"));
- }
- }
-
- #[allow(unused)]
- pub fn refresh_profiles() {
- if let Some(window) = Self::global().get_window() {
- log_err!(window.emit("verge://refresh-profiles-config", "yes"));
- }
- }
-
- pub fn notice_message, M: Into>(status: S, msg: M) {
- if let Some(window) = Self::global().get_window() {
- log_err!(window.emit("verge://notice-message", (status.into(), msg.into())));
- }
- }
-
- pub fn update_systray() -> Result<()> {
- let app_handle = Self::global().app_handle.lock();
- if app_handle.is_none() {
- bail!("update_systray unhandled error");
- }
- Tray::update_systray(app_handle.as_ref().unwrap())?;
- Ok(())
- }
-
- /// update the system tray state
- pub fn update_systray_part() -> Result<()> {
- let app_handle = Self::global().app_handle.lock();
- if app_handle.is_none() {
- bail!("update_systray unhandled error");
- }
- Tray::update_part(app_handle.as_ref().unwrap())?;
- Ok(())
- }
-}
diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs
deleted file mode 100644
index cd4c149..0000000
--- a/src-tauri/src/core/hotkey.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-use crate::{config::Config, feat, log_err};
-use anyhow::{bail, Result};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::{collections::HashMap, sync::Arc};
-use tauri::{AppHandle, GlobalShortcutManager};
-use wry::application::accelerator::Accelerator;
-
-pub struct Hotkey {
- current: Arc>>, // 保存当前的热键设置
-
- app_handle: Arc>>,
-}
-
-impl Hotkey {
- pub fn global() -> &'static Hotkey {
- static HOTKEY: OnceCell = OnceCell::new();
-
- HOTKEY.get_or_init(|| Hotkey {
- current: Arc::new(Mutex::new(Vec::new())),
- app_handle: Arc::new(Mutex::new(None)),
- })
- }
-
- pub fn init(&self, app_handle: AppHandle) -> Result<()> {
- *self.app_handle.lock() = Some(app_handle);
-
- let verge = Config::verge();
-
- if let Some(hotkeys) = verge.latest().hotkeys.as_ref() {
- for hotkey in hotkeys.iter() {
- let mut iter = hotkey.split(',');
- let func = iter.next();
- let key = iter.next();
-
- match (key, func) {
- (Some(key), Some(func)) => {
- log_err!(Self::check_key(key).and_then(|_| self.register(key, func)));
- }
- _ => {
- let key = key.unwrap_or("None");
- let func = func.unwrap_or("None");
- log::error!(target: "app", "invalid hotkey `{key}`:`{func}`");
- }
- }
- }
- *self.current.lock() = hotkeys.clone();
- }
-
- Ok(())
- }
-
- /// 检查一个键是否合法
- fn check_key(hotkey: &str) -> Result<()> {
- // fix #287
- // tauri的这几个方法全部有Result expect,会panic,先检测一遍避免挂了
- if hotkey.parse::().is_err() {
- bail!("invalid hotkey `{hotkey}`");
- }
- Ok(())
- }
-
- fn get_manager(&self) -> Result {
- let app_handle = self.app_handle.lock();
- if app_handle.is_none() {
- bail!("failed to get the hotkey manager");
- }
- Ok(app_handle.as_ref().unwrap().global_shortcut_manager())
- }
-
- fn register(&self, hotkey: &str, func: &str) -> Result<()> {
- let mut manager = self.get_manager()?;
-
- if manager.is_registered(hotkey)? {
- manager.unregister(hotkey)?;
- }
-
- let f = match func.trim() {
- "open_dashboard" => || feat::open_dashboard(),
- "clash_mode_rule" => || feat::change_clash_mode("rule".into()),
- "clash_mode_global" => || feat::change_clash_mode("global".into()),
- "clash_mode_direct" => || feat::change_clash_mode("direct".into()),
- "clash_mode_script" => || feat::change_clash_mode("script".into()),
- "toggle_system_proxy" => || feat::toggle_system_proxy(),
- "enable_system_proxy" => || feat::enable_system_proxy(),
- "disable_system_proxy" => || feat::disable_system_proxy(),
- "toggle_tun_mode" => || feat::toggle_tun_mode(),
- "enable_tun_mode" => || feat::enable_tun_mode(),
- "disable_tun_mode" => || feat::disable_tun_mode(),
-
- _ => bail!("invalid function \"{func}\""),
- };
-
- manager.register(hotkey, f)?;
- log::info!(target: "app", "register hotkey {hotkey} {func}");
- Ok(())
- }
-
- fn unregister(&self, hotkey: &str) -> Result<()> {
- self.get_manager()?.unregister(&hotkey)?;
- log::info!(target: "app", "unregister hotkey {hotkey}");
- Ok(())
- }
-
- pub fn update(&self, new_hotkeys: Vec) -> Result<()> {
- let mut current = self.current.lock();
- let old_map = Self::get_map_from_vec(¤t);
- let new_map = Self::get_map_from_vec(&new_hotkeys);
-
- let (del, add) = Self::get_diff(old_map, new_map);
-
- // 先检查一遍所有新的热键是不是可以用的
- for (hotkey, _) in add.iter() {
- Self::check_key(hotkey)?;
- }
-
- del.iter().for_each(|key| {
- let _ = self.unregister(key);
- });
-
- add.iter().for_each(|(key, func)| {
- log_err!(self.register(key, func));
- });
-
- *current = new_hotkeys;
- Ok(())
- }
-
- fn get_map_from_vec<'a>(hotkeys: &'a Vec) -> HashMap<&'a str, &'a str> {
- let mut map = HashMap::new();
-
- hotkeys.iter().for_each(|hotkey| {
- let mut iter = hotkey.split(',');
- let func = iter.next();
- let key = iter.next();
-
- if func.is_some() && key.is_some() {
- let func = func.unwrap().trim();
- let key = key.unwrap().trim();
- map.insert(key, func);
- }
- });
- map
- }
-
- fn get_diff<'a>(
- old_map: HashMap<&'a str, &'a str>,
- new_map: HashMap<&'a str, &'a str>,
- ) -> (Vec<&'a str>, Vec<(&'a str, &'a str)>) {
- let mut del_list = vec![];
- let mut add_list = vec![];
-
- old_map.iter().for_each(|(&key, func)| {
- match new_map.get(key) {
- Some(new_func) => {
- if new_func != func {
- del_list.push(key);
- add_list.push((key, *new_func));
- }
- }
- None => del_list.push(key),
- };
- });
-
- new_map.iter().for_each(|(&key, &func)| {
- if old_map.get(key).is_none() {
- add_list.push((key, func));
- }
- });
-
- (del_list, add_list)
- }
-}
-
-impl Drop for Hotkey {
- fn drop(&mut self) {
- if let Ok(mut manager) = self.get_manager() {
- let _ = manager.unregister_all();
- }
- }
-}
diff --git a/src-tauri/src/core/logger.rs b/src-tauri/src/core/logger.rs
deleted file mode 100644
index b426415..0000000
--- a/src-tauri/src/core/logger.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::{collections::VecDeque, sync::Arc};
-
-const LOGS_QUEUE_LEN: usize = 100;
-
-pub struct Logger {
- log_data: Arc>>,
-}
-
-impl Logger {
- pub fn global() -> &'static Logger {
- static LOGGER: OnceCell = OnceCell::new();
-
- LOGGER.get_or_init(|| Logger {
- log_data: Arc::new(Mutex::new(VecDeque::with_capacity(LOGS_QUEUE_LEN + 10))),
- })
- }
-
- pub fn get_log(&self) -> VecDeque {
- self.log_data.lock().clone()
- }
-
- pub fn set_log(&self, text: String) {
- let mut logs = self.log_data.lock();
- if logs.len() > LOGS_QUEUE_LEN {
- logs.pop_front();
- }
- logs.push_back(text);
- }
-
- pub fn clear_log(&self) {
- let mut logs = self.log_data.lock();
- logs.clear();
- }
-}
diff --git a/src-tauri/src/core/manager.rs b/src-tauri/src/core/manager.rs
deleted file mode 100644
index fdb9269..0000000
--- a/src-tauri/src/core/manager.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use std::borrow::Cow;
-
-/// 给clash内核的tun模式授权
-#[cfg(any(target_os = "macos", target_os = "linux"))]
-pub fn grant_permission(core: String) -> anyhow::Result<()> {
- use std::process::Command;
- use tauri::utils::platform::current_exe;
-
- let path = current_exe()?.with_file_name(core).canonicalize()?;
- let path = path.display().to_string();
-
- log::debug!("grant_permission path: {path}");
-
- #[cfg(target_os = "macos")]
- let output = {
- // the path of clash /Applications/Clash Verge.app/Contents/MacOS/clash
- // https://apple.stackexchange.com/questions/82967/problem-with-empty-spaces-when-executing-shell-commands-in-applescript
- // let path = escape(&path);
- let path = path.replace(' ', "\\\\ ");
- let shell = format!("chown root:admin {path}\nchmod +sx {path}");
- let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
- Command::new("osascript")
- .args(vec!["-e", &command])
- .output()?
- };
-
- #[cfg(target_os = "linux")]
- let output = {
- let path = path.replace(' ', "\\ "); // 避免路径中有空格
- let shell = format!("setcap cap_net_bind_service,cap_net_admin=+ep {path}");
-
- let sudo = match Command::new("which").arg("pkexec").output() {
- Ok(output) => {
- if output.stdout.is_empty() {
- "sudo"
- } else {
- "pkexec"
- }
- }
- Err(_) => "sudo",
- };
-
- Command::new(sudo).arg("sh").arg("-c").arg(shell).output()?
- };
-
- if output.status.success() {
- Ok(())
- } else {
- let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
- anyhow::bail!("{stderr}");
- }
-}
-
-#[allow(unused)]
-pub fn escape<'a>(text: &'a str) -> Cow<'a, str> {
- let bytes = text.as_bytes();
-
- let mut owned = None;
-
- for pos in 0..bytes.len() {
- let special = match bytes[pos] {
- b' ' => Some(b' '),
- _ => None,
- };
- if let Some(s) = special {
- if owned.is_none() {
- owned = Some(bytes[0..pos].to_owned());
- }
- owned.as_mut().unwrap().push(b'\\');
- owned.as_mut().unwrap().push(b'\\');
- owned.as_mut().unwrap().push(s);
- } else if let Some(owned) = owned.as_mut() {
- owned.push(bytes[pos]);
- }
- }
-
- if let Some(owned) = owned {
- unsafe { Cow::Owned(String::from_utf8_unchecked(owned)) }
- } else {
- unsafe { Cow::Borrowed(std::str::from_utf8_unchecked(bytes)) }
- }
-}
diff --git a/src-tauri/src/core/mod.rs b/src-tauri/src/core/mod.rs
deleted file mode 100644
index 4221721..0000000
--- a/src-tauri/src/core/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-pub mod clash_api;
-mod core;
-pub mod handle;
-pub mod hotkey;
-pub mod logger;
-pub mod manager;
-pub mod sysopt;
-pub mod timer;
-pub mod tray;
-pub mod win_service;
-
-pub use self::core::*;
diff --git a/src-tauri/src/core/sysopt.rs b/src-tauri/src/core/sysopt.rs
deleted file mode 100644
index c43114e..0000000
--- a/src-tauri/src/core/sysopt.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use crate::{config::Config, log_err};
-use anyhow::{anyhow, Result};
-use auto_launch::{AutoLaunch, AutoLaunchBuilder};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::sync::Arc;
-use sysproxy::Sysproxy;
-use tauri::{async_runtime::Mutex as TokioMutex, utils::platform::current_exe};
-
-pub struct Sysopt {
- /// current system proxy setting
- cur_sysproxy: Arc>>,
-
- /// record the original system proxy
- /// recover it when exit
- old_sysproxy: Arc>>,
-
- /// helps to auto launch the app
- auto_launch: Arc>>,
-
- /// record whether the guard async is running or not
- guard_state: Arc>,
-}
-
-#[cfg(target_os = "windows")]
-static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;";
-#[cfg(target_os = "linux")]
-static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,::1";
-#[cfg(target_os = "macos")]
-static DEFAULT_BYPASS: &str = "127.0.0.1,localhost,";
-
-impl Sysopt {
- pub fn global() -> &'static Sysopt {
- static SYSOPT: OnceCell = OnceCell::new();
-
- SYSOPT.get_or_init(|| Sysopt {
- cur_sysproxy: Arc::new(Mutex::new(None)),
- old_sysproxy: Arc::new(Mutex::new(None)),
- auto_launch: Arc::new(Mutex::new(None)),
- guard_state: Arc::new(TokioMutex::new(false)),
- })
- }
-
- /// init the sysproxy
- pub fn init_sysproxy(&self) -> Result<()> {
- let port = { Config::clash().latest().get_mixed_port() };
-
- let (enable, bypass) = {
- let verge = Config::verge();
- let verge = verge.latest();
- (
- verge.enable_system_proxy.clone().unwrap_or(false),
- verge.system_proxy_bypass.clone(),
- )
- };
-
- let current = Sysproxy {
- enable,
- host: String::from("127.0.0.1"),
- port,
- bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()),
- };
-
- if enable {
- let old = Sysproxy::get_system_proxy().map_or(None, |p| Some(p));
- current.set_system_proxy()?;
-
- *self.old_sysproxy.lock() = old;
- *self.cur_sysproxy.lock() = Some(current);
- }
-
- // run the system proxy guard
- self.guard_proxy();
- Ok(())
- }
-
- /// update the system proxy
- pub fn update_sysproxy(&self) -> Result<()> {
- let mut cur_sysproxy = self.cur_sysproxy.lock();
- let old_sysproxy = self.old_sysproxy.lock();
-
- if cur_sysproxy.is_none() || old_sysproxy.is_none() {
- drop(cur_sysproxy);
- drop(old_sysproxy);
- return self.init_sysproxy();
- }
-
- let (enable, bypass) = {
- let verge = Config::verge();
- let verge = verge.latest();
- (
- verge.enable_system_proxy.clone().unwrap_or(false),
- verge.system_proxy_bypass.clone(),
- )
- };
- let mut sysproxy = cur_sysproxy.take().unwrap();
-
- sysproxy.enable = enable;
- sysproxy.bypass = bypass.unwrap_or(DEFAULT_BYPASS.into());
-
- sysproxy.set_system_proxy()?;
- *cur_sysproxy = Some(sysproxy);
-
- Ok(())
- }
-
- /// reset the sysproxy
- pub fn reset_sysproxy(&self) -> Result<()> {
- let mut cur_sysproxy = self.cur_sysproxy.lock();
- let mut old_sysproxy = self.old_sysproxy.lock();
-
- let cur_sysproxy = cur_sysproxy.take();
-
- if let Some(mut old) = old_sysproxy.take() {
- // 如果原代理和当前代理 端口一致,就disable关闭,否则就恢复原代理设置
- // 当前没有设置代理的时候,不确定旧设置是否和当前一致,全关了
- let port_same = cur_sysproxy.map_or(true, |cur| old.port == cur.port);
-
- if old.enable && port_same {
- old.enable = false;
- log::info!(target: "app", "reset proxy by disabling the original proxy");
- } else {
- log::info!(target: "app", "reset proxy to the original proxy");
- }
-
- old.set_system_proxy()?;
- } else if let Some(mut cur @ Sysproxy { enable: true, .. }) = cur_sysproxy {
- // 没有原代理,就按现在的代理设置disable即可
- log::info!(target: "app", "reset proxy by disabling the current proxy");
- cur.enable = false;
- cur.set_system_proxy()?;
- } else {
- log::info!(target: "app", "reset proxy with no action");
- }
-
- Ok(())
- }
-
- /// init the auto launch
- pub fn init_launch(&self) -> Result<()> {
- let enable = { Config::verge().latest().enable_auto_launch.clone() };
- let enable = enable.unwrap_or(false);
-
- let app_exe = current_exe()?;
- let app_exe = dunce::canonicalize(app_exe)?;
- let app_name = app_exe
- .file_stem()
- .and_then(|f| f.to_str())
- .ok_or(anyhow!("failed to get file stem"))?;
-
- let app_path = app_exe
- .as_os_str()
- .to_str()
- .ok_or(anyhow!("failed to get app_path"))?
- .to_string();
-
- // fix issue #26
- #[cfg(target_os = "windows")]
- let app_path = format!("\"{app_path}\"");
-
- // use the /Applications/Clash Verge.app path
- #[cfg(target_os = "macos")]
- let app_path = (|| -> Option {
- let path = std::path::PathBuf::from(&app_path);
- let path = path.parent()?.parent()?.parent()?;
- let extension = path.extension()?.to_str()?;
- match extension == "app" {
- true => Some(path.as_os_str().to_str()?.to_string()),
- false => None,
- }
- })()
- .unwrap_or(app_path);
-
- // fix #403
- #[cfg(target_os = "linux")]
- let app_path = {
- use crate::core::handle::Handle;
- use tauri::Manager;
-
- let handle = Handle::global();
- match handle.app_handle.lock().as_ref() {
- Some(app_handle) => {
- let appimage = app_handle.env().appimage;
- appimage
- .and_then(|p| p.to_str().map(|s| s.to_string()))
- .unwrap_or(app_path)
- }
- None => app_path,
- }
- };
-
- let auto = AutoLaunchBuilder::new()
- .set_app_name(app_name)
- .set_app_path(&app_path)
- .build()?;
-
- // 避免在开发时将自启动关了
- #[cfg(feature = "verge-dev")]
- if !enable {
- return Ok(());
- }
-
- #[cfg(target_os = "macos")]
- {
- if enable && !auto.is_enabled().unwrap_or(false) {
- // 避免重复设置登录项
- let _ = auto.disable();
- auto.enable()?;
- } else if !enable {
- let _ = auto.disable();
- }
- }
-
- #[cfg(not(target_os = "macos"))]
- if enable {
- auto.enable()?;
- }
-
- *self.auto_launch.lock() = Some(auto);
-
- Ok(())
- }
-
- /// update the startup
- pub fn update_launch(&self) -> Result<()> {
- let auto_launch = self.auto_launch.lock();
-
- if auto_launch.is_none() {
- drop(auto_launch);
- return self.init_launch();
- }
- let enable = { Config::verge().latest().enable_auto_launch.clone() };
- let enable = enable.unwrap_or(false);
- let auto_launch = auto_launch.as_ref().unwrap();
-
- match enable {
- true => auto_launch.enable()?,
- false => log_err!(auto_launch.disable()), // 忽略关闭的错误
- };
-
- Ok(())
- }
-
- /// launch a system proxy guard
- /// read config from file directly
- pub fn guard_proxy(&self) {
- use tokio::time::{sleep, Duration};
-
- let guard_state = self.guard_state.clone();
-
- tauri::async_runtime::spawn(async move {
- // if it is running, exit
- let mut state = guard_state.lock().await;
- if *state {
- return;
- }
- *state = true;
- drop(state);
-
- // default duration is 10s
- let mut wait_secs = 10u64;
-
- loop {
- sleep(Duration::from_secs(wait_secs)).await;
-
- let (enable, guard, guard_duration, bypass) = {
- let verge = Config::verge();
- let verge = verge.latest();
- (
- verge.enable_system_proxy.clone().unwrap_or(false),
- verge.enable_proxy_guard.clone().unwrap_or(false),
- verge.proxy_guard_duration.clone().unwrap_or(10),
- verge.system_proxy_bypass.clone(),
- )
- };
-
- // stop loop
- if !enable || !guard {
- break;
- }
-
- // update duration
- wait_secs = guard_duration;
-
- log::debug!(target: "app", "try to guard the system proxy");
-
- let port = { Config::clash().latest().get_mixed_port() };
-
- let sysproxy = Sysproxy {
- enable: true,
- host: "127.0.0.1".into(),
- port,
- bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()),
- };
-
- log_err!(sysproxy.set_system_proxy());
- }
-
- let mut state = guard_state.lock().await;
- *state = false;
- drop(state);
- });
- }
-}
diff --git a/src-tauri/src/core/timer.rs b/src-tauri/src/core/timer.rs
deleted file mode 100644
index 1b40f0f..0000000
--- a/src-tauri/src/core/timer.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-use crate::config::Config;
-use crate::feat;
-use anyhow::{Context, Result};
-use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
-use once_cell::sync::OnceCell;
-use parking_lot::Mutex;
-use std::collections::HashMap;
-use std::sync::Arc;
-
-type TaskID = u64;
-
-pub struct Timer {
- /// cron manager
- delay_timer: Arc>,
-
- /// save the current state
- timer_map: Arc>>,
-
- /// increment id
- timer_count: Arc>,
-}
-
-impl Timer {
- pub fn global() -> &'static Timer {
- static TIMER: OnceCell = OnceCell::new();
-
- TIMER.get_or_init(|| Timer {
- delay_timer: Arc::new(Mutex::new(DelayTimerBuilder::default().build())),
- timer_map: Arc::new(Mutex::new(HashMap::new())),
- timer_count: Arc::new(Mutex::new(1)),
- })
- }
-
- /// restore timer
- pub fn init(&self) -> Result<()> {
- self.refresh()?;
-
- let cur_timestamp = chrono::Local::now().timestamp();
-
- let timer_map = self.timer_map.lock();
- let delay_timer = self.delay_timer.lock();
-
- Config::profiles().latest().get_items().map(|items| {
- items
- .iter()
- .filter_map(|item| {
- // mins to seconds
- let interval = ((item.option.as_ref()?.update_interval?) as i64) * 60;
- let updated = item.updated? as i64;
-
- if interval > 0 && cur_timestamp - updated >= interval {
- Some(item)
- } else {
- None
- }
- })
- .for_each(|item| {
- if let Some(uid) = item.uid.as_ref() {
- if let Some((task_id, _)) = timer_map.get(uid) {
- crate::log_err!(delay_timer.advance_task(*task_id));
- }
- }
- })
- });
-
- Ok(())
- }
-
- /// Correctly update all cron tasks
- pub fn refresh(&self) -> Result<()> {
- let diff_map = self.gen_diff();
-
- let mut timer_map = self.timer_map.lock();
- let mut delay_timer = self.delay_timer.lock();
-
- for (uid, diff) in diff_map.into_iter() {
- match diff {
- DiffFlag::Del(tid) => {
- let _ = timer_map.remove(&uid);
- crate::log_err!(delay_timer.remove_task(tid));
- }
- DiffFlag::Add(tid, val) => {
- let _ = timer_map.insert(uid.clone(), (tid, val));
- crate::log_err!(self.add_task(&mut delay_timer, uid, tid, val));
- }
- DiffFlag::Mod(tid, val) => {
- let _ = timer_map.insert(uid.clone(), (tid, val));
- crate::log_err!(delay_timer.remove_task(tid));
- crate::log_err!(self.add_task(&mut delay_timer, uid, tid, val));
- }
- }
- }
-
- Ok(())
- }
-
- /// generate a uid -> update_interval map
- fn gen_map(&self) -> HashMap {
- let mut new_map = HashMap::new();
-
- if let Some(items) = Config::profiles().latest().get_items() {
- for item in items.iter() {
- if item.option.is_some() {
- let option = item.option.as_ref().unwrap();
- let interval = option.update_interval.unwrap_or(0);
-
- if interval > 0 {
- new_map.insert(item.uid.clone().unwrap(), interval);
- }
- }
- }
- }
-
- new_map
- }
-
- /// generate the diff map for refresh
- fn gen_diff(&self) -> HashMap {
- let mut diff_map = HashMap::new();
-
- let timer_map = self.timer_map.lock();
-
- let new_map = self.gen_map();
- let cur_map = &timer_map;
-
- cur_map.iter().for_each(|(uid, (tid, val))| {
- let new_val = new_map.get(uid).unwrap_or(&0);
-
- if *new_val == 0 {
- diff_map.insert(uid.clone(), DiffFlag::Del(*tid));
- } else if new_val != val {
- diff_map.insert(uid.clone(), DiffFlag::Mod(*tid, *new_val));
- }
- });
-
- let mut count = self.timer_count.lock();
-
- new_map.iter().for_each(|(uid, val)| {
- if cur_map.get(uid).is_none() {
- diff_map.insert(uid.clone(), DiffFlag::Add(*count, *val));
-
- *count += 1;
- }
- });
-
- diff_map
- }
-
- /// add a cron task
- fn add_task(
- &self,
- delay_timer: &mut DelayTimer,
- uid: String,
- tid: TaskID,
- minutes: u64,
- ) -> Result<()> {
- let task = TaskBuilder::default()
- .set_task_id(tid)
- .set_maximum_parallel_runnable_num(1)
- .set_frequency_repeated_by_minutes(minutes)
- // .set_frequency_repeated_by_seconds(minutes) // for test
- .spawn_async_routine(move || Self::async_task(uid.to_owned()))
- .context("failed to create timer task")?;
-
- delay_timer
- .add_task(task)
- .context("failed to add timer task")?;
-
- Ok(())
- }
-
- /// the task runner
- async fn async_task(uid: String) {
- log::info!(target: "app", "running timer task `{uid}`");
- crate::log_err!(feat::update_profile(uid, None).await);
- }
-}
-
-#[derive(Debug)]
-enum DiffFlag {
- Del(TaskID),
- Add(TaskID, u64),
- Mod(TaskID, u64),
-}
diff --git a/src-tauri/src/core/tray.rs b/src-tauri/src/core/tray.rs
deleted file mode 100644
index 307e35d..0000000
--- a/src-tauri/src/core/tray.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use crate::{cmds, config::Config, feat, utils::resolve};
-use anyhow::Result;
-use tauri::{
- api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
- SystemTraySubmenu,
-};
-
-pub struct Tray {}
-
-impl Tray {
- pub fn tray_menu(app_handle: &AppHandle) -> SystemTrayMenu {
- let zh = { Config::verge().latest().language == Some("zh".into()) };
-
- let version = app_handle.package_info().version.to_string();
-
- macro_rules! t {
- ($en: expr, $zh: expr) => {
- if zh {
- $zh
- } else {
- $en
- }
- };
- }
-
- SystemTrayMenu::new()
- .add_item(CustomMenuItem::new(
- "open_window",
- t!("Dashboard", "打开面板"),
- ))
- .add_native_item(SystemTrayMenuItem::Separator)
- .add_item(CustomMenuItem::new(
- "rule_mode",
- t!("Rule Mode", "规则模式"),
- ))
- .add_item(CustomMenuItem::new(
- "global_mode",
- t!("Global Mode", "全局模式"),
- ))
- .add_item(CustomMenuItem::new(
- "direct_mode",
- t!("Direct Mode", "直连模式"),
- ))
- .add_item(CustomMenuItem::new(
- "script_mode",
- t!("Script Mode", "脚本模式"),
- ))
- .add_native_item(SystemTrayMenuItem::Separator)
- .add_item(CustomMenuItem::new(
- "system_proxy",
- t!("System Proxy", "系统代理"),
- ))
- .add_item(CustomMenuItem::new("tun_mode", t!("TUN Mode", "Tun 模式")))
- .add_item(CustomMenuItem::new(
- "copy_env",
- t!("Copy Env", "复制环境变量"),
- ))
- .add_submenu(SystemTraySubmenu::new(
- t!("Open Dir", "打开目录"),
- SystemTrayMenu::new()
- .add_item(CustomMenuItem::new(
- "open_app_dir",
- t!("App Dir", "应用目录"),
- ))
- .add_item(CustomMenuItem::new(
- "open_core_dir",
- t!("Core Dir", "内核目录"),
- ))
- .add_item(CustomMenuItem::new(
- "open_logs_dir",
- t!("Logs Dir", "日志目录"),
- )),
- ))
- .add_submenu(SystemTraySubmenu::new(
- t!("More", "更多"),
- SystemTrayMenu::new()
- .add_item(CustomMenuItem::new(
- "restart_clash",
- t!("Restart Clash", "重启 Clash"),
- ))
- .add_item(CustomMenuItem::new(
- "restart_app",
- t!("Restart App", "重启应用"),
- ))
- .add_item(
- CustomMenuItem::new("app_version", format!("Version {version}")).disabled(),
- ),
- ))
- .add_native_item(SystemTrayMenuItem::Separator)
- .add_item(CustomMenuItem::new("quit", t!("Quit", "退出")).accelerator("CmdOrControl+Q"))
- }
-
- pub fn update_systray(app_handle: &AppHandle) -> Result<()> {
- app_handle
- .tray_handle()
- .set_menu(Tray::tray_menu(app_handle))?;
- Tray::update_part(app_handle)?;
- Ok(())
- }
-
- pub fn update_part(app_handle: &AppHandle) -> Result<()> {
- let mode = {
- Config::clash()
- .latest()
- .0
- .get("mode")
- .map(|val| val.as_str().unwrap_or("rule"))
- .unwrap_or("rule")
- .to_owned()
- };
-
- let tray = app_handle.tray_handle();
-
- let _ = tray.get_item("rule_mode").set_selected(mode == "rule");
- let _ = tray.get_item("global_mode").set_selected(mode == "global");
- let _ = tray.get_item("direct_mode").set_selected(mode == "direct");
- let _ = tray.get_item("script_mode").set_selected(mode == "script");
-
- let verge = Config::verge();
- let verge = verge.latest();
- let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
- let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
-
- #[cfg(target_os = "windows")]
- {
- let indication_icon = if *system_proxy {
- include_bytes!("../../icons/win-tray-icon-activated.png").to_vec()
- } else {
- include_bytes!("../../icons/win-tray-icon.png").to_vec()
- };
-
- let _ = tray.set_icon(tauri::Icon::Raw(indication_icon));
- }
-
- let _ = tray.get_item("system_proxy").set_selected(*system_proxy);
- let _ = tray.get_item("tun_mode").set_selected(*tun_mode);
-
- Ok(())
- }
-
- pub fn on_system_tray_event(app_handle: &AppHandle, event: SystemTrayEvent) {
- match event {
- SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
- mode @ ("rule_mode" | "global_mode" | "direct_mode" | "script_mode") => {
- let mode = &mode[0..mode.len() - 5];
- feat::change_clash_mode(mode.into());
- }
-
- "open_window" => resolve::create_window(app_handle),
- "system_proxy" => feat::toggle_system_proxy(),
- "tun_mode" => feat::toggle_tun_mode(),
- "copy_env" => feat::copy_clash_env(),
- "open_app_dir" => crate::log_err!(cmds::open_app_dir()),
- "open_core_dir" => crate::log_err!(cmds::open_core_dir()),
- "open_logs_dir" => crate::log_err!(cmds::open_logs_dir()),
- "restart_clash" => feat::restart_clash_core(),
- "restart_app" => api::process::restart(&app_handle.env()),
- "quit" => {
- let _ = resolve::save_window_size_position(app_handle, true);
-
- resolve::resolve_reset();
- api::process::kill_children();
- app_handle.exit(0);
- std::process::exit(0);
- }
- _ => {}
- },
- #[cfg(target_os = "windows")]
- SystemTrayEvent::LeftClick { .. } => {
- resolve::create_window(app_handle);
- }
- _ => {}
- }
- }
-}
diff --git a/src-tauri/src/core/win_service.rs b/src-tauri/src/core/win_service.rs
deleted file mode 100644
index 865895b..0000000
--- a/src-tauri/src/core/win_service.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-#![cfg(target_os = "windows")]
-
-use crate::config::Config;
-use crate::utils::dirs;
-use anyhow::{bail, Context, Result};
-use deelevate::{PrivilegeLevel, Token};
-use runas::Command as RunasCommand;
-use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
-use std::os::windows::process::CommandExt;
-use std::path::PathBuf;
-use std::time::Duration;
-use std::{env::current_exe, process::Command as StdCommand};
-use tokio::time::sleep;
-
-const SERVICE_URL: &str = "http://127.0.0.1:33211";
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct ResponseBody {
- pub core_type: Option,
- pub bin_path: String,
- pub config_dir: String,
- pub log_file: String,
-}
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct JsonResponse {
- pub code: u64,
- pub msg: String,
- pub data: Option,
-}
-
-/// Install the Clash Verge Service
-/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
-pub async fn install_service() -> Result<()> {
- let binary_path = dirs::service_path()?;
- let install_path = binary_path.with_file_name("install-service.exe");
-
- if !install_path.exists() {
- bail!("installer exe not found");
- }
-
- let token = Token::with_current_process()?;
- let level = token.privilege_level()?;
-
- let status = match level {
- PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).show(false).status()?,
- _ => StdCommand::new(install_path)
- .creation_flags(0x08000000)
- .status()?,
- };
-
- if !status.success() {
- bail!(
- "failed to install service with status {}",
- status.code().unwrap()
- );
- }
-
- Ok(())
-}
-
-/// Uninstall the Clash Verge Service
-/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
-pub async fn uninstall_service() -> Result<()> {
- let binary_path = dirs::service_path()?;
- let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
-
- if !uninstall_path.exists() {
- bail!("uninstaller exe not found");
- }
-
- let token = Token::with_current_process()?;
- let level = token.privilege_level()?;
-
- let status = match level {
- PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).show(false).status()?,
- _ => StdCommand::new(uninstall_path)
- .creation_flags(0x08000000)
- .status()?,
- };
-
- if !status.success() {
- bail!(
- "failed to uninstall service with status {}",
- status.code().unwrap()
- );
- }
-
- Ok(())
-}
-
-/// check the windows service status
-pub async fn check_service() -> Result {
- let url = format!("{SERVICE_URL}/get_clash");
- let response = reqwest::ClientBuilder::new()
- .no_proxy()
- .build()?
- .get(url)
- .send()
- .await
- .context("failed to connect to the Clash Verge Service")?
- .json::()
- .await
- .context("failed to parse the Clash Verge Service response")?;
-
- Ok(response)
-}
-
-/// start the clash by service
-pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
- let status = check_service().await?;
-
- if status.code == 0 {
- stop_core_by_service().await?;
- sleep(Duration::from_secs(1)).await;
- }
-
- let clash_core = { Config::verge().latest().clash_core.clone() };
- let clash_core = clash_core.unwrap_or("clash".into());
-
- let clash_bin = format!("{clash_core}.exe");
- let bin_path = current_exe()?.with_file_name(clash_bin);
- let bin_path = dirs::path_to_str(&bin_path)?;
-
- let config_dir = dirs::app_home_dir()?;
- let config_dir = dirs::path_to_str(&config_dir)?;
-
- let log_path = dirs::service_log_file()?;
- let log_path = dirs::path_to_str(&log_path)?;
-
- let config_file = dirs::path_to_str(config_file)?;
-
- let mut map = HashMap::new();
- map.insert("core_type", clash_core.as_str());
- map.insert("bin_path", bin_path);
- map.insert("config_dir", config_dir);
- map.insert("config_file", config_file);
- map.insert("log_file", log_path);
-
- let url = format!("{SERVICE_URL}/start_clash");
- let res = reqwest::ClientBuilder::new()
- .no_proxy()
- .build()?
- .post(url)
- .json(&map)
- .send()
- .await?
- .json::()
- .await
- .context("failed to connect to the Clash Verge Service")?;
-
- if res.code != 0 {
- bail!(res.msg);
- }
-
- Ok(())
-}
-
-/// stop the clash by service
-pub(super) async fn stop_core_by_service() -> Result<()> {
- let url = format!("{SERVICE_URL}/stop_clash");
- let res = reqwest::ClientBuilder::new()
- .no_proxy()
- .build()?
- .post(url)
- .send()
- .await?
- .json::()
- .await
- .context("failed to connect to the Clash Verge Service")?;
-
- if res.code != 0 {
- bail!(res.msg);
- }
-
- Ok(())
-}
diff --git a/src-tauri/src/enhance/builtin/meta_guard.js b/src-tauri/src/enhance/builtin/meta_guard.js
deleted file mode 100644
index be4183b..0000000
--- a/src-tauri/src/enhance/builtin/meta_guard.js
+++ /dev/null
@@ -1,6 +0,0 @@
-function main(params) {
- if (params.mode === "script") {
- params.mode = "rule";
- }
- return params;
-}
diff --git a/src-tauri/src/enhance/builtin/meta_hy_alpn.js b/src-tauri/src/enhance/builtin/meta_hy_alpn.js
deleted file mode 100644
index da1fac0..0000000
--- a/src-tauri/src/enhance/builtin/meta_hy_alpn.js
+++ /dev/null
@@ -1,10 +0,0 @@
-function main(params) {
- if (Array.isArray(params.proxies)) {
- params.proxies.forEach((p, i) => {
- if (p.type === "hysteria" && typeof p.alpn === "string") {
- params.proxies[i].alpn = [p.alpn];
- }
- });
- }
- return params;
-}
diff --git a/src-tauri/src/enhance/chain.rs b/src-tauri/src/enhance/chain.rs
deleted file mode 100644
index 75c61fb..0000000
--- a/src-tauri/src/enhance/chain.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use crate::{
- config::PrfItem,
- utils::{dirs, help},
-};
-use serde_yaml::Mapping;
-use std::fs;
-
-#[derive(Debug, Clone)]
-pub struct ChainItem {
- pub uid: String,
- pub data: ChainType,
-}
-
-#[derive(Debug, Clone)]
-pub enum ChainType {
- Merge(Mapping),
- Script(String),
-}
-
-#[derive(Debug, Clone)]
-pub enum ChainSupport {
- Clash,
- ClashMeta,
- All,
-}
-
-impl From<&PrfItem> for Option {
- fn from(item: &PrfItem) -> Self {
- let itype = item.itype.as_ref()?.as_str();
- let file = item.file.clone()?;
- let uid = item.uid.clone().unwrap_or("".into());
- let path = dirs::app_profiles_dir().ok()?.join(file);
-
- if !path.exists() {
- return None;
- }
-
- match itype {
- "script" => Some(ChainItem {
- uid,
- data: ChainType::Script(fs::read_to_string(path).ok()?),
- }),
- "merge" => Some(ChainItem {
- uid,
- data: ChainType::Merge(help::read_merge_mapping(&path).ok()?),
- }),
- _ => None,
- }
- }
-}
-
-impl ChainItem {
- /// 内建支持一些脚本
- pub fn builtin() -> Vec<(ChainSupport, ChainItem)> {
- // meta 的一些处理
- let meta_guard =
- ChainItem::to_script("verge_meta_guard", include_str!("./builtin/meta_guard.js"));
-
- // meta 1.13.2 alpn string 转 数组
- let hy_alpn =
- ChainItem::to_script("verge_hy_alpn", include_str!("./builtin/meta_hy_alpn.js"));
-
- vec![
- (ChainSupport::ClashMeta, hy_alpn),
- (ChainSupport::ClashMeta, meta_guard),
- ]
- }
-
- pub fn to_script, D: Into>(uid: U, data: D) -> Self {
- Self {
- uid: uid.into(),
- data: ChainType::Script(data.into()),
- }
- }
-}
-
-impl ChainSupport {
- pub fn is_support(&self, core: Option<&String>) -> bool {
- match core {
- Some(core) => match (self, core.as_str()) {
- (ChainSupport::All, _) => true,
- (ChainSupport::Clash, "clash") => true,
- (ChainSupport::ClashMeta, "clash-meta") => true,
- _ => false,
- },
- None => true,
- }
- }
-}
diff --git a/src-tauri/src/enhance/field.rs b/src-tauri/src/enhance/field.rs
deleted file mode 100644
index 2130b41..0000000
--- a/src-tauri/src/enhance/field.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use serde_yaml::{Mapping, Value};
-use std::collections::HashSet;
-
-pub const HANDLE_FIELDS: [&str; 9] = [
- "mode",
- "port",
- "socks-port",
- "mixed-port",
- "allow-lan",
- "log-level",
- "ipv6",
- "secret",
- "external-controller",
-];
-
-pub const DEFAULT_FIELDS: [&str; 5] = [
- "proxies",
- "proxy-groups",
- "proxy-providers",
- "rules",
- "rule-providers",
-];
-
-pub const OTHERS_FIELDS: [&str; 30] = [
- "dns",
- "tun",
- "ebpf",
- "hosts",
- "script",
- "profile",
- "payload",
- "tunnels",
- "auto-redir",
- "experimental",
- "interface-name",
- "routing-mark",
- "redir-port",
- "tproxy-port",
- "iptables",
- "external-ui",
- "bind-address",
- "authentication",
- "tls", // meta
- "sniffer", // meta
- "geox-url", // meta
- "listeners", // meta
- "sub-rules", // meta
- "geodata-mode", // meta
- "unified-delay", // meta
- "tcp-concurrent", // meta
- "enable-process", // meta
- "find-process-mode", // meta
- "external-controller-tls", // meta
- "global-client-fingerprint", // meta
-];
-
-pub fn use_clash_fields() -> Vec {
- DEFAULT_FIELDS
- .into_iter()
- .chain(HANDLE_FIELDS)
- .chain(OTHERS_FIELDS)
- .map(|s| s.to_string())
- .collect()
-}
-
-pub fn use_valid_fields(mut valid: Vec) -> Vec {
- let others = Vec::from(OTHERS_FIELDS);
-
- valid.iter_mut().for_each(|s| s.make_ascii_lowercase());
- valid
- .into_iter()
- .filter(|s| others.contains(&s.as_str()))
- .chain(DEFAULT_FIELDS.iter().map(|s| s.to_string()))
- .collect()
-}
-
-pub fn use_filter(config: Mapping, filter: &Vec, enable: bool) -> Mapping {
- if !enable {
- return config;
- }
-
- let mut ret = Mapping::new();
-
- for (key, value) in config.into_iter() {
- if let Some(key) = key.as_str() {
- if filter.contains(&key.to_string()) {
- ret.insert(Value::from(key), value);
- }
- }
- }
- ret
-}
-
-pub fn use_lowercase(config: Mapping) -> Mapping {
- let mut ret = Mapping::new();
-
- for (key, value) in config.into_iter() {
- if let Some(key_str) = key.as_str() {
- let mut key_str = String::from(key_str);
- key_str.make_ascii_lowercase();
- ret.insert(Value::from(key_str), value);
- }
- }
- ret
-}
-
-pub fn use_sort(config: Mapping, enable_filter: bool) -> Mapping {
- let mut ret = Mapping::new();
-
- HANDLE_FIELDS
- .into_iter()
- .chain(OTHERS_FIELDS)
- .chain(DEFAULT_FIELDS)
- .for_each(|key| {
- let key = Value::from(key);
- config.get(&key).map(|value| {
- ret.insert(key, value.clone());
- });
- });
-
- if !enable_filter {
- let supported_keys: HashSet<&str> = HANDLE_FIELDS
- .into_iter()
- .chain(OTHERS_FIELDS)
- .chain(DEFAULT_FIELDS)
- .collect();
-
- let config_keys: HashSet<&str> = config
- .keys()
- .filter_map(|e| e.as_str())
- .into_iter()
- .collect();
-
- config_keys.difference(&supported_keys).for_each(|&key| {
- let key = Value::from(key);
- config.get(&key).map(|value| {
- ret.insert(key, value.clone());
- });
- });
- }
-
- ret
-}
-
-pub fn use_keys(config: &Mapping) -> Vec {
- config
- .iter()
- .filter_map(|(key, _)| key.as_str())
- .map(|s| {
- let mut s = s.to_string();
- s.make_ascii_lowercase();
- return s;
- })
- .collect()
-}
diff --git a/src-tauri/src/enhance/merge.rs b/src-tauri/src/enhance/merge.rs
deleted file mode 100644
index 20342c9..0000000
--- a/src-tauri/src/enhance/merge.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-use super::{use_filter, use_lowercase};
-use serde_yaml::{self, Mapping, Sequence, Value};
-
-const MERGE_FIELDS: [&str; 6] = [
- "prepend-rules",
- "append-rules",
- "prepend-proxies",
- "append-proxies",
- "prepend-proxy-groups",
- "append-proxy-groups",
-];
-
-pub fn use_merge(merge: Mapping, mut config: Mapping) -> Mapping {
- // 直接覆盖原字段
- use_lowercase(merge.clone())
- .into_iter()
- .for_each(|(key, value)| {
- config.insert(key, value);
- });
-
- let merge_list = MERGE_FIELDS.iter().map(|s| s.to_string());
- let merge = use_filter(merge, &merge_list.collect(), true);
-
- ["rules", "proxies", "proxy-groups"]
- .iter()
- .for_each(|key_str| {
- let key_val = Value::from(key_str.to_string());
-
- let mut list = Sequence::default();
- list = config.get(&key_val).map_or(list.clone(), |val| {
- val.as_sequence().map_or(list, |v| v.clone())
- });
-
- let pre_key = Value::from(format!("prepend-{key_str}"));
- let post_key = Value::from(format!("append-{key_str}"));
-
- if let Some(pre_val) = merge.get(&pre_key) {
- if pre_val.is_sequence() {
- let mut pre_val = pre_val.as_sequence().unwrap().clone();
- pre_val.extend(list);
- list = pre_val;
- }
- }
-
- if let Some(post_val) = merge.get(&post_key) {
- if post_val.is_sequence() {
- list.extend(post_val.as_sequence().unwrap().clone());
- }
- }
-
- config.insert(key_val, Value::from(list));
- });
- config
-}
-
-#[test]
-fn test_merge() -> anyhow::Result<()> {
- let merge = r"
- prepend-rules:
- - prepend
- - 1123123
- append-rules:
- - append
- prepend-proxies:
- - 9999
- append-proxies:
- - 1111
- rules:
- - replace
- proxy-groups:
- - 123781923810
- tun:
- enable: true
- dns:
- enable: true
- ";
-
- let config = r"
- rules:
- - aaaaa
- script1: test
- ";
-
- let merge = serde_yaml::from_str::(merge)?;
- let config = serde_yaml::from_str::(config)?;
-
- let result = serde_yaml::to_string(&use_merge(merge, config))?;
-
- println!("{result}");
-
- Ok(())
-}
diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs
deleted file mode 100644
index 0a41400..0000000
--- a/src-tauri/src/enhance/mod.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-mod chain;
-mod field;
-mod merge;
-mod script;
-mod tun;
-
-pub(self) use self::field::*;
-
-use self::chain::*;
-use self::merge::*;
-use self::script::*;
-use self::tun::*;
-use crate::config::Config;
-use serde_yaml::Mapping;
-use std::collections::HashMap;
-use std::collections::HashSet;
-
-type ResultLog = Vec<(String, String)>;
-
-/// Enhance mode
-/// 返回最终配置、该配置包含的键、和script执行的结果
-pub fn enhance() -> (Mapping, Vec, HashMap) {
- // config.yaml 的配置
- let clash_config = { Config::clash().latest().0.clone() };
-
- let (clash_core, enable_tun, enable_builtin, enable_filter) = {
- let verge = Config::verge();
- let verge = verge.latest();
- (
- verge.clash_core.clone(),
- verge.enable_tun_mode.clone().unwrap_or(false),
- verge.enable_builtin_enhanced.clone().unwrap_or(true),
- verge.enable_clash_fields.clone().unwrap_or(true),
- )
- };
-
- // 从profiles里拿东西
- let (mut config, chain, valid) = {
- let profiles = Config::profiles();
- let profiles = profiles.latest();
-
- let current = profiles.current_mapping().unwrap_or(Mapping::new());
-
- let chain = match profiles.chain.as_ref() {
- Some(chain) => chain
- .iter()
- .filter_map(|uid| profiles.get_item(uid).ok())
- .filter_map(|item| >::from(item))
- .collect::>(),
- None => vec![],
- };
-
- let valid = profiles.valid.clone().unwrap_or(vec![]);
-
- (current, chain, valid)
- };
-
- let mut result_map = HashMap::new(); // 保存脚本日志
- let mut exists_keys = use_keys(&config); // 保存出现过的keys
-
- let valid = use_valid_fields(valid);
- config = use_filter(config, &valid, enable_filter);
-
- // 处理用户的profile
- chain.into_iter().for_each(|item| match item.data {
- ChainType::Merge(merge) => {
- exists_keys.extend(use_keys(&merge));
- config = use_merge(merge, config.to_owned());
- config = use_filter(config.to_owned(), &valid, enable_filter);
- }
- ChainType::Script(script) => {
- let mut logs = vec![];
-
- match use_script(script, config.to_owned()) {
- Ok((res_config, res_logs)) => {
- exists_keys.extend(use_keys(&res_config));
- config = use_filter(res_config, &valid, enable_filter);
- logs.extend(res_logs);
- }
- Err(err) => logs.push(("exception".into(), err.to_string())),
- }
-
- result_map.insert(item.uid, logs);
- }
- });
-
- // 合并默认的config
- for (key, value) in clash_config.into_iter() {
- config.insert(key, value);
- }
-
- let clash_fields = use_clash_fields();
-
- // 内建脚本最后跑
- if enable_builtin {
- ChainItem::builtin()
- .into_iter()
- .filter(|(s, _)| s.is_support(clash_core.as_ref()))
- .map(|(_, c)| c)
- .for_each(|item| {
- log::debug!(target: "app", "run builtin script {}", item.uid);
-
- match item.data {
- ChainType::Script(script) => match use_script(script, config.to_owned()) {
- Ok((res_config, _)) => {
- config = use_filter(res_config, &clash_fields, enable_filter);
- }
- Err(err) => {
- log::error!(target: "app", "builtin script error `{err}`");
- }
- },
- _ => {}
- }
- });
- }
-
- config = use_filter(config, &clash_fields, enable_filter);
- config = use_tun(config, enable_tun);
- config = use_sort(config, enable_filter);
-
- let mut exists_set = HashSet::new();
- exists_set.extend(exists_keys.into_iter().filter(|s| clash_fields.contains(s)));
- exists_keys = exists_set.into_iter().collect();
-
- (config, exists_keys, result_map)
-}
diff --git a/src-tauri/src/enhance/script.rs b/src-tauri/src/enhance/script.rs
deleted file mode 100644
index 97b34c2..0000000
--- a/src-tauri/src/enhance/script.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use super::use_lowercase;
-use anyhow::Result;
-use serde_yaml::Mapping;
-
-pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(String, String)>)> {
- use rquickjs::{Context, Func, Runtime};
- use std::sync::{Arc, Mutex};
-
- let runtime = Runtime::new().unwrap();
- let context = Context::full(&runtime).unwrap();
- let outputs = Arc::new(Mutex::new(vec![]));
-
- let copy_outputs = outputs.clone();
- let result = context.with(|ctx| -> Result {
- ctx.globals().set(
- "__verge_log__",
- Func::from(move |level: String, data: String| {
- let mut out = copy_outputs.lock().unwrap();
- out.push((level, data));
- }),
- )?;
-
- ctx.eval(
- r#"var console = Object.freeze({
- log(data){__verge_log__("log",JSON.stringify(data))},
- info(data){__verge_log__("info",JSON.stringify(data))},
- error(data){__verge_log__("error",JSON.stringify(data))},
- debug(data){__verge_log__("debug",JSON.stringify(data))},
- });"#,
- )?;
-
- let config = use_lowercase(config.clone());
- let config_str = serde_json::to_string(&config)?;
-
- let code = format!(
- r#"try{{
- {script};
- JSON.stringify(main({config_str})||'')
- }} catch(err) {{
- `__error_flag__ ${{err.toString()}}`
- }}"#
- );
- let result: String = ctx.eval(code.as_str())?;
- if result.starts_with("__error_flag__") {
- anyhow::bail!(result[15..].to_owned());
- }
- if result == "\"\"" {
- anyhow::bail!("main function should return object");
- }
- return Ok(serde_json::from_str::(result.as_str())?);
- });
-
- let mut out = outputs.lock().unwrap();
- match result {
- Ok(config) => Ok((use_lowercase(config), out.to_vec())),
- Err(err) => {
- out.push(("exception".into(), err.to_string()));
- Ok((config, out.to_vec()))
- }
- }
-}
-
-#[test]
-fn test_script() {
- let script = r#"
- function main(config) {
- if (Array.isArray(config.rules)) {
- config.rules = [...config.rules, "add"];
- }
- console.log(config);
- config.proxies = ["111"];
- return config;
- }
- "#;
-
- let config = r#"
- rules:
- - 111
- - 222
- tun:
- enable: false
- dns:
- enable: false
- "#;
-
- let config = serde_yaml::from_str(config).unwrap();
- let (config, results) = use_script(script.into(), config).unwrap();
-
- let config_str = serde_yaml::to_string(&config).unwrap();
-
- println!("{config_str}");
-
- dbg!(results);
-}
diff --git a/src-tauri/src/enhance/tun.rs b/src-tauri/src/enhance/tun.rs
deleted file mode 100644
index b72823a..0000000
--- a/src-tauri/src/enhance/tun.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use serde_yaml::{Mapping, Value};
-
-macro_rules! revise {
- ($map: expr, $key: expr, $val: expr) => {
- let ret_key = Value::String($key.into());
- $map.insert(ret_key, Value::from($val));
- };
-}
-
-// if key not exists then append value
-macro_rules! append {
- ($map: expr, $key: expr, $val: expr) => {
- let ret_key = Value::String($key.into());
- if !$map.contains_key(&ret_key) {
- $map.insert(ret_key, Value::from($val));
- }
- };
-}
-
-pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
- let tun_key = Value::from("tun");
- let tun_val = config.get(&tun_key);
-
- if !enable && tun_val.is_none() {
- return config;
- }
-
- let mut tun_val = tun_val.map_or(Mapping::new(), |val| {
- val.as_mapping().cloned().unwrap_or(Mapping::new())
- });
-
- revise!(tun_val, "enable", enable);
- if enable {
- append!(tun_val, "stack", "gvisor");
- append!(tun_val, "dns-hijack", vec!["any:53"]);
- append!(tun_val, "auto-route", true);
- append!(tun_val, "auto-detect-interface", true);
- }
-
- revise!(config, "tun", tun_val);
-
- if enable {
- use_dns_for_tun(config)
- } else {
- config
- }
-}
-
-fn use_dns_for_tun(mut config: Mapping) -> Mapping {
- let dns_key = Value::from("dns");
- let dns_val = config.get(&dns_key);
-
- let mut dns_val = dns_val.map_or(Mapping::new(), |val| {
- val.as_mapping().cloned().unwrap_or(Mapping::new())
- });
-
- // 开启tun将同时开启dns
- revise!(dns_val, "enable", true);
-
- append!(dns_val, "enhanced-mode", "fake-ip");
- append!(dns_val, "fake-ip-range", "198.18.0.1/16");
- append!(
- dns_val,
- "nameserver",
- vec!["114.114.114.114", "223.5.5.5", "8.8.8.8"]
- );
- append!(dns_val, "fallback", vec![] as Vec<&str>);
-
- #[cfg(target_os = "windows")]
- append!(
- dns_val,
- "fake-ip-filter",
- vec![
- "dns.msftncsi.com",
- "www.msftncsi.com",
- "www.msftconnecttest.com"
- ]
- );
- revise!(config, "dns", dns_val);
- config
-}
diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs
deleted file mode 100644
index a446c27..0000000
--- a/src-tauri/src/feat.rs
+++ /dev/null
@@ -1,341 +0,0 @@
-//!
-//! feat mod 里的函数主要用于
-//! - hotkey 快捷键
-//! - timer 定时器
-//! - cmds 页面调用
-//!
-use crate::config::*;
-use crate::core::*;
-use crate::log_err;
-use crate::utils::resolve;
-use anyhow::{bail, Result};
-use serde_yaml::{Mapping, Value};
-use wry::application::clipboard::Clipboard;
-
-// 打开面板
-pub fn open_dashboard() {
- let handle = handle::Handle::global();
- let app_handle = handle.app_handle.lock();
- if let Some(app_handle) = app_handle.as_ref() {
- resolve::create_window(app_handle);
- }
-}
-
-// 重启clash
-pub fn restart_clash_core() {
- tauri::async_runtime::spawn(async {
- match CoreManager::global().run_core().await {
- Ok(_) => {
- handle::Handle::refresh_clash();
- handle::Handle::notice_message("set_config::ok", "ok");
- }
- Err(err) => {
- handle::Handle::notice_message("set_config::error", format!("{err}"));
- log::error!(target:"app", "{err}");
- }
- }
- });
-}
-
-// 切换模式 rule/global/direct/script mode
-pub fn change_clash_mode(mode: String) {
- let mut mapping = Mapping::new();
- mapping.insert(Value::from("mode"), mode.clone().into());
-
- tauri::async_runtime::spawn(async move {
- log::debug!(target: "app", "change clash mode to {mode}");
-
- match clash_api::patch_configs(&mapping).await {
- Ok(_) => {
- // 更新配置
- Config::clash().data().patch_config(mapping);
-
- if Config::clash().data().save_config().is_ok() {
- handle::Handle::refresh_clash();
- log_err!(handle::Handle::update_systray_part());
- }
- }
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-// 切换系统代理
-pub fn toggle_system_proxy() {
- let enable = Config::verge().draft().enable_system_proxy.clone();
- let enable = enable.unwrap_or(false);
-
- tauri::async_runtime::spawn(async move {
- match patch_verge(IVerge {
- enable_system_proxy: Some(!enable),
- ..IVerge::default()
- })
- .await
- {
- Ok(_) => handle::Handle::refresh_verge(),
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-// 打开系统代理
-pub fn enable_system_proxy() {
- tauri::async_runtime::spawn(async {
- match patch_verge(IVerge {
- enable_system_proxy: Some(true),
- ..IVerge::default()
- })
- .await
- {
- Ok(_) => handle::Handle::refresh_verge(),
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-// 关闭系统代理
-pub fn disable_system_proxy() {
- tauri::async_runtime::spawn(async {
- match patch_verge(IVerge {
- enable_system_proxy: Some(false),
- ..IVerge::default()
- })
- .await
- {
- Ok(_) => handle::Handle::refresh_verge(),
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-// 切换tun模式
-pub fn toggle_tun_mode() {
- let enable = Config::verge().data().enable_tun_mode.clone();
- let enable = enable.unwrap_or(false);
-
- tauri::async_runtime::spawn(async move {
- match patch_verge(IVerge {
- enable_tun_mode: Some(!enable),
- ..IVerge::default()
- })
- .await
- {
- Ok(_) => handle::Handle::refresh_verge(),
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-// 打开tun模式
-pub fn enable_tun_mode() {
- tauri::async_runtime::spawn(async {
- match patch_verge(IVerge {
- enable_tun_mode: Some(true),
- ..IVerge::default()
- })
- .await
- {
- Ok(_) => handle::Handle::refresh_verge(),
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-// 关闭tun模式
-pub fn disable_tun_mode() {
- tauri::async_runtime::spawn(async {
- match patch_verge(IVerge {
- enable_tun_mode: Some(false),
- ..IVerge::default()
- })
- .await
- {
- Ok(_) => handle::Handle::refresh_verge(),
- Err(err) => log::error!(target: "app", "{err}"),
- }
- });
-}
-
-/// 修改clash的配置
-pub async fn patch_clash(patch: Mapping) -> Result<()> {
- Config::clash().draft().patch_config(patch.clone());
-
- match {
- let mixed_port = patch.get("mixed-port");
- if mixed_port.is_some() {
- let changed = mixed_port != Config::clash().data().0.get("mixed-port");
- // 检查端口占用
- if changed {
- if let Some(port) = mixed_port.clone().unwrap().as_u64() {
- if !port_scanner::local_port_available(port as u16) {
- Config::clash().discard();
- bail!("port already in use");
- }
- }
- }
- };
-
- // 激活配置
- if mixed_port.is_some()
- || patch.get("secret").is_some()
- || patch.get("external-controller").is_some()
- {
- Config::generate()?;
- CoreManager::global().run_core().await?;
- handle::Handle::refresh_clash();
- }
-
- // 更新系统代理
- if mixed_port.is_some() {
- log_err!(sysopt::Sysopt::global().init_sysproxy());
- }
-
- if patch.get("mode").is_some() {
- log_err!(handle::Handle::update_systray_part());
- }
-
- Config::runtime().latest().patch_config(patch);
-
- >::Ok(())
- } {
- Ok(()) => {
- Config::clash().apply();
- Config::clash().data().save_config()?;
- Ok(())
- }
- Err(err) => {
- Config::clash().discard();
- Err(err)
- }
- }
-}
-
-/// 修改verge的配置
-/// 一般都是一个个的修改
-pub async fn patch_verge(patch: IVerge) -> Result<()> {
- Config::verge().draft().patch_config(patch.clone());
-
- let tun_mode = patch.enable_tun_mode;
- let auto_launch = patch.enable_auto_launch;
- let system_proxy = patch.enable_system_proxy;
- let proxy_bypass = patch.system_proxy_bypass;
- let language = patch.language;
-
- match {
- #[cfg(target_os = "windows")]
- {
- let service_mode = patch.enable_service_mode;
-
- if service_mode.is_some() {
- log::debug!(target: "app", "change service mode to {}", service_mode.unwrap());
-
- Config::generate()?;
- CoreManager::global().run_core().await?;
- } else if tun_mode.is_some() {
- update_core_config().await?;
- }
- }
-
- #[cfg(not(target_os = "windows"))]
- if tun_mode.is_some() {
- update_core_config().await?;
- }
-
- if auto_launch.is_some() {
- sysopt::Sysopt::global().update_launch()?;
- }
- if system_proxy.is_some() || proxy_bypass.is_some() {
- sysopt::Sysopt::global().update_sysproxy()?;
- sysopt::Sysopt::global().guard_proxy();
- }
-
- if let Some(true) = patch.enable_proxy_guard {
- sysopt::Sysopt::global().guard_proxy();
- }
-
- if let Some(hotkeys) = patch.hotkeys {
- hotkey::Hotkey::global().update(hotkeys)?;
- }
-
- if language.is_some() {
- handle::Handle::update_systray()?;
- } else if system_proxy.or(tun_mode).is_some() {
- handle::Handle::update_systray_part()?;
- }
-
- >::Ok(())
- } {
- Ok(()) => {
- Config::verge().apply();
- Config::verge().data().save_file()?;
- Ok(())
- }
- Err(err) => {
- Config::verge().discard();
- Err(err)
- }
- }
-}
-
-/// 更新某个profile
-/// 如果更新当前配置就激活配置
-pub async fn update_profile(uid: String, option: Option) -> Result<()> {
- let url_opt = {
- let profiles = Config::profiles();
- let profiles = profiles.latest();
- let item = profiles.get_item(&uid)?;
- let is_remote = item.itype.as_ref().map_or(false, |s| s == "remote");
-
- if !is_remote {
- None // 直接更新
- } else if item.url.is_none() {
- bail!("failed to get the profile item url");
- } else {
- Some((item.url.clone().unwrap(), item.option.clone()))
- }
- };
-
- let should_update = match url_opt {
- Some((url, opt)) => {
- let merged_opt = PrfOption::merge(opt, option);
- let item = PrfItem::from_url(&url, None, None, merged_opt).await?;
-
- let profiles = Config::profiles();
- let mut profiles = profiles.latest();
- profiles.update_item(uid.clone(), item)?;
-
- Some(uid) == profiles.get_current()
- }
- None => true,
- };
-
- if should_update {
- update_core_config().await?;
- }
-
- Ok(())
-}
-
-/// 更新配置
-async fn update_core_config() -> Result<()> {
- match CoreManager::global().update_config().await {
- Ok(_) => {
- handle::Handle::refresh_clash();
- handle::Handle::notice_message("set_config::ok", "ok");
- Ok(())
- }
- Err(err) => {
- handle::Handle::notice_message("set_config::error", format!("{err}"));
- Err(err)
- }
- }
-}
-
-/// copy env variable
-pub fn copy_clash_env() {
- let port = { Config::clash().data().get_client_info().port };
- let text = format!("export https_proxy=http://127.0.0.1:{port} http_proxy=http://127.0.0.1:{port} all_proxy=socks5://127.0.0.1:{port}");
-
- let mut cliboard = Clipboard::new();
- cliboard.write_text(text);
-}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
deleted file mode 100644
index 0c20bec..0000000
--- a/src-tauri/src/main.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-#![cfg_attr(
- all(not(debug_assertions), target_os = "windows"),
- windows_subsystem = "windows"
-)]
-
-mod cmds;
-mod config;
-mod core;
-mod enhance;
-mod feat;
-mod utils;
-
-use crate::utils::{init, resolve, server};
-use tauri::{api, SystemTray};
-
-fn main() -> std::io::Result<()> {
- // 单例检测
- if server::check_singleton().is_err() {
- println!("app exists");
- return Ok(());
- }
-
- crate::log_err!(init::init_config());
-
- #[allow(unused_mut)]
- let mut builder = tauri::Builder::default()
- .system_tray(SystemTray::new())
- .setup(|app| Ok(resolve::resolve_setup(app)))
- .on_system_tray_event(core::tray::Tray::on_system_tray_event)
- .invoke_handler(tauri::generate_handler![
- // common
- cmds::get_sys_proxy,
- cmds::open_app_dir,
- cmds::open_logs_dir,
- cmds::open_web_url,
- cmds::open_core_dir,
- // cmds::kill_sidecar,
- cmds::restart_sidecar,
- cmds::grant_permission,
- // clash
- cmds::get_clash_info,
- cmds::get_clash_logs,
- cmds::patch_clash_config,
- cmds::change_clash_core,
- cmds::get_runtime_config,
- cmds::get_runtime_yaml,
- cmds::get_runtime_exists,
- cmds::get_runtime_logs,
- // verge
- cmds::get_verge_config,
- cmds::patch_verge_config,
- // cmds::update_hotkeys,
- // profile
- cmds::get_profiles,
- cmds::enhance_profiles,
- cmds::patch_profiles_config,
- cmds::view_profile,
- cmds::patch_profile,
- cmds::create_profile,
- cmds::import_profile,
- cmds::update_profile,
- cmds::delete_profile,
- cmds::read_profile_file,
- cmds::save_profile_file,
- // service mode
- cmds::service::check_service,
- cmds::service::install_service,
- cmds::service::uninstall_service,
- // clash api
- cmds::clash_api_get_proxy_delay
- ]);
-
- #[cfg(target_os = "macos")]
- {
- use tauri::{Menu, MenuItem, Submenu};
-
- builder = builder.menu(
- Menu::new().add_submenu(Submenu::new(
- "Edit",
- Menu::new()
- .add_native_item(MenuItem::Undo)
- .add_native_item(MenuItem::Redo)
- .add_native_item(MenuItem::Copy)
- .add_native_item(MenuItem::Paste)
- .add_native_item(MenuItem::Cut)
- .add_native_item(MenuItem::SelectAll)
- .add_native_item(MenuItem::CloseWindow)
- .add_native_item(MenuItem::Quit),
- )),
- );
- }
-
- let app = builder
- .build(tauri::generate_context!())
- .expect("error while running tauri application");
-
- app.run(|app_handle, e| match e {
- tauri::RunEvent::ExitRequested { api, .. } => {
- api.prevent_exit();
- }
- tauri::RunEvent::Exit => {
- resolve::resolve_reset();
- api::process::kill_children();
- app_handle.exit(0);
- }
- #[cfg(target_os = "macos")]
- tauri::RunEvent::WindowEvent { label, event, .. } => {
- use tauri::Manager;
-
- if label == "main" {
- match event {
- tauri::WindowEvent::CloseRequested { api, .. } => {
- api.prevent_close();
- let _ = resolve::save_window_size_position(&app_handle, true);
-
- app_handle.get_window("main").map(|win| {
- let _ = win.hide();
- });
- }
- _ => {}
- }
- }
- }
- #[cfg(not(target_os = "macos"))]
- tauri::RunEvent::WindowEvent { label, event, .. } => {
- if label == "main" {
- match event {
- tauri::WindowEvent::CloseRequested { .. } => {
- let _ = resolve::save_window_size_position(&app_handle, true);
- }
- tauri::WindowEvent::Moved(_) | tauri::WindowEvent::Resized(_) => {
- let _ = resolve::save_window_size_position(&app_handle, false);
- }
- _ => {}
- }
- }
- }
- _ => {}
- });
-
- Ok(())
-}
diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs
deleted file mode 100644
index 696831d..0000000
--- a/src-tauri/src/utils/dirs.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-use anyhow::Result;
-use std::path::PathBuf;
-use tauri::{
- api::path::{home_dir, resource_dir},
- Env, PackageInfo,
-};
-
-#[cfg(not(feature = "verge-dev"))]
-static APP_DIR: &str = "clash-verge";
-#[cfg(feature = "verge-dev")]
-static APP_DIR: &str = "clash-verge-dev";
-
-static CLASH_CONFIG: &str = "config.yaml";
-static VERGE_CONFIG: &str = "verge.yaml";
-static PROFILE_YAML: &str = "profiles.yaml";
-
-static mut RESOURCE_DIR: Option = None;
-
-/// portable flag
-#[allow(unused)]
-static mut PORTABLE_FLAG: bool = false;
-
-pub static mut APP_VERSION: &str = "v1.2.0";
-
-/// initialize portable flag
-#[cfg(target_os = "windows")]
-pub unsafe fn init_portable_flag() -> Result<()> {
- use tauri::utils::platform::current_exe;
-
- let exe = current_exe()?;
-
- if let Some(dir) = exe.parent() {
- let dir = PathBuf::from(dir).join(".config/PORTABLE");
-
- if dir.exists() {
- PORTABLE_FLAG = true;
- }
- }
-
- Ok(())
-}
-
-/// get the verge app home dir
-pub fn app_home_dir() -> Result {
- #[cfg(target_os = "windows")]
- unsafe {
- use tauri::utils::platform::current_exe;
-
- if !PORTABLE_FLAG {
- Ok(home_dir()
- .ok_or(anyhow::anyhow!("failed to get app home dir"))?
- .join(".config")
- .join(APP_DIR))
- } else {
- let app_exe = current_exe()?;
- let app_exe = dunce::canonicalize(app_exe)?;
- let app_dir = app_exe
- .parent()
- .ok_or(anyhow::anyhow!("failed to get the portable app dir"))?;
- Ok(PathBuf::from(app_dir).join(".config").join(APP_DIR))
- }
- }
-
- #[cfg(not(target_os = "windows"))]
- Ok(home_dir()
- .ok_or(anyhow::anyhow!("failed to get the app home dir"))?
- .join(".config")
- .join(APP_DIR))
-}
-
-/// get the resources dir
-pub fn app_resources_dir(package_info: &PackageInfo) -> Result {
- let res_dir = resource_dir(package_info, &Env::default())
- .ok_or(anyhow::anyhow!("failed to get the resource dir"))?
- .join("resources");
-
- unsafe {
- RESOURCE_DIR = Some(res_dir.clone());
-
- let ver = package_info.version.to_string();
- let ver_str = format!("v{ver}");
- APP_VERSION = Box::leak(Box::new(ver_str));
- }
-
- Ok(res_dir)
-}
-
-/// profiles dir
-pub fn app_profiles_dir() -> Result {
- Ok(app_home_dir()?.join("profiles"))
-}
-
-/// logs dir
-pub fn app_logs_dir() -> Result {
- Ok(app_home_dir()?.join("logs"))
-}
-
-pub fn clash_path() -> Result {
- Ok(app_home_dir()?.join(CLASH_CONFIG))
-}
-
-pub fn verge_path() -> Result {
- Ok(app_home_dir()?.join(VERGE_CONFIG))
-}
-
-pub fn profiles_path() -> Result {
- Ok(app_home_dir()?.join(PROFILE_YAML))
-}
-
-#[allow(unused)]
-pub fn app_res_dir() -> Result {
- unsafe {
- Ok(RESOURCE_DIR
- .clone()
- .ok_or(anyhow::anyhow!("failed to get the resource dir"))?)
- }
-}
-
-pub fn clash_pid_path() -> Result {
- unsafe {
- Ok(RESOURCE_DIR
- .clone()
- .ok_or(anyhow::anyhow!("failed to get the resource dir"))?
- .join("clash.pid"))
- }
-}
-
-#[cfg(windows)]
-pub fn service_path() -> Result {
- unsafe {
- let res_dir = RESOURCE_DIR
- .clone()
- .ok_or(anyhow::anyhow!("failed to get the resource dir"))?;
- Ok(res_dir.join("clash-verge-service.exe"))
- }
-}
-
-#[cfg(windows)]
-pub fn service_log_file() -> Result {
- use chrono::Local;
-
- let log_dir = app_logs_dir()?.join("service");
-
- let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string();
- let log_file = format!("{}.log", local_time);
- let log_file = log_dir.join(log_file);
-
- let _ = std::fs::create_dir_all(&log_dir);
-
- Ok(log_file)
-}
-
-pub fn path_to_str(path: &PathBuf) -> Result<&str> {
- let path_str = path
- .as_os_str()
- .to_str()
- .ok_or(anyhow::anyhow!("failed to get path from {:?}", path))?;
- Ok(path_str)
-}
diff --git a/src-tauri/src/utils/help.rs b/src-tauri/src/utils/help.rs
deleted file mode 100644
index 03a89f4..0000000
--- a/src-tauri/src/utils/help.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-use anyhow::{anyhow, bail, Context, Result};
-use nanoid::nanoid;
-use serde::{de::DeserializeOwned, Serialize};
-use serde_yaml::{Mapping, Value};
-use std::{fs, path::PathBuf, str::FromStr};
-
-/// read data from yaml as struct T
-pub fn read_yaml(path: &PathBuf) -> Result {
- if !path.exists() {
- bail!("file not found \"{}\"", path.display());
- }
-
- let yaml_str = fs::read_to_string(&path)
- .with_context(|| format!("failed to read the file \"{}\"", path.display()))?;
-
- serde_yaml::from_str::(&yaml_str).with_context(|| {
- format!(
- "failed to read the file with yaml format \"{}\"",
- path.display()
- )
- })
-}
-
-/// read mapping from yaml fix #165
-pub fn read_merge_mapping(path: &PathBuf) -> Result {
- let mut val: Value = read_yaml(path)?;
- val.apply_merge()
- .with_context(|| format!("failed to apply merge \"{}\"", path.display()))?;
-
- Ok(val
- .as_mapping()
- .ok_or(anyhow!(
- "failed to transform to yaml mapping \"{}\"",
- path.display()
- ))?
- .to_owned())
-}
-
-/// save the data to the file
-/// can set `prefix` string to add some comments
-pub fn save_yaml(path: &PathBuf, data: &T, prefix: Option<&str>) -> Result<()> {
- let data_str = serde_yaml::to_string(data)?;
-
- let yaml_str = match prefix {
- Some(prefix) => format!("{prefix}\n\n{data_str}"),
- None => data_str,
- };
-
- let path_str = path.as_os_str().to_string_lossy().to_string();
- fs::write(path, yaml_str.as_bytes())
- .with_context(|| format!("failed to save file \"{path_str}\""))
-}
-
-const ALPHABET: [char; 62] = [
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
- 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B',
- 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
- 'V', 'W', 'X', 'Y', 'Z',
-];
-
-/// generate the uid
-pub fn get_uid(prefix: &str) -> String {
- let id = nanoid!(11, &ALPHABET);
- format!("{prefix}{id}")
-}
-
-/// parse the string
-/// xxx=123123; => 123123
-pub fn parse_str(target: &str, key: &str) -> Option {
- target.find(key).and_then(|idx| {
- let idx = idx + key.len();
- let value = &target[idx..];
-
- match value.split(';').nth(0) {
- Some(value) => value.trim().parse(),
- None => value.trim().parse(),
- }
- .ok()
- })
-}
-
-/// open file
-/// use vscode by default
-pub fn open_file(path: PathBuf) -> Result<()> {
- #[cfg(target_os = "macos")]
- let code = "Visual Studio Code";
- #[cfg(not(target_os = "macos"))]
- let code = "code";
-
- // use vscode first
- if let Err(err) = open::with(&path, code) {
- log::error!(target: "app", "failed to open file with VScode `{err}`");
- // default open
- open::that(path)?;
- }
-
- Ok(())
-}
-
-#[macro_export]
-macro_rules! error {
- ($result: expr) => {
- log::error!(target: "app", "{}", $result);
- };
-}
-
-#[macro_export]
-macro_rules! log_err {
- ($result: expr) => {
- if let Err(err) = $result {
- log::error!(target: "app", "{err}");
- }
- };
-
- ($result: expr, $err_str: expr) => {
- if let Err(_) = $result {
- log::error!(target: "app", "{}", $err_str);
- }
- };
-}
-
-#[macro_export]
-macro_rules! trace_err {
- ($result: expr, $err_str: expr) => {
- if let Err(err) = $result {
- log::trace!(target: "app", "{}, err {}", $err_str, err);
- }
- }
-}
-
-/// wrap the anyhow error
-/// transform the error to String
-#[macro_export]
-macro_rules! wrap_err {
- ($stat: expr) => {
- match $stat {
- Ok(a) => Ok(a),
- Err(err) => {
- log::error!(target: "app", "{}", err.to_string());
- Err(format!("{}", err.to_string()))
- }
- }
- };
-}
-
-/// return the string literal error
-#[macro_export]
-macro_rules! ret_err {
- ($str: expr) => {
- return Err($str.into())
- };
-}
-
-#[test]
-fn test_parse_value() {
- let test_1 = "upload=111; download=2222; total=3333; expire=444";
- let test_2 = "attachment; filename=Clash.yaml";
-
- assert_eq!(parse_str::(test_1, "upload=").unwrap(), 111);
- assert_eq!(parse_str::(test_1, "download=").unwrap(), 2222);
- assert_eq!(parse_str::(test_1, "total=").unwrap(), 3333);
- assert_eq!(parse_str::(test_1, "expire=").unwrap(), 444);
- assert_eq!(
- parse_str::(test_2, "filename=").unwrap(),
- format!("Clash.yaml")
- );
-
- assert_eq!(parse_str::(test_1, "aaa="), None);
- assert_eq!(parse_str::(test_1, "upload1="), None);
- assert_eq!(parse_str::(test_1, "expire1="), None);
- assert_eq!(parse_str::(test_2, "attachment="), None);
-}
diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs
deleted file mode 100644
index e9bcd42..0000000
--- a/src-tauri/src/utils/init.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-use crate::config::*;
-use crate::utils::{dirs, help};
-use anyhow::Result;
-use chrono::{DateTime, Local};
-use log::LevelFilter;
-use log4rs::append::console::ConsoleAppender;
-use log4rs::append::file::FileAppender;
-use log4rs::config::{Appender, Logger, Root};
-use log4rs::encode::pattern::PatternEncoder;
-use std::fs::{self, DirEntry};
-use std::str::FromStr;
-use tauri::PackageInfo;
-
-/// initialize this instance's log file
-fn init_log() -> Result<()> {
- let log_dir = dirs::app_logs_dir()?;
- if !log_dir.exists() {
- let _ = fs::create_dir_all(&log_dir);
- }
-
- let log_level = Config::verge().data().get_log_level();
- if log_level == LevelFilter::Off {
- return Ok(());
- }
-
- let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string();
- let log_file = format!("{}.log", local_time);
- let log_file = log_dir.join(log_file);
-
- let log_pattern = match log_level {
- LevelFilter::Trace => "{d(%Y-%m-%d %H:%M:%S)} {l} [{M}] - {m}{n}",
- _ => "{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}",
- };
-
- let encode = Box::new(PatternEncoder::new(log_pattern));
-
- let stdout = ConsoleAppender::builder().encoder(encode.clone()).build();
- let tofile = FileAppender::builder().encoder(encode).build(log_file)?;
-
- let mut logger_builder = Logger::builder();
- let mut root_builder = Root::builder();
-
- let log_more = log_level == LevelFilter::Trace || log_level == LevelFilter::Debug;
-
- #[cfg(feature = "verge-dev")]
- {
- logger_builder = logger_builder.appenders(["file", "stdout"]);
- if log_more {
- root_builder = root_builder.appenders(["file", "stdout"]);
- } else {
- root_builder = root_builder.appenders(["stdout"]);
- }
- }
- #[cfg(not(feature = "verge-dev"))]
- {
- logger_builder = logger_builder.appenders(["file"]);
- if log_more {
- root_builder = root_builder.appenders(["file"]);
- }
- }
-
- let (config, _) = log4rs::config::Config::builder()
- .appender(Appender::builder().build("stdout", Box::new(stdout)))
- .appender(Appender::builder().build("file", Box::new(tofile)))
- .logger(logger_builder.additive(false).build("app", log_level))
- .build_lossy(root_builder.build(log_level));
-
- log4rs::init_config(config)?;
-
- Ok(())
-}
-
-/// 删除log文件
-pub fn delete_log() -> Result<()> {
- let log_dir = dirs::app_logs_dir()?;
- if !log_dir.exists() {
- return Ok(());
- }
-
- let auto_log_clean = {
- let verge = Config::verge();
- let verge = verge.data();
- verge.auto_log_clean.clone().unwrap_or(0)
- };
-
- let day = match auto_log_clean {
- 1 => 7,
- 2 => 30,
- 3 => 90,
- _ => return Ok(()),
- };
-
- log::debug!(target: "app", "try to delete log files, day: {day}");
-
- // %Y-%m-%d to NaiveDateTime
- let parse_time_str = |s: &str| {
- let sa: Vec<&str> = s.split('-').collect();
- if sa.len() != 4 {
- return Err(anyhow::anyhow!("invalid time str"));
- }
-
- let year = i32::from_str(sa[0])?;
- let month = u32::from_str(sa[1])?;
- let day = u32::from_str(sa[2])?;
- let time = chrono::NaiveDate::from_ymd_opt(year, month, day)
- .ok_or(anyhow::anyhow!("invalid time str"))?
- .and_hms_opt(0, 0, 0)
- .ok_or(anyhow::anyhow!("invalid time str"))?;
- Ok(time)
- };
-
- let process_file = |file: DirEntry| -> Result<()> {
- let file_name = file.file_name();
- let file_name = file_name.to_str().unwrap_or_default();
-
- if file_name.ends_with(".log") {
- let now = Local::now();
- let created_time = parse_time_str(&file_name[0..file_name.len() - 4])?;
- let file_time = DateTime::::from_local(created_time, now.offset().clone());
-
- let duration = now.signed_duration_since(file_time);
- if duration.num_days() > day {
- let file_path = file.path();
- let _ = fs::remove_file(file_path);
- log::info!(target: "app", "delete log file: {file_name}");
- }
- }
- Ok(())
- };
-
- for file in fs::read_dir(&log_dir)? {
- if let Ok(file) = file {
- let _ = process_file(file);
- }
- }
- Ok(())
-}
-
-/// Initialize all the config files
-/// before tauri setup
-pub fn init_config() -> Result<()> {
- #[cfg(target_os = "windows")]
- unsafe {
- let _ = dirs::init_portable_flag();
- }
-
- let _ = init_log();
- let _ = delete_log();
-
- crate::log_err!(dirs::app_home_dir().map(|app_dir| {
- if !app_dir.exists() {
- let _ = fs::create_dir_all(&app_dir);
- }
- }));
-
- crate::log_err!(dirs::app_profiles_dir().map(|profiles_dir| {
- if !profiles_dir.exists() {
- let _ = fs::create_dir_all(&profiles_dir);
- }
- }));
-
- crate::log_err!(dirs::clash_path().map(|path| {
- if !path.exists() {
- help::save_yaml(&path, &IClashTemp::template().0, Some("# Clash Verge"))?;
- }
- >::Ok(())
- }));
-
- crate::log_err!(dirs::verge_path().map(|path| {
- if !path.exists() {
- help::save_yaml(&path, &IVerge::template(), Some("# Clash Verge"))?;
- }
- >::Ok(())
- }));
-
- crate::log_err!(dirs::profiles_path().map(|path| {
- if !path.exists() {
- help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge"))?;
- }
- >::Ok(())
- }));
-
- Ok(())
-}
-
-/// initialize app resources
-/// after tauri setup
-pub fn init_resources(package_info: &PackageInfo) -> Result<()> {
- let app_dir = dirs::app_home_dir()?;
- let res_dir = dirs::app_resources_dir(package_info)?;
-
- if !app_dir.exists() {
- let _ = fs::create_dir_all(&app_dir);
- }
- if !res_dir.exists() {
- let _ = fs::create_dir_all(&res_dir);
- }
-
- #[cfg(target_os = "windows")]
- let file_list = ["Country.mmdb", "geoip.dat", "geosite.dat", "wintun.dll"];
- #[cfg(not(target_os = "windows"))]
- let file_list = ["Country.mmdb", "geoip.dat", "geosite.dat"];
-
- // copy the resource file
- // if the source file is newer than the destination file, copy it over
- for file in file_list.iter() {
- let src_path = res_dir.join(file);
- let dest_path = app_dir.join(file);
-
- let handle_copy = || {
- match fs::copy(&src_path, &dest_path) {
- Ok(_) => log::debug!(target: "app", "resources copied '{file}'"),
- Err(err) => {
- log::error!(target: "app", "failed to copy resources '{file}', {err}")
- }
- };
- };
-
- if src_path.exists() && !dest_path.exists() {
- handle_copy();
- continue;
- }
-
- let src_modified = fs::metadata(&src_path).and_then(|m| m.modified());
- let dest_modified = fs::metadata(&dest_path).and_then(|m| m.modified());
-
- match (src_modified, dest_modified) {
- (Ok(src_modified), Ok(dest_modified)) => {
- if src_modified > dest_modified {
- handle_copy();
- } else {
- log::debug!(target: "app", "skipping resource copy '{file}'");
- }
- }
- _ => {
- log::debug!(target: "app", "failed to get modified '{file}'");
- handle_copy();
- }
- };
- }
-
- Ok(())
-}
diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs
deleted file mode 100644
index aeb0a60..0000000
--- a/src-tauri/src/utils/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub mod dirs;
-pub mod help;
-pub mod init;
-pub mod resolve;
-pub mod server;
-pub mod tmpl;
-// mod winhelp;
diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs
deleted file mode 100644
index 14d4bdd..0000000
--- a/src-tauri/src/utils/resolve.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use crate::{config::Config, core::*, utils::init, utils::server};
-use crate::{log_err, trace_err};
-use anyhow::Result;
-use tauri::{App, AppHandle, Manager};
-
-/// handle something when start app
-pub fn resolve_setup(app: &mut App) {
- #[cfg(target_os = "macos")]
- app.set_activation_policy(tauri::ActivationPolicy::Accessory);
-
- handle::Handle::global().init(app.app_handle());
-
- log_err!(init::init_resources(app.package_info()));
-
- // 启动核心
- log::trace!("init config");
- log_err!(Config::init_config());
-
- log::trace!("launch core");
- log_err!(CoreManager::global().init());
-
- // setup a simple http server for singleton
- log::trace!("launch embed server");
- server::embed_server(app.app_handle());
-
- log::trace!("init system tray");
- log_err!(tray::Tray::update_systray(&app.app_handle()));
-
- let silent_start = { Config::verge().data().enable_silent_start.clone() };
- if !silent_start.unwrap_or(false) {
- create_window(&app.app_handle());
- }
-
- log_err!(sysopt::Sysopt::global().init_launch());
- log_err!(sysopt::Sysopt::global().init_sysproxy());
-
- log_err!(handle::Handle::update_systray_part());
- log_err!(hotkey::Hotkey::global().init(app.app_handle()));
- log_err!(timer::Timer::global().init());
-}
-
-/// reset system proxy
-pub fn resolve_reset() {
- log_err!(sysopt::Sysopt::global().reset_sysproxy());
- log_err!(CoreManager::global().stop_core());
-}
-
-/// create main window
-pub fn create_window(app_handle: &AppHandle) {
- if let Some(window) = app_handle.get_window("main") {
- trace_err!(window.unminimize(), "set win unminimize");
- trace_err!(window.show(), "set win visible");
- trace_err!(window.set_focus(), "set win focus");
- return;
- }
-
- let mut builder = tauri::window::WindowBuilder::new(
- app_handle,
- "main".to_string(),
- tauri::WindowUrl::App("index.html".into()),
- )
- .title("Clash Verge")
- .fullscreen(false)
- .min_inner_size(600.0, 520.0);
-
- match Config::verge().latest().window_size_position.clone() {
- Some(size_pos) if size_pos.len() == 4 => {
- let size = (size_pos[0], size_pos[1]);
- let pos = (size_pos[2], size_pos[3]);
- let w = size.0.clamp(600.0, f64::INFINITY);
- let h = size.1.clamp(520.0, f64::INFINITY);
- builder = builder.inner_size(w, h).position(pos.0, pos.1);
- }
- _ => {
- #[cfg(target_os = "windows")]
- {
- builder = builder.inner_size(800.0, 636.0).center();
- }
-
- #[cfg(target_os = "macos")]
- {
- builder = builder.inner_size(800.0, 642.0).center();
- }
-
- #[cfg(target_os = "linux")]
- {
- builder = builder.inner_size(800.0, 642.0).center();
- }
- }
- };
-
- #[cfg(target_os = "windows")]
- {
- use std::time::Duration;
- use tokio::time::sleep;
- use window_shadows::set_shadow;
-
- match builder
- .decorations(false)
- .transparent(true)
- .visible(false)
- .build()
- {
- Ok(win) => {
- log::trace!("try to calculate the monitor size");
- let center = (|| -> Result {
- let mut center = false;
- let monitor = win.current_monitor()?.ok_or(anyhow::anyhow!(""))?;
- let size = monitor.size();
- let pos = win.outer_position()?;
-
- if pos.x < -400
- || pos.x > (size.width - 200).try_into()?
- || pos.y < -200
- || pos.y > (size.height - 200).try_into()?
- {
- center = true;
- }
- Ok(center)
- })();
-
- if center.unwrap_or(true) {
- trace_err!(win.center(), "set win center");
- }
-
- log::trace!("try to create window");
- let app_handle = app_handle.clone();
-
- // 加点延迟避免界面闪一下
- tauri::async_runtime::spawn(async move {
- sleep(Duration::from_millis(888)).await;
-
- if let Some(window) = app_handle.get_window("main") {
- trace_err!(set_shadow(&window, true), "set win shadow");
- trace_err!(window.show(), "set win visible");
- trace_err!(window.unminimize(), "set win unminimize");
- trace_err!(window.set_focus(), "set win focus");
- } else {
- log::error!(target: "app", "failed to create window, get_window is None")
- }
- });
- }
- Err(err) => log::error!(target: "app", "failed to create window, {err}"),
- }
- }
-
- #[cfg(target_os = "macos")]
- crate::log_err!(builder
- .decorations(true)
- .hidden_title(true)
- .title_bar_style(tauri::TitleBarStyle::Overlay)
- .build());
-
- #[cfg(target_os = "linux")]
- crate::log_err!(builder.decorations(true).transparent(false).build());
-}
-
-/// save window size and position
-pub fn save_window_size_position(app_handle: &AppHandle, save_to_file: bool) -> Result<()> {
- let win = app_handle
- .get_window("main")
- .ok_or(anyhow::anyhow!("failed to get window"))?;
-
- let scale = win.scale_factor()?;
- let size = win.inner_size()?;
- let size = size.to_logical::(scale);
- let pos = win.outer_position()?;
- let pos = pos.to_logical::(scale);
-
- let verge = Config::verge();
- let mut verge = verge.latest();
- verge.window_size_position = Some(vec![size.width, size.height, pos.x, pos.y]);
-
- if save_to_file {
- verge.save_file()?;
- }
-
- Ok(())
-}
diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs
deleted file mode 100644
index f4e9836..0000000
--- a/src-tauri/src/utils/server.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-extern crate warp;
-
-use super::resolve;
-use crate::config::IVerge;
-use anyhow::{bail, Result};
-use port_scanner::local_port_available;
-use tauri::AppHandle;
-use warp::Filter;
-
-/// check whether there is already exists
-pub fn check_singleton() -> Result<()> {
- let port = IVerge::get_singleton_port();
-
- if !local_port_available(port) {
- tauri::async_runtime::block_on(async {
- let url = format!("http://127.0.0.1:{port}/commands/visible");
- let resp = reqwest::get(url).await?.text().await?;
-
- if &resp == "ok" {
- bail!("app exists");
- }
-
- log::error!("failed to setup singleton listen server");
- Ok(())
- })
- } else {
- Ok(())
- }
-}
-
-/// The embed server only be used to implement singleton process
-/// maybe it can be used as pac server later
-pub fn embed_server(app_handle: AppHandle) {
- let port = IVerge::get_singleton_port();
-
- tauri::async_runtime::spawn(async move {
- let commands = warp::path!("commands" / "visible").map(move || {
- resolve::create_window(&app_handle);
- format!("ok")
- });
-
- warp::serve(commands).bind(([127, 0, 0, 1], port)).await;
- });
-}
diff --git a/src-tauri/src/utils/tmpl.rs b/src-tauri/src/utils/tmpl.rs
deleted file mode 100644
index ec17c33..0000000
--- a/src-tauri/src/utils/tmpl.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-///! Some config file template
-
-/// template for new a profile item
-pub const ITEM_LOCAL: &str = "# Profile Template for clash verge
-
-proxies:
-
-proxy-groups:
-
-rules:
-";
-
-/// enhanced profile
-pub const ITEM_MERGE: &str = "# Merge Template for clash verge
-# The `Merge` format used to enhance profile
-
-prepend-rules:
-
-prepend-proxies:
-
-prepend-proxy-groups:
-
-append-rules:
-
-append-proxies:
-
-append-proxy-groups:
-";
-
-/// enhanced profile
-pub const ITEM_SCRIPT: &str = "// Define the `main` function
-
-function main(params) {
- return params;
-}
-";
diff --git a/src-tauri/src/utils/winhelp.rs b/src-tauri/src/utils/winhelp.rs
deleted file mode 100644
index e903d95..0000000
--- a/src-tauri/src/utils/winhelp.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-#![cfg(target_os = "windows")]
-#![allow(non_snake_case)]
-#![allow(non_camel_case_types)]
-
-//!
-//! From https://github.com/tauri-apps/window-vibrancy/blob/dev/src/windows.rs
-//!
-
-use windows_sys::Win32::{
- Foundation::*,
- System::{LibraryLoader::*, SystemInformation::*},
-};
-
-fn get_function_impl(library: &str, function: &str) -> Option