mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-06-02 06:14:48 +02:00
refactor: align CI and native build with python torrent backend
This commit is contained in:
@@ -19,10 +19,6 @@ jobs:
|
|||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
env:
|
|
||||||
VCPKG_COMMIT: b472291f295551b7127359ea38fdd2ca092f6f1b
|
|
||||||
VCPKG_BINARY_CACHE: 'C:\Users\runneradmin\AppData\Local\vcpkg\archives'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -36,46 +32,6 @@ jobs:
|
|||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- name: Cache vcpkg binary archives (Windows)
|
|
||||||
id: cache-vcpkg
|
|
||||||
if: matrix.os == 'windows-2022'
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.VCPKG_BINARY_CACHE }}
|
|
||||||
key: ${{ runner.os }}-vcpkg-${{ env.VCPKG_COMMIT }}-x64-windows-static-md
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-vcpkg-${{ env.VCPKG_COMMIT }}-
|
|
||||||
|
|
||||||
- name: Install libtorrent dependencies (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y pkg-config
|
|
||||||
sudo apt-get install -y libtorrent-rasterbar2.0-dev || sudo apt-get install -y libtorrent-rasterbar-dev
|
|
||||||
|
|
||||||
- name: Install libtorrent dependencies (Windows)
|
|
||||||
if: matrix.os == 'windows-2022'
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$vcpkgRoot = Join-Path $env:RUNNER_TEMP "vcpkg"
|
|
||||||
git clone --depth 1 https://github.com/microsoft/vcpkg $vcpkgRoot
|
|
||||||
git -C $vcpkgRoot fetch --depth 1 origin $env:VCPKG_COMMIT
|
|
||||||
git -C $vcpkgRoot checkout $env:VCPKG_COMMIT
|
|
||||||
& "$vcpkgRoot/bootstrap-vcpkg.bat" -disableMetrics
|
|
||||||
New-Item -ItemType Directory -Path $env:VCPKG_BINARY_CACHE -Force | Out-Null
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_DEFAULT_BINARY_CACHE=$env:VCPKG_BINARY_CACHE"
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_BINARY_SOURCES=clear;files,$env:VCPKG_BINARY_CACHE,readwrite"
|
|
||||||
& "$vcpkgRoot/vcpkg.exe" install --clean-after-build "libtorrent:x64-windows-static-md" "boost-throw-exception:x64-windows-static-md"
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_ROOT=$vcpkgRoot"
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKGRS_TRIPLET=x64-windows-static-md"
|
|
||||||
|
|
||||||
- name: Save vcpkg binary archives (Windows)
|
|
||||||
if: matrix.os == 'windows-2022' && steps.cache-vcpkg.outputs.cache-hit != 'true' && always()
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.VCPKG_BINARY_CACHE }}
|
|
||||||
key: ${{ steps.cache-vcpkg.outputs.cache-primary-key }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn --frozen-lockfile
|
run: yarn --frozen-lockfile
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ jobs:
|
|||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
env:
|
|
||||||
VCPKG_COMMIT: b472291f295551b7127359ea38fdd2ca092f6f1b
|
|
||||||
VCPKG_BINARY_CACHE: 'C:\Users\runneradmin\AppData\Local\vcpkg\archives'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -34,46 +30,6 @@ jobs:
|
|||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- name: Cache vcpkg binary archives (Windows)
|
|
||||||
id: cache-vcpkg
|
|
||||||
if: matrix.os == 'windows-2022'
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.VCPKG_BINARY_CACHE }}
|
|
||||||
key: ${{ runner.os }}-vcpkg-${{ env.VCPKG_COMMIT }}-x64-windows-static-md
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-vcpkg-${{ env.VCPKG_COMMIT }}-
|
|
||||||
|
|
||||||
- name: Install libtorrent dependencies (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y pkg-config
|
|
||||||
sudo apt-get install -y libtorrent-rasterbar2.0-dev || sudo apt-get install -y libtorrent-rasterbar-dev
|
|
||||||
|
|
||||||
- name: Install libtorrent dependencies (Windows)
|
|
||||||
if: matrix.os == 'windows-2022'
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$vcpkgRoot = Join-Path $env:RUNNER_TEMP "vcpkg"
|
|
||||||
git clone --depth 1 https://github.com/microsoft/vcpkg $vcpkgRoot
|
|
||||||
git -C $vcpkgRoot fetch --depth 1 origin $env:VCPKG_COMMIT
|
|
||||||
git -C $vcpkgRoot checkout $env:VCPKG_COMMIT
|
|
||||||
& "$vcpkgRoot/bootstrap-vcpkg.bat" -disableMetrics
|
|
||||||
New-Item -ItemType Directory -Path $env:VCPKG_BINARY_CACHE -Force | Out-Null
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_DEFAULT_BINARY_CACHE=$env:VCPKG_BINARY_CACHE"
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_BINARY_SOURCES=clear;files,$env:VCPKG_BINARY_CACHE,readwrite"
|
|
||||||
& "$vcpkgRoot/vcpkg.exe" install --clean-after-build "libtorrent:x64-windows-static-md" "boost-throw-exception:x64-windows-static-md"
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_ROOT=$vcpkgRoot"
|
|
||||||
Add-Content -Path $env:GITHUB_ENV -Value "VCPKGRS_TRIPLET=x64-windows-static-md"
|
|
||||||
|
|
||||||
- name: Save vcpkg binary archives (Windows)
|
|
||||||
if: matrix.os == 'windows-2022' && steps.cache-vcpkg.outputs.cache-hit != 'true' && always()
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.VCPKG_BINARY_CACHE }}
|
|
||||||
key: ${{ steps.cache-vcpkg.outputs.cache-primary-key }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn --frozen-lockfile
|
run: yarn --frozen-lockfile
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ Please, refer to our Documentation pages: [docs.hydralauncher.gg](https://docs.h
|
|||||||
- Node.js + Yarn
|
- Node.js + Yarn
|
||||||
- Python 3.9+ with `pip install -r requirements.txt`
|
- Python 3.9+ with `pip install -r requirements.txt`
|
||||||
- Rust toolchain (for `hydra-native`)
|
- Rust toolchain (for `hydra-native`)
|
||||||
- `libtorrent-rasterbar` development package (Linux/macOS, usually `libtorrent-rasterbar2.0-dev` or `libtorrent-rasterbar-dev`) or vcpkg `libtorrent` (Windows)
|
|
||||||
|
|
||||||
After installing dependencies, `postinstall` now builds the Rust native addon automatically (`hydra-native/hydra-native.node`).
|
After installing dependencies, `postinstall` now builds the Rust native addon automatically (`hydra-native/hydra-native.node`).
|
||||||
|
|
||||||
|
|||||||
Generated
+1
-531
@@ -8,21 +8,6 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anstyle"
|
|
||||||
version = "1.0.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.102"
|
version = "1.0.102"
|
||||||
@@ -59,59 +44,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.2.57"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
|
|
||||||
dependencies = [
|
|
||||||
"find-msvc-tools",
|
|
||||||
"shlex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "4.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
|
|
||||||
dependencies = [
|
|
||||||
"clap_builder",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_builder"
|
|
||||||
version = "4.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
|
||||||
dependencies = [
|
|
||||||
"anstyle",
|
|
||||||
"clap_lex",
|
|
||||||
"strsim",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "codespan-reporting"
|
|
||||||
version = "0.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"termcolor",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -152,79 +90,6 @@ version = "0.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxx"
|
|
||||||
version = "1.0.194"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"cxx-build",
|
|
||||||
"cxxbridge-cmd",
|
|
||||||
"cxxbridge-flags",
|
|
||||||
"cxxbridge-macro",
|
|
||||||
"foldhash 0.2.0",
|
|
||||||
"link-cplusplus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxx-build"
|
|
||||||
version = "1.0.194"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"codespan-reporting",
|
|
||||||
"indexmap",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"scratch",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxxbridge-cmd"
|
|
||||||
version = "1.0.194"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328"
|
|
||||||
dependencies = [
|
|
||||||
"clap",
|
|
||||||
"codespan-reporting",
|
|
||||||
"indexmap",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxxbridge-flags"
|
|
||||||
version = "1.0.194"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxxbridge-macro"
|
|
||||||
version = "1.0.194"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "displaydoc"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtor"
|
name = "dtor"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -255,12 +120,6 @@ dependencies = [
|
|||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "find-msvc-tools"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.1.9"
|
version = "1.1.9"
|
||||||
@@ -277,21 +136,6 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foldhash"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "form_urlencoded"
|
|
||||||
version = "1.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
|
|
||||||
dependencies = [
|
|
||||||
"percent-encoding",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -409,7 +253,7 @@ version = "0.15.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foldhash 0.1.5",
|
"foldhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -428,103 +272,13 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|||||||
name = "hydra-native"
|
name = "hydra-native"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"cxx",
|
|
||||||
"cxx-build",
|
|
||||||
"image",
|
"image",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"napi",
|
"napi",
|
||||||
"napi-build",
|
"napi-build",
|
||||||
"napi-derive",
|
"napi-derive",
|
||||||
"once_cell",
|
|
||||||
"pkg-config",
|
|
||||||
"regex",
|
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
"url",
|
|
||||||
"urlencoding",
|
|
||||||
"uuid",
|
"uuid",
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_collections"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"potential_utf",
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_locale_core"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"litemap",
|
|
||||||
"tinystr",
|
|
||||||
"writeable",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_normalizer"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
|
|
||||||
dependencies = [
|
|
||||||
"icu_collections",
|
|
||||||
"icu_normalizer_data",
|
|
||||||
"icu_properties",
|
|
||||||
"icu_provider",
|
|
||||||
"smallvec",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_normalizer_data"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_properties"
|
|
||||||
version = "2.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
|
||||||
dependencies = [
|
|
||||||
"icu_collections",
|
|
||||||
"icu_locale_core",
|
|
||||||
"icu_properties_data",
|
|
||||||
"icu_provider",
|
|
||||||
"zerotrie",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_properties_data"
|
|
||||||
version = "2.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_provider"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"icu_locale_core",
|
|
||||||
"writeable",
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
"zerotrie",
|
|
||||||
"zerovec",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -533,27 +287,6 @@ version = "2.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
|
|
||||||
dependencies = [
|
|
||||||
"idna_adapter",
|
|
||||||
"smallvec",
|
|
||||||
"utf8_iter",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna_adapter"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
|
|
||||||
dependencies = [
|
|
||||||
"icu_normalizer",
|
|
||||||
"icu_properties",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.10"
|
version = "0.25.10"
|
||||||
@@ -632,21 +365,6 @@ dependencies = [
|
|||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "link-cplusplus"
|
|
||||||
version = "1.0.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "litemap"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.29"
|
version = "0.4.29"
|
||||||
@@ -802,24 +520,12 @@ version = "1.21.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "percent-encoding"
|
|
||||||
version = "2.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
@@ -833,15 +539,6 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "potential_utf"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
|
|
||||||
dependencies = [
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
@@ -888,35 +585,6 @@ version = "6.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@@ -929,12 +597,6 @@ version = "1.0.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scratch"
|
|
||||||
version = "1.0.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.27"
|
version = "1.0.27"
|
||||||
@@ -948,7 +610,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"serde_derive",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -984,12 +645,6 @@ dependencies = [
|
|||||||
"zmij",
|
"zmij",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simd-adler32"
|
name = "simd-adler32"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@@ -1002,24 +657,6 @@ version = "0.4.12"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stable_deref_trait"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.117"
|
version = "2.0.117"
|
||||||
@@ -1031,17 +668,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "synstructure"
|
|
||||||
version = "0.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.37.2"
|
version = "0.37.2"
|
||||||
@@ -1056,25 +682,6 @@ dependencies = [
|
|||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tinystr"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.50.0"
|
version = "1.50.0"
|
||||||
@@ -1102,42 +709,12 @@ version = "1.12.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "url"
|
|
||||||
version = "2.5.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
|
|
||||||
dependencies = [
|
|
||||||
"form_urlencoded",
|
|
||||||
"idna",
|
|
||||||
"percent-encoding",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "urlencoding"
|
|
||||||
version = "2.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf8_iter"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.22.0"
|
version = "1.22.0"
|
||||||
@@ -1149,12 +726,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vcpkg"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasip2"
|
name = "wasip2"
|
||||||
version = "1.0.2+wasi-0.2.9"
|
version = "1.0.2+wasi-0.2.9"
|
||||||
@@ -1274,15 +845,6 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1397,15 +959,6 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.61.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-threading"
|
name = "windows-threading"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1503,89 +1056,6 @@ dependencies = [
|
|||||||
"wasmparser",
|
"wasmparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "writeable"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yoke"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
|
|
||||||
dependencies = [
|
|
||||||
"stable_deref_trait",
|
|
||||||
"yoke-derive",
|
|
||||||
"zerofrom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yoke-derive"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"synstructure",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerofrom"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
|
||||||
dependencies = [
|
|
||||||
"zerofrom-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerofrom-derive"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"synstructure",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerotrie"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerovec"
|
|
||||||
version = "0.11.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
|
||||||
dependencies = [
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
"zerovec-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerovec-derive"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zmij"
|
name = "zmij"
|
||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
|
|||||||
@@ -7,21 +7,12 @@ edition = "2021"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.100"
|
|
||||||
image = { version = "0.25.8", default-features = false, features = ["gif", "jpeg", "png", "webp"] }
|
image = { version = "0.25.8", default-features = false, features = ["gif", "jpeg", "png", "webp"] }
|
||||||
cxx = "1.0.189"
|
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
napi = { version = "3.5.2", default-features = false, features = ["napi8", "tokio_rt"] }
|
napi = { version = "3.5.2", default-features = false, features = ["napi8", "tokio_rt"] }
|
||||||
napi-derive = "3.3.2"
|
napi-derive = "3.3.2"
|
||||||
once_cell = "1.21.3"
|
|
||||||
regex = "1.12.2"
|
|
||||||
sysinfo = "0.37.2"
|
sysinfo = "0.37.2"
|
||||||
url = "2.5.7"
|
|
||||||
urlencoding = "2.1.3"
|
|
||||||
uuid = { version = "1.11.0", features = ["v4"] }
|
uuid = { version = "1.11.0", features = ["v4"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cxx-build = "1.0.189"
|
|
||||||
napi-build = "2.3.1"
|
napi-build = "2.3.1"
|
||||||
pkg-config = "0.3.32"
|
|
||||||
vcpkg = "0.2.15"
|
|
||||||
|
|||||||
@@ -1,100 +1,6 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
napi_build::setup();
|
napi_build::setup();
|
||||||
|
|
||||||
let mut build = cxx_build::bridge("src/libtorrent_bridge.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
build
|
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||||
.file("cpp/libtorrent_bridge.cc")
|
|
||||||
.file("cpp/bridge_state.cc")
|
|
||||||
.file("cpp/bridge_utils.cc")
|
|
||||||
.file("cpp/torrent_helpers.cc")
|
|
||||||
.include(".")
|
|
||||||
.include("cpp")
|
|
||||||
.std("c++17");
|
|
||||||
|
|
||||||
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
|
||||||
|
|
||||||
if target_os == "linux" || target_os == "macos" {
|
|
||||||
let library = pkg_config::Config::new()
|
|
||||||
.probe("libtorrent-rasterbar")
|
|
||||||
.unwrap_or_else(|error| {
|
|
||||||
panic!(
|
|
||||||
"libtorrent-rasterbar development package is required for hydra-native: {error}"
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
for include_path in library.include_paths {
|
|
||||||
build.include(include_path);
|
|
||||||
}
|
|
||||||
} else if target_os == "windows" {
|
|
||||||
build.flag_if_supported("/EHsc");
|
|
||||||
build.define("_WIN32_WINNT", Some("0x0A00"));
|
|
||||||
build.define("TORRENT_ABI_VERSION", Some("3"));
|
|
||||||
|
|
||||||
let library = vcpkg::Config::new()
|
|
||||||
.emit_includes(true)
|
|
||||||
.find_package("libtorrent")
|
|
||||||
.unwrap_or_else(|error| {
|
|
||||||
panic!(
|
|
||||||
"vcpkg libtorrent package is required for hydra-native (set VCPKG_ROOT and install port libtorrent): {error}"
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
for include_path in library.include_paths {
|
|
||||||
build.include(include_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
for link_path in &library.link_paths {
|
|
||||||
emit_matching_link_lib(link_path, "boost_throw_exception");
|
|
||||||
emit_matching_link_lib(link_path, "boost_exception");
|
|
||||||
|
|
||||||
let manual_link_path = link_path.join("manual-link");
|
|
||||||
emit_matching_link_lib(&manual_link_path, "boost_throw_exception");
|
|
||||||
emit_matching_link_lib(&manual_link_path, "boost_exception");
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-lib=bcrypt");
|
|
||||||
println!("cargo:rustc-link-lib=mswsock");
|
|
||||||
println!("cargo:rustc-link-lib=ws2_32");
|
|
||||||
println!("cargo:rustc-link-lib=iphlpapi");
|
|
||||||
println!("cargo:rustc-link-lib=dbghelp");
|
|
||||||
println!("cargo:rustc-link-lib=crypt32");
|
|
||||||
println!("cargo:rustc-link-lib=user32");
|
|
||||||
}
|
|
||||||
|
|
||||||
build.compile("hydra_libtorrent_bridge");
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=src/libtorrent_bridge.rs");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/bridge_state.h");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/bridge_state.cc");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/bridge_utils.h");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/bridge_utils.cc");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/torrent_helpers.h");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/torrent_helpers.cc");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/libtorrent_bridge.h");
|
|
||||||
println!("cargo:rerun-if-changed=cpp/libtorrent_bridge.cc");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_matching_link_lib(link_path: &std::path::Path, prefix: &str) {
|
|
||||||
let entries = match std::fs::read_dir(link_path) {
|
|
||||||
Ok(entries) => entries,
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
for entry in entries.flatten() {
|
|
||||||
let path = entry.path();
|
|
||||||
let extension = path.extension().and_then(|value| value.to_str());
|
|
||||||
if extension != Some("lib") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let stem = match path.file_stem().and_then(|value| value.to_str()) {
|
|
||||||
Some(stem) => stem,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if stem.starts_with(prefix) {
|
|
||||||
println!("cargo:rustc-link-lib={stem}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ use std::io::BufReader;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{cmp::Ordering, collections::HashMap};
|
use std::{cmp::Ordering, collections::HashMap};
|
||||||
|
|
||||||
mod libtorrent_bridge;
|
|
||||||
|
|
||||||
#[path = "torrent_libtorrent.rs"]
|
|
||||||
mod torrent;
|
|
||||||
|
|
||||||
use image::codecs::gif::GifDecoder;
|
use image::codecs::gif::GifDecoder;
|
||||||
use image::codecs::png::PngDecoder;
|
use image::codecs::png::PngDecoder;
|
||||||
use image::codecs::webp::WebPDecoder;
|
use image::codecs::webp::WebPDecoder;
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
#[cxx::bridge(namespace = "hydra::libtorrent_bridge")]
|
|
||||||
pub mod ffi {
|
|
||||||
pub struct BridgeTorrentFileEntry {
|
|
||||||
pub index: u32,
|
|
||||||
pub path: String,
|
|
||||||
pub length: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BridgeTorrentFilesResult {
|
|
||||||
pub ok: bool,
|
|
||||||
pub error: String,
|
|
||||||
pub name: String,
|
|
||||||
pub total_size: i64,
|
|
||||||
pub files: Vec<BridgeTorrentFileEntry>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BridgeTorrentStatusResult {
|
|
||||||
pub present: bool,
|
|
||||||
pub progress: f64,
|
|
||||||
pub num_peers: u32,
|
|
||||||
pub num_seeds: u32,
|
|
||||||
pub download_speed: i64,
|
|
||||||
pub upload_speed: i64,
|
|
||||||
pub bytes_downloaded: i64,
|
|
||||||
pub file_size: i64,
|
|
||||||
pub folder_name: String,
|
|
||||||
pub status: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C++" {
|
|
||||||
include!("cpp/libtorrent_bridge.h");
|
|
||||||
|
|
||||||
pub fn init_session(listen_port_start: u16, listen_port_end: u16) -> String;
|
|
||||||
|
|
||||||
pub fn set_download_limit(max_download_speed_bytes_per_second: i64) -> String;
|
|
||||||
|
|
||||||
pub fn start_torrent(
|
|
||||||
game_id: &str,
|
|
||||||
magnet: &str,
|
|
||||||
save_path: &str,
|
|
||||||
trackers: &Vec<String>,
|
|
||||||
file_indices: &Vec<u32>,
|
|
||||||
selective: bool,
|
|
||||||
upload_mode: bool,
|
|
||||||
timeout_ms: u32,
|
|
||||||
) -> String;
|
|
||||||
|
|
||||||
pub fn pause_torrent(game_id: &str) -> String;
|
|
||||||
|
|
||||||
pub fn cancel_torrent(game_id: &str) -> String;
|
|
||||||
|
|
||||||
pub fn get_torrent_status(game_id: &str) -> BridgeTorrentStatusResult;
|
|
||||||
|
|
||||||
pub fn get_torrent_files(
|
|
||||||
magnet: &str,
|
|
||||||
save_path: &str,
|
|
||||||
trackers: &Vec<String>,
|
|
||||||
timeout_ms: u32,
|
|
||||||
max_files: u32,
|
|
||||||
) -> BridgeTorrentFilesResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,766 +0,0 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
use napi::bindgen_prelude::Error;
|
|
||||||
use napi_derive::napi;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use regex::Regex;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::libtorrent_bridge::ffi as bridge;
|
|
||||||
|
|
||||||
const TORRENT_FILES_CACHE_TTL_SECONDS: u64 = 300;
|
|
||||||
const TORRENT_FILES_CACHE_MAX_ITEMS: usize = 128;
|
|
||||||
const TORRENT_MAX_FILES: usize = 100_000;
|
|
||||||
const HYDRA_TORRENT_STATUS_SEEDING: u32 = 5;
|
|
||||||
|
|
||||||
static MAGNET_HASH_HEX_RE: Lazy<Regex> =
|
|
||||||
Lazy::new(|| Regex::new(r"^[a-fA-F0-9]{40}$").expect("valid regex"));
|
|
||||||
static MAGNET_HASH_BASE32_RE: Lazy<Regex> =
|
|
||||||
Lazy::new(|| Regex::new(r"^[a-zA-Z2-7]{32}$").expect("valid regex"));
|
|
||||||
|
|
||||||
const DEFAULT_TRACKERS: &[&str] = &[
|
|
||||||
"udp://tracker.opentrackr.org:1337/announce",
|
|
||||||
"http://tracker.opentrackr.org:1337/announce",
|
|
||||||
"udp://open.tracker.cl:1337/announce",
|
|
||||||
"udp://open.demonii.com:1337/announce",
|
|
||||||
"udp://open.stealth.si:80/announce",
|
|
||||||
"udp://tracker.torrent.eu.org:451/announce",
|
|
||||||
"udp://exodus.desync.com:6969/announce",
|
|
||||||
"udp://tracker.theoks.net:6969/announce",
|
|
||||||
"udp://tracker-udp.gbitt.info:80/announce",
|
|
||||||
"udp://explodie.org:6969/announce",
|
|
||||||
"https://tracker.tamersunion.org:443/announce",
|
|
||||||
"udp://tracker2.dler.org:80/announce",
|
|
||||||
"udp://tracker1.myporn.club:9337/announce",
|
|
||||||
"udp://tracker.tiny-vps.com:6969/announce",
|
|
||||||
"udp://tracker.dler.org:6969/announce",
|
|
||||||
"udp://tracker.bittor.pw:1337/announce",
|
|
||||||
"udp://tracker.0x7c0.com:6969/announce",
|
|
||||||
"udp://retracker01-msk-virt.corbina.net:80/announce",
|
|
||||||
"udp://opentracker.io:6969/announce",
|
|
||||||
"udp://open.free-tracker.ga:6969/announce",
|
|
||||||
"udp://new-line.net:6969/announce",
|
|
||||||
"udp://moonburrow.club:6969/announce",
|
|
||||||
"udp://leet-tracker.moe:1337/announce",
|
|
||||||
"udp://bt2.archive.org:6969/announce",
|
|
||||||
"udp://bt1.archive.org:6969/announce",
|
|
||||||
"http://tracker2.dler.org:80/announce",
|
|
||||||
"http://tracker1.bt.moack.co.kr:80/announce",
|
|
||||||
"http://tracker.dler.org:6969/announce",
|
|
||||||
"http://tr.kxmp.cf:80/announce",
|
|
||||||
"udp://u.peer-exchange.download:6969/announce",
|
|
||||||
"udp://ttk2.nbaonlineservice.com:6969/announce",
|
|
||||||
"udp://tracker.tryhackx.org:6969/announce",
|
|
||||||
"udp://tracker.srv00.com:6969/announce",
|
|
||||||
"udp://tracker.skynetcloud.site:6969/announce",
|
|
||||||
"udp://tracker.jamesthebard.net:6969/announce",
|
|
||||||
"udp://tracker.fnix.net:6969/announce",
|
|
||||||
"udp://tracker.filemail.com:6969/announce",
|
|
||||||
"udp://tracker.farted.net:6969/announce",
|
|
||||||
"udp://tracker.edkj.club:6969/announce",
|
|
||||||
"udp://tracker.dump.cl:6969/announce",
|
|
||||||
"udp://tracker.deadorbit.nl:6969/announce",
|
|
||||||
"udp://tracker.darkness.services:6969/announce",
|
|
||||||
"udp://tracker.ccp.ovh:6969/announce",
|
|
||||||
"udp://tamas3.ynh.fr:6969/announce",
|
|
||||||
"udp://ryjer.com:6969/announce",
|
|
||||||
"udp://run.publictracker.xyz:6969/announce",
|
|
||||||
"udp://public.tracker.vraphim.com:6969/announce",
|
|
||||||
"udp://p4p.arenabg.com:1337/announce",
|
|
||||||
"udp://p2p.publictracker.xyz:6969/announce",
|
|
||||||
"udp://open.u-p.pw:6969/announce",
|
|
||||||
"udp://open.publictracker.xyz:6969/announce",
|
|
||||||
"udp://open.dstud.io:6969/announce",
|
|
||||||
"udp://open.demonoid.ch:6969/announce",
|
|
||||||
"udp://odd-hd.fr:6969/announce",
|
|
||||||
"udp://martin-gebhardt.eu:25/announce",
|
|
||||||
"udp://jutone.com:6969/announce",
|
|
||||||
"udp://isk.richardsw.club:6969/announce",
|
|
||||||
"udp://evan.im:6969/announce",
|
|
||||||
"udp://epider.me:6969/announce",
|
|
||||||
"udp://d40969.acod.regrucolo.ru:6969/announce",
|
|
||||||
"udp://bt.rer.lol:6969/announce",
|
|
||||||
"udp://amigacity.xyz:6969/announce",
|
|
||||||
"udp://1c.premierzal.ru:6969/announce",
|
|
||||||
"https://trackers.run:443/announce",
|
|
||||||
"https://tracker.yemekyedim.com:443/announce",
|
|
||||||
"https://tracker.renfei.net:443/announce",
|
|
||||||
"https://tracker.pmman.tech:443/announce",
|
|
||||||
"https://tracker.lilithraws.org:443/announce",
|
|
||||||
"https://tracker.imgoingto.icu:443/announce",
|
|
||||||
"https://tracker.cloudit.top:443/announce",
|
|
||||||
"https://tracker-zhuqiy.dgj055.icu:443/announce",
|
|
||||||
"http://tracker.renfei.net:8080/announce",
|
|
||||||
"http://tracker.mywaifu.best:6969/announce",
|
|
||||||
"http://tracker.ipv6tracker.org:80/announce",
|
|
||||||
"http://tracker.files.fm:6969/announce",
|
|
||||||
"http://tracker.edkj.club:6969/announce",
|
|
||||||
"http://tracker.bt4g.com:2095/announce",
|
|
||||||
"http://tracker-zhuqiy.dgj055.icu:80/announce",
|
|
||||||
"http://t1.aag.moe:17715/announce",
|
|
||||||
"http://t.overflow.biz:6969/announce",
|
|
||||||
"http://bittorrent-tracker.e-n-c-r-y-p-t.net:1337/announce",
|
|
||||||
"udp://torrents.artixlinux.org:6969/announce",
|
|
||||||
"udp://mail.artixlinux.org:6969/announce",
|
|
||||||
"udp://ipv4.rer.lol:2710/announce",
|
|
||||||
"udp://concen.org:6969/announce",
|
|
||||||
"udp://bt.rer.lol:2710/announce",
|
|
||||||
"udp://aegir.sexy:6969/announce",
|
|
||||||
"https://www.peckservers.com:9443/announce",
|
|
||||||
"https://tracker.ipfsscan.io:443/announce",
|
|
||||||
"https://tracker.gcrenwp.top:443/announce",
|
|
||||||
"http://www.peckservers.com:9000/announce",
|
|
||||||
"http://tracker1.itzmx.com:8080/announce",
|
|
||||||
"http://ch3oh.ru:6969/announce",
|
|
||||||
"http://bvarf.tracker.sh:2086/announce",
|
|
||||||
];
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TorrentFileEntry {
|
|
||||||
pub index: u32,
|
|
||||||
pub path: String,
|
|
||||||
pub length: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TorrentFilesPayload {
|
|
||||||
pub info_hash: String,
|
|
||||||
pub name: String,
|
|
||||||
pub total_size: i64,
|
|
||||||
pub files: Vec<TorrentFileEntry>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TorrentStatusPayload {
|
|
||||||
pub progress: f64,
|
|
||||||
pub num_peers: u32,
|
|
||||||
pub num_seeds: u32,
|
|
||||||
pub estimated_seeds: u32,
|
|
||||||
pub download_speed: i64,
|
|
||||||
pub upload_speed: i64,
|
|
||||||
pub bytes_downloaded: i64,
|
|
||||||
pub file_size: i64,
|
|
||||||
pub folder_name: String,
|
|
||||||
pub status: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TorrentSeedStatusPayload {
|
|
||||||
pub game_id: String,
|
|
||||||
pub progress: f64,
|
|
||||||
pub num_peers: u32,
|
|
||||||
pub num_seeds: u32,
|
|
||||||
pub estimated_seeds: u32,
|
|
||||||
pub download_speed: i64,
|
|
||||||
pub upload_speed: i64,
|
|
||||||
pub bytes_downloaded: i64,
|
|
||||||
pub file_size: i64,
|
|
||||||
pub folder_name: String,
|
|
||||||
pub status: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
pub struct StartTorrentPayload {
|
|
||||||
pub game_id: String,
|
|
||||||
pub url: String,
|
|
||||||
pub save_path: String,
|
|
||||||
pub folder_name: Option<String>,
|
|
||||||
pub file_indices: Option<Vec<u32>>,
|
|
||||||
pub timeout_ms: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
pub struct ResumeSeedingPayload {
|
|
||||||
pub game_id: String,
|
|
||||||
pub url: String,
|
|
||||||
pub save_path: String,
|
|
||||||
pub folder_name: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CachedTorrentFiles {
|
|
||||||
cached_at: Instant,
|
|
||||||
payload: TorrentFilesPayload,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sanitize_folder_component(value: &str) -> Option<String> {
|
|
||||||
let trimmed = value.trim();
|
|
||||||
if trimmed.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sanitized = String::with_capacity(trimmed.len());
|
|
||||||
|
|
||||||
for ch in trimmed.chars() {
|
|
||||||
let mapped = match ch {
|
|
||||||
'<' | '>' | ':' | '"' | '/' | '\\' | '|' | '?' | '*' => '_',
|
|
||||||
_ if ch.is_control() => '_',
|
|
||||||
_ => ch,
|
|
||||||
};
|
|
||||||
sanitized.push(mapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
let compact = sanitized.trim_matches(['.', ' ']);
|
|
||||||
if compact.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(compact.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_reserved_output_folder(
|
|
||||||
root_save_path: &str,
|
|
||||||
torrent_name: Option<&str>,
|
|
||||||
file_count: usize,
|
|
||||||
info_hash: &str,
|
|
||||||
) -> String {
|
|
||||||
if file_count <= 1 {
|
|
||||||
return root_save_path.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let fallback_hash_len = info_hash.len().min(12);
|
|
||||||
let fallback_name = format!("torrent-{}", &info_hash[..fallback_hash_len]);
|
|
||||||
let folder_name = torrent_name
|
|
||||||
.and_then(sanitize_folder_component)
|
|
||||||
.unwrap_or(fallback_name);
|
|
||||||
|
|
||||||
PathBuf::from(root_save_path)
|
|
||||||
.join(folder_name)
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_single_top_level_folder(files_payload: &TorrentFilesPayload) -> bool {
|
|
||||||
if files_payload.files.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut root_segment: Option<String> = None;
|
|
||||||
|
|
||||||
for file in &files_payload.files {
|
|
||||||
let normalized_path = file.path.replace('\\', "/");
|
|
||||||
let parts = normalized_path
|
|
||||||
.split('/')
|
|
||||||
.filter(|segment| !segment.trim().is_empty())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if parts.len() < 2 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let first_segment = parts[0].to_ascii_lowercase();
|
|
||||||
if let Some(existing_segment) = &root_segment {
|
|
||||||
if existing_segment != &first_segment {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
root_segment = Some(first_segment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
root_segment.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_existing_folder_candidate(
|
|
||||||
root_save_path: &str,
|
|
||||||
folder_name: Option<&str>,
|
|
||||||
) -> Option<String> {
|
|
||||||
let sanitized_folder_name = folder_name
|
|
||||||
.and_then(sanitize_folder_component)
|
|
||||||
.filter(|value| !value.is_empty())?;
|
|
||||||
|
|
||||||
let existing_path = PathBuf::from(root_save_path).join(sanitized_folder_name);
|
|
||||||
if existing_path.is_dir() {
|
|
||||||
return Some(existing_path.to_string_lossy().to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_torrent_output_folder(
|
|
||||||
root_save_path: &str,
|
|
||||||
magnet: &str,
|
|
||||||
info_hash: &str,
|
|
||||||
timeout_ms: u32,
|
|
||||||
folder_name: Option<&str>,
|
|
||||||
) -> String {
|
|
||||||
if let Some(existing_path) = resolve_existing_folder_candidate(root_save_path, folder_name) {
|
|
||||||
return existing_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
match fetch_torrent_files_internal(magnet.to_string(), info_hash.to_string(), timeout_ms) {
|
|
||||||
Ok(files_payload) => {
|
|
||||||
if has_single_top_level_folder(&files_payload) {
|
|
||||||
root_save_path.to_string()
|
|
||||||
} else {
|
|
||||||
build_reserved_output_folder(
|
|
||||||
root_save_path,
|
|
||||||
Some(&files_payload.name),
|
|
||||||
files_payload.files.len(),
|
|
||||||
info_hash,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => root_save_path.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_reserved_output_folder_exists(
|
|
||||||
root_save_path: &str,
|
|
||||||
resolved_save_path: &str,
|
|
||||||
) -> napi::Result<()> {
|
|
||||||
if Path::new(resolved_save_path) == Path::new(root_save_path) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::create_dir_all(resolved_save_path).map_err(|err| Error::from_reason(err.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TorrentManager {
|
|
||||||
downloading_game_id: Option<String>,
|
|
||||||
seeding_game_ids: HashSet<String>,
|
|
||||||
current_download_limit: Option<u32>,
|
|
||||||
torrent_files_cache: HashMap<String, CachedTorrentFiles>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TorrentManager {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
downloading_game_id: None,
|
|
||||||
seeding_game_ids: HashSet::new(),
|
|
||||||
current_download_limit: None,
|
|
||||||
torrent_files_cache: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn normalize_timeout_ms(timeout_ms: Option<u32>, default_ms: u32) -> u32 {
|
|
||||||
let value = timeout_ms.unwrap_or(default_ms);
|
|
||||||
value.clamp(5_000, 120_000)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cache_get(&mut self, info_hash: &str) -> Option<TorrentFilesPayload> {
|
|
||||||
self.prune_expired_cache();
|
|
||||||
self.torrent_files_cache
|
|
||||||
.get(info_hash)
|
|
||||||
.map(|item| item.payload.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cache_set(&mut self, info_hash: String, payload: TorrentFilesPayload) {
|
|
||||||
self.prune_expired_cache();
|
|
||||||
|
|
||||||
if self.torrent_files_cache.len() >= TORRENT_FILES_CACHE_MAX_ITEMS {
|
|
||||||
let oldest_key = self
|
|
||||||
.torrent_files_cache
|
|
||||||
.iter()
|
|
||||||
.min_by_key(|(_, value)| value.cached_at)
|
|
||||||
.map(|(key, _)| key.clone());
|
|
||||||
|
|
||||||
if let Some(key) = oldest_key {
|
|
||||||
self.torrent_files_cache.remove(&key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.torrent_files_cache.insert(
|
|
||||||
info_hash,
|
|
||||||
CachedTorrentFiles {
|
|
||||||
cached_at: Instant::now(),
|
|
||||||
payload,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prune_expired_cache(&mut self) {
|
|
||||||
let ttl = Duration::from_secs(TORRENT_FILES_CACHE_TTL_SECONDS);
|
|
||||||
self.torrent_files_cache
|
|
||||||
.retain(|_, value| value.cached_at.elapsed() <= ttl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TORRENT_MANAGER: Lazy<Mutex<TorrentManager>> =
|
|
||||||
Lazy::new(|| Mutex::new(TorrentManager::new()));
|
|
||||||
|
|
||||||
fn map_bridge_error(error: String) -> napi::Result<()> {
|
|
||||||
if error.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::from_reason(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_session() -> napi::Result<()> {
|
|
||||||
let current_limit = {
|
|
||||||
TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?
|
|
||||||
.current_download_limit
|
|
||||||
};
|
|
||||||
|
|
||||||
map_bridge_error(bridge::init_session(5881, 5892))?;
|
|
||||||
|
|
||||||
if let Some(limit) = current_limit {
|
|
||||||
map_bridge_error(bridge::set_download_limit(limit as i64))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_magnet_uri(raw_magnet: &str) -> napi::Result<(String, String)> {
|
|
||||||
let magnet = raw_magnet.trim();
|
|
||||||
|
|
||||||
if !magnet.starts_with("magnet:") || magnet.len() > 8192 {
|
|
||||||
return Err(Error::from_reason("invalid_magnet"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed = Url::parse(magnet).map_err(|_| Error::from_reason("invalid_magnet"))?;
|
|
||||||
if parsed.scheme() != "magnet" {
|
|
||||||
return Err(Error::from_reason("invalid_magnet"));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (key, value) in parsed.query_pairs() {
|
|
||||||
if key != "xt" {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !value.starts_with("urn:btih:") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hash = value[9..].trim().to_lowercase();
|
|
||||||
if MAGNET_HASH_HEX_RE.is_match(&hash) || MAGNET_HASH_BASE32_RE.is_match(&hash) {
|
|
||||||
return Ok((magnet.to_string(), hash));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::from_reason("invalid_magnet"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_magnet_trackers(magnet: &str) -> Vec<String> {
|
|
||||||
let mut trackers = Vec::new();
|
|
||||||
|
|
||||||
if let Ok(parsed) = Url::parse(magnet) {
|
|
||||||
for (key, value) in parsed.query_pairs() {
|
|
||||||
if key == "tr" {
|
|
||||||
let tracker = value.to_string();
|
|
||||||
if !trackers.contains(&tracker) {
|
|
||||||
trackers.push(tracker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for value in DEFAULT_TRACKERS {
|
|
||||||
let tracker = value.to_string();
|
|
||||||
if !trackers.contains(&tracker) {
|
|
||||||
trackers.push(tracker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trackers
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fetch_torrent_files_internal(
|
|
||||||
magnet: String,
|
|
||||||
info_hash: String,
|
|
||||||
timeout_ms: u32,
|
|
||||||
) -> napi::Result<TorrentFilesPayload> {
|
|
||||||
{
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
|
|
||||||
if let Some(cached) = manager.cache_get(&info_hash) {
|
|
||||||
return Ok(cached);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_session()?;
|
|
||||||
|
|
||||||
let trackers = parse_magnet_trackers(&magnet);
|
|
||||||
let temp_save_path = std::env::temp_dir().to_string_lossy().to_string();
|
|
||||||
|
|
||||||
let bridge_result = bridge::get_torrent_files(
|
|
||||||
&magnet,
|
|
||||||
&temp_save_path,
|
|
||||||
&trackers,
|
|
||||||
timeout_ms,
|
|
||||||
TORRENT_MAX_FILES as u32,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !bridge_result.ok {
|
|
||||||
return Err(Error::from_reason(bridge_result.error));
|
|
||||||
}
|
|
||||||
|
|
||||||
let payload = TorrentFilesPayload {
|
|
||||||
info_hash: info_hash.clone(),
|
|
||||||
name: bridge_result.name,
|
|
||||||
total_size: bridge_result.total_size,
|
|
||||||
files: bridge_result
|
|
||||||
.files
|
|
||||||
.into_iter()
|
|
||||||
.map(|file| TorrentFileEntry {
|
|
||||||
index: file.index,
|
|
||||||
path: file.path,
|
|
||||||
length: file.length,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
manager.cache_set(info_hash, payload.clone());
|
|
||||||
|
|
||||||
Ok(payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_get_status(game_id: String) -> napi::Result<Option<TorrentStatusPayload>> {
|
|
||||||
if game_id.trim().is_empty() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let status = bridge::get_torrent_status(&game_id);
|
|
||||||
if !status.present {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(TorrentStatusPayload {
|
|
||||||
progress: status.progress,
|
|
||||||
num_peers: status.num_peers,
|
|
||||||
num_seeds: status.num_seeds,
|
|
||||||
estimated_seeds: 0,
|
|
||||||
download_speed: status.download_speed,
|
|
||||||
upload_speed: status.upload_speed,
|
|
||||||
bytes_downloaded: status.bytes_downloaded,
|
|
||||||
file_size: status.file_size,
|
|
||||||
folder_name: status.folder_name,
|
|
||||||
status: status.status,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_get_seed_status() -> napi::Result<Vec<TorrentSeedStatusPayload>> {
|
|
||||||
let game_ids = {
|
|
||||||
let manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
|
|
||||||
manager
|
|
||||||
.seeding_game_ids
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut payload = Vec::new();
|
|
||||||
|
|
||||||
for game_id in game_ids {
|
|
||||||
let status = bridge::get_torrent_status(&game_id);
|
|
||||||
if !status.present {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if status.status != HYDRA_TORRENT_STATUS_SEEDING {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
payload.push(TorrentSeedStatusPayload {
|
|
||||||
game_id,
|
|
||||||
progress: status.progress,
|
|
||||||
num_peers: status.num_peers,
|
|
||||||
num_seeds: status.num_seeds,
|
|
||||||
estimated_seeds: 0,
|
|
||||||
download_speed: status.download_speed,
|
|
||||||
upload_speed: status.upload_speed,
|
|
||||||
bytes_downloaded: status.bytes_downloaded,
|
|
||||||
file_size: status.file_size,
|
|
||||||
folder_name: status.folder_name,
|
|
||||||
status: status.status,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub async fn torrent_get_files(
|
|
||||||
magnet: String,
|
|
||||||
timeout_ms: Option<u32>,
|
|
||||||
) -> napi::Result<TorrentFilesPayload> {
|
|
||||||
let (magnet, info_hash) = validate_magnet_uri(&magnet)?;
|
|
||||||
let timeout_ms = TorrentManager::normalize_timeout_ms(timeout_ms, 30_000);
|
|
||||||
fetch_torrent_files_internal(magnet, info_hash, timeout_ms)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub async fn torrent_start(payload: StartTorrentPayload) -> napi::Result<()> {
|
|
||||||
if payload.save_path.trim().is_empty() {
|
|
||||||
return Err(Error::from_reason("invalid_save_path"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (magnet, info_hash) = validate_magnet_uri(&payload.url)?;
|
|
||||||
let selective = payload.file_indices.is_some();
|
|
||||||
let output_resolution_timeout_ms =
|
|
||||||
TorrentManager::normalize_timeout_ms(payload.timeout_ms, 10_000);
|
|
||||||
let timeout_ms = TorrentManager::normalize_timeout_ms(
|
|
||||||
payload.timeout_ms,
|
|
||||||
if selective { 60_000 } else { 30_000 },
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_save_path = resolve_torrent_output_folder(
|
|
||||||
&payload.save_path,
|
|
||||||
&magnet,
|
|
||||||
&info_hash,
|
|
||||||
output_resolution_timeout_ms,
|
|
||||||
payload.folder_name.as_deref(),
|
|
||||||
);
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"[hydra-native][torrent_start] game_id={} save_path={} resolved_save_path={} folder_name_hint={}",
|
|
||||||
payload.game_id,
|
|
||||||
payload.save_path,
|
|
||||||
resolved_save_path,
|
|
||||||
payload.folder_name.as_deref().unwrap_or("")
|
|
||||||
);
|
|
||||||
|
|
||||||
ensure_reserved_output_folder_exists(&payload.save_path, &resolved_save_path)?;
|
|
||||||
|
|
||||||
ensure_session()?;
|
|
||||||
|
|
||||||
let trackers = parse_magnet_trackers(&magnet);
|
|
||||||
let file_indices = payload.file_indices.unwrap_or_default();
|
|
||||||
|
|
||||||
map_bridge_error(bridge::start_torrent(
|
|
||||||
&payload.game_id,
|
|
||||||
&magnet,
|
|
||||||
&resolved_save_path,
|
|
||||||
&trackers,
|
|
||||||
&file_indices,
|
|
||||||
selective,
|
|
||||||
false,
|
|
||||||
timeout_ms,
|
|
||||||
))?;
|
|
||||||
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
manager.downloading_game_id = Some(payload.game_id.clone());
|
|
||||||
manager.seeding_game_ids.remove(&payload.game_id);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_pause(game_id: String) -> napi::Result<()> {
|
|
||||||
map_bridge_error(bridge::pause_torrent(&game_id))?;
|
|
||||||
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
if manager.downloading_game_id.as_deref() == Some(game_id.as_str()) {
|
|
||||||
manager.downloading_game_id = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_cancel(game_id: String) -> napi::Result<()> {
|
|
||||||
map_bridge_error(bridge::cancel_torrent(&game_id))?;
|
|
||||||
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
manager.seeding_game_ids.remove(&game_id);
|
|
||||||
|
|
||||||
if manager.downloading_game_id.as_deref() == Some(game_id.as_str()) {
|
|
||||||
manager.downloading_game_id = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_resume_seeding(payload: ResumeSeedingPayload) -> napi::Result<()> {
|
|
||||||
if payload.save_path.trim().is_empty() {
|
|
||||||
return Err(Error::from_reason("invalid_save_path"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (magnet, info_hash) = validate_magnet_uri(&payload.url)?;
|
|
||||||
ensure_session()?;
|
|
||||||
|
|
||||||
let resolved_save_path = resolve_torrent_output_folder(
|
|
||||||
&payload.save_path,
|
|
||||||
&magnet,
|
|
||||||
&info_hash,
|
|
||||||
15_000,
|
|
||||||
payload.folder_name.as_deref(),
|
|
||||||
);
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"[hydra-native][torrent_resume_seeding] game_id={} save_path={} resolved_save_path={} folder_name_hint={}",
|
|
||||||
payload.game_id,
|
|
||||||
payload.save_path,
|
|
||||||
resolved_save_path,
|
|
||||||
payload.folder_name.as_deref().unwrap_or("")
|
|
||||||
);
|
|
||||||
|
|
||||||
ensure_reserved_output_folder_exists(&payload.save_path, &resolved_save_path)?;
|
|
||||||
|
|
||||||
let trackers = parse_magnet_trackers(&magnet);
|
|
||||||
let no_file_indices = Vec::<u32>::new();
|
|
||||||
|
|
||||||
map_bridge_error(bridge::start_torrent(
|
|
||||||
&payload.game_id,
|
|
||||||
&magnet,
|
|
||||||
&resolved_save_path,
|
|
||||||
&trackers,
|
|
||||||
&no_file_indices,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
30_000,
|
|
||||||
))?;
|
|
||||||
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
manager.seeding_game_ids.insert(payload.game_id);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_pause_seeding(game_id: String) -> napi::Result<()> {
|
|
||||||
torrent_cancel(game_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_set_download_limit(
|
|
||||||
max_download_speed_bytes_per_second: Option<u32>,
|
|
||||||
) -> napi::Result<()> {
|
|
||||||
let limit = max_download_speed_bytes_per_second.filter(|value| *value > 0);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut manager = TORRENT_MANAGER
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| Error::from_reason("internal_error"))?;
|
|
||||||
manager.current_download_limit = limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_session()?;
|
|
||||||
|
|
||||||
map_bridge_error(bridge::set_download_limit(
|
|
||||||
limit.map(|value| value as i64).unwrap_or(0),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn torrent_backend() -> String {
|
|
||||||
"libtorrent".to_string()
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,2 @@
|
|||||||
libtorrent
|
libtorrent
|
||||||
cx_Freeze == 7.2.3
|
cx_Freeze == 7.2.3
|
||||||
cx_Logging; sys_platform == 'win32'
|
|
||||||
pywin32; sys_platform == 'win32'
|
|
||||||
|
|||||||
@@ -72,52 +72,6 @@ const copySidecarLibrariesOnWindows = async (sourceDirectory) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const listUnixDependencies = async (binaryPath) => {
|
|
||||||
if (process.platform === "linux") {
|
|
||||||
const { stdout } = await execFile("ldd", [binaryPath], {
|
|
||||||
cwd: projectRoot,
|
|
||||||
maxBuffer: 1024 * 1024 * 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
return stdout
|
|
||||||
.split("\n")
|
|
||||||
.map((line) => line.trim())
|
|
||||||
.map((line) => {
|
|
||||||
const match = line.match(/=>\s+(\/[^\s]+)\s+\(/);
|
|
||||||
return match ? match[1] : null;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const shouldBundleUnixDependency = (dependencyPath) => {
|
|
||||||
const basename = path.basename(dependencyPath);
|
|
||||||
|
|
||||||
return (
|
|
||||||
basename.startsWith("libtorrent-rasterbar") ||
|
|
||||||
basename.startsWith("libboost_")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const copySidecarLibrariesOnUnix = async () => {
|
|
||||||
if (process.platform !== "linux") return;
|
|
||||||
|
|
||||||
const dependencies = await listUnixDependencies(outputNodePath);
|
|
||||||
|
|
||||||
for (const dependencyPath of dependencies) {
|
|
||||||
if (!shouldBundleUnixDependency(dependencyPath)) continue;
|
|
||||||
if (!fs.existsSync(dependencyPath)) continue;
|
|
||||||
|
|
||||||
const targetPath = path.join(outputDir, path.basename(dependencyPath));
|
|
||||||
|
|
||||||
if (!fs.existsSync(targetPath)) {
|
|
||||||
fs.copyFileSync(dependencyPath, targetPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const build = async () => {
|
const build = async () => {
|
||||||
const sourceLibraryName = sourceLibraryNameByPlatform[process.platform];
|
const sourceLibraryName = sourceLibraryNameByPlatform[process.platform];
|
||||||
|
|
||||||
@@ -127,7 +81,7 @@ const build = async () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Building hydra-native Rust addon (libtorrent)...");
|
console.log("Building hydra-native Rust addon...");
|
||||||
|
|
||||||
const cargoArgs = [
|
const cargoArgs = [
|
||||||
"build",
|
"build",
|
||||||
@@ -154,7 +108,6 @@ const build = async () => {
|
|||||||
fs.copyFileSync(sourceLibraryPath, outputNodePath);
|
fs.copyFileSync(sourceLibraryPath, outputNodePath);
|
||||||
|
|
||||||
await copySidecarLibrariesOnWindows(path.dirname(sourceLibraryPath));
|
await copySidecarLibrariesOnWindows(path.dirname(sourceLibraryPath));
|
||||||
await copySidecarLibrariesOnUnix();
|
|
||||||
await ensureDepsResolvableOnLinux();
|
await ensureDepsResolvableOnLinux();
|
||||||
|
|
||||||
console.log(`Hydra native addon ready at ${outputNodePath}`);
|
console.log(`Hydra native addon ready at ${outputNodePath}`);
|
||||||
|
|||||||
+1
-1
@@ -280,7 +280,7 @@ app.on("before-quit", async (e) => {
|
|||||||
if (!canAppBeClosed) {
|
if (!canAppBeClosed) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
PowerSaveBlockerManager.reset();
|
PowerSaveBlockerManager.reset();
|
||||||
/* Disconnects libtorrent */
|
/* Disconnects Python RPC */
|
||||||
PythonRPC.kill();
|
PythonRPC.kill();
|
||||||
await clearGamesPlaytime();
|
await clearGamesPlaytime();
|
||||||
canAppBeClosed = true;
|
canAppBeClosed = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user