feat: align motrix-style download UI/actions and stabilize aria2 ops
This commit is contained in:
67
src-tauri/Cargo.lock
generated
67
src-tauri/Cargo.lock
generated
@@ -86,6 +86,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-log",
|
||||
]
|
||||
|
||||
@@ -668,6 +669,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
@@ -2955,6 +2958,30 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"dispatch2",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"js-sys",
|
||||
"log",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation",
|
||||
"raw-window-handle",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -3760,6 +3787,46 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
"rfd",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 2.0.18",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
"glob",
|
||||
"percent-encoding",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.18",
|
||||
"toml 0.9.12+spec-1.1.0",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.8.0"
|
||||
|
||||
@@ -23,5 +23,6 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
tauri = { version = "2.10.0", features = [] }
|
||||
tauri-plugin-log = "2"
|
||||
tauri-plugin-dialog = "2"
|
||||
reqwest = { version = "0.12.24", default-features = false, features = ["json", "rustls-tls"] }
|
||||
base64 = "0.22"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default"
|
||||
"core:default",
|
||||
"dialog:allow-open"
|
||||
]
|
||||
}
|
||||
|
||||
91
src-tauri/resources/engine/darwin/arm64/aria2.conf
Normal file
91
src-tauri/resources/engine/darwin/arm64/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix macOS Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=none
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/darwin/arm64/aria2c
Executable file
BIN
src-tauri/resources/engine/darwin/arm64/aria2c
Executable file
Binary file not shown.
91
src-tauri/resources/engine/darwin/x64/aria2.conf
Normal file
91
src-tauri/resources/engine/darwin/x64/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix macOS Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=none
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/darwin/x64/aria2c
Executable file
BIN
src-tauri/resources/engine/darwin/x64/aria2c
Executable file
Binary file not shown.
91
src-tauri/resources/engine/linux/arm64/aria2.conf
Normal file
91
src-tauri/resources/engine/linux/arm64/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix Linux Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=trunc
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/linux/arm64/aria2c
Executable file
BIN
src-tauri/resources/engine/linux/arm64/aria2c
Executable file
Binary file not shown.
91
src-tauri/resources/engine/linux/armv7l/aria2.conf
Normal file
91
src-tauri/resources/engine/linux/armv7l/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix Linux Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=trunc
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/linux/armv7l/aria2c
Executable file
BIN
src-tauri/resources/engine/linux/armv7l/aria2c
Executable file
Binary file not shown.
91
src-tauri/resources/engine/linux/x64/aria2.conf
Normal file
91
src-tauri/resources/engine/linux/x64/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix Linux Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=trunc
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/linux/x64/aria2c
Executable file
BIN
src-tauri/resources/engine/linux/x64/aria2c
Executable file
Binary file not shown.
91
src-tauri/resources/engine/win32/ia32/aria2.conf
Normal file
91
src-tauri/resources/engine/win32/ia32/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix Windows Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=none
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/win32/ia32/aria2c.exe
Executable file
BIN
src-tauri/resources/engine/win32/ia32/aria2c.exe
Executable file
Binary file not shown.
91
src-tauri/resources/engine/win32/x64/aria2.conf
Normal file
91
src-tauri/resources/engine/win32/x64/aria2.conf
Normal file
@@ -0,0 +1,91 @@
|
||||
###############################
|
||||
# Motrix Windows Aria2 config file
|
||||
#
|
||||
# @see https://aria2.github.io/manual/en/html/aria2c.html
|
||||
#
|
||||
###############################
|
||||
|
||||
|
||||
################ RPC ################
|
||||
# Enable JSON-RPC/XML-RPC server.
|
||||
enable-rpc=true
|
||||
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
|
||||
rpc-allow-origin-all=true
|
||||
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
|
||||
rpc-listen-all=true
|
||||
|
||||
|
||||
################ File system ################
|
||||
# Save a control file(*.aria2) every SEC seconds.
|
||||
auto-save-interval=10
|
||||
# Enable disk cache.
|
||||
disk-cache=64M
|
||||
# Specify file allocation method.
|
||||
file-allocation=falloc
|
||||
# No file allocation is made for files whose size is smaller than SIZE
|
||||
no-file-allocation-limit=64M
|
||||
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
|
||||
save-session-interval=10
|
||||
|
||||
|
||||
################ Task ################
|
||||
# Exclude seed only downloads when counting concurrent active downloads
|
||||
bt-detach-seed-only=true
|
||||
# Verify the peer using certificates specified in --ca-certificate option.
|
||||
check-certificate=false
|
||||
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
|
||||
# without getting a single byte, then force the download to fail.
|
||||
max-file-not-found=10
|
||||
# Set number of tries.
|
||||
max-tries=0
|
||||
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
|
||||
retry-wait=10
|
||||
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
|
||||
connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
timeout=10
|
||||
# aria2 does not split less than 2*SIZE byte range.
|
||||
min-split-size=1M
|
||||
# Send Accept: deflate, gzip request header.
|
||||
http-accept-gzip=true
|
||||
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
|
||||
remote-time=true
|
||||
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
|
||||
summary-interval=0
|
||||
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
|
||||
content-disposition-default-utf8=true
|
||||
|
||||
|
||||
################ BT Task ################
|
||||
# Enable Local Peer Discovery.
|
||||
bt-enable-lpd=true
|
||||
# Requires BitTorrent message payload encryption with arc4.
|
||||
# bt-force-encryption=true
|
||||
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
|
||||
bt-hash-check-seed=true
|
||||
# Specify the maximum number of peers per torrent.
|
||||
bt-max-peers=128
|
||||
# Try to download first and last pieces of each file first. This is useful for previewing files.
|
||||
bt-prioritize-piece=head
|
||||
# Removes the unselected files when download is completed in BitTorrent.
|
||||
bt-remove-unselected-file=true
|
||||
# Seed previously downloaded files without verifying piece hashes.
|
||||
bt-seed-unverified=false
|
||||
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
|
||||
bt-tracker-connect-timeout=10
|
||||
# Set timeout in seconds.
|
||||
bt-tracker-timeout=10
|
||||
# Set host and port as an entry point to IPv4 DHT network.
|
||||
dht-entry-point=dht.transmissionbt.com:6881
|
||||
# Set host and port as an entry point to IPv6 DHT network.
|
||||
dht-entry-point6=dht.transmissionbt.com:6881
|
||||
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
|
||||
enable-dht=true
|
||||
# Enable IPv6 DHT functionality.
|
||||
enable-dht6=true
|
||||
# Enable Peer Exchange extension.
|
||||
enable-peer-exchange=true
|
||||
# Specify the string used during the bitorrent extended handshake for the peer's client version.
|
||||
peer-agent=Transmission/3.00
|
||||
# Specify the prefix of peer ID.
|
||||
peer-id-prefix=-TR3000-
|
||||
BIN
src-tauri/resources/engine/win32/x64/aria2c.exe
Executable file
BIN
src-tauri/resources/engine/win32/x64/aria2c.exe
Executable file
Binary file not shown.
@@ -2,11 +2,13 @@ use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use std::env;
|
||||
use std::net::{SocketAddr, TcpStream};
|
||||
use std::path::Path;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::Mutex;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tauri::State;
|
||||
use tauri::{Manager, State};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -46,6 +48,13 @@ pub struct Aria2AddTorrentRequest {
|
||||
pub split: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Aria2TaskCommandRequest {
|
||||
pub rpc: Aria2RpcConfig,
|
||||
pub gid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EngineStatusResponse {
|
||||
@@ -66,6 +75,7 @@ pub struct Aria2TaskSummary {
|
||||
pub download_speed: String,
|
||||
pub dir: String,
|
||||
pub file_name: String,
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@@ -84,9 +94,20 @@ pub struct TorrentFilePayload {
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Aria2BinaryProbeResponse {
|
||||
pub found: bool,
|
||||
pub binary_path: Option<String>,
|
||||
pub source: Option<String>,
|
||||
pub candidates: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EngineRuntime {
|
||||
child: Option<Child>,
|
||||
external_reuse: bool,
|
||||
rpc_port: Option<u16>,
|
||||
binary_path: Option<String>,
|
||||
args: Vec<String>,
|
||||
started_at: Option<u64>,
|
||||
@@ -96,6 +117,8 @@ impl Default for EngineRuntime {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
child: None,
|
||||
external_reuse: false,
|
||||
rpc_port: None,
|
||||
binary_path: None,
|
||||
args: vec![],
|
||||
started_at: None,
|
||||
@@ -111,7 +134,7 @@ pub struct EngineState {
|
||||
impl EngineState {
|
||||
fn status(runtime: &EngineRuntime) -> EngineStatusResponse {
|
||||
EngineStatusResponse {
|
||||
running: runtime.child.is_some(),
|
||||
running: runtime.child.is_some() || runtime.external_reuse,
|
||||
pid: runtime.child.as_ref().map(std::process::Child::id),
|
||||
binary_path: runtime.binary_path.clone(),
|
||||
args: runtime.args.clone(),
|
||||
@@ -153,6 +176,133 @@ fn default_aria2_binary() -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_binary_hint(binary_hint: Option<&str>) -> String {
|
||||
let value = binary_hint.unwrap_or("").trim();
|
||||
if value.is_empty() {
|
||||
default_aria2_binary()
|
||||
} else {
|
||||
value.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn candidate_push(path: &Path, out: &mut Vec<String>) {
|
||||
if let Some(s) = path.to_str() {
|
||||
let v = s.trim();
|
||||
if !v.is_empty() {
|
||||
out.push(v.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn platform_aliases() -> Vec<&'static str> {
|
||||
match env::consts::OS {
|
||||
"macos" => vec!["macos", "darwin"],
|
||||
"windows" => vec!["windows", "win32"],
|
||||
"linux" => vec!["linux"],
|
||||
_ => vec![env::consts::OS],
|
||||
}
|
||||
}
|
||||
|
||||
fn arch_aliases() -> Vec<&'static str> {
|
||||
match env::consts::ARCH {
|
||||
"aarch64" => vec!["aarch64", "arm64"],
|
||||
"x86_64" => vec!["x86_64", "x64"],
|
||||
"x86" => vec!["x86", "ia32"],
|
||||
"arm" => vec!["arm", "armv7l"],
|
||||
other => vec![other],
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_binary_candidates(app: &tauri::AppHandle, binary_hint: Option<&str>) -> Vec<String> {
|
||||
let binary_name = normalize_binary_hint(binary_hint);
|
||||
let mut candidates: Vec<String> = vec![];
|
||||
|
||||
if let Some(raw) = binary_hint.map(str::trim).filter(|v| !v.is_empty()) {
|
||||
candidates.push(raw.to_string());
|
||||
}
|
||||
|
||||
if let Ok(env_path) = env::var("ARIA2C_BIN") {
|
||||
let trimmed = env_path.trim();
|
||||
if !trimmed.is_empty() {
|
||||
candidates.push(trimmed.to_string());
|
||||
}
|
||||
}
|
||||
if let Ok(env_path) = env::var("ARIA2C_PATH") {
|
||||
let trimmed = env_path.trim();
|
||||
if !trimmed.is_empty() {
|
||||
candidates.push(trimmed.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(path_var) = env::var_os("PATH") {
|
||||
for dir in env::split_paths(&path_var) {
|
||||
candidate_push(&dir.join(&binary_name), &mut candidates);
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let lower = binary_name.to_ascii_lowercase();
|
||||
if !lower.ends_with(".exe") {
|
||||
candidate_push(&dir.join(format!("{binary_name}.exe")), &mut candidates);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let source_engine_base = Path::new(env!("CARGO_MANIFEST_DIR")).join("resources").join("engine");
|
||||
let mut engine_bases = vec![source_engine_base];
|
||||
if let Ok(resource_dir) = app.path().resource_dir() {
|
||||
engine_bases.push(resource_dir.join("engine"));
|
||||
}
|
||||
|
||||
let platforms = platform_aliases();
|
||||
let arches = arch_aliases();
|
||||
for base in engine_bases {
|
||||
for platform in &platforms {
|
||||
for arch in &arches {
|
||||
candidate_push(&base.join(platform).join(arch).join(&binary_name), &mut candidates);
|
||||
}
|
||||
candidate_push(&base.join(platform).join(&binary_name), &mut candidates);
|
||||
}
|
||||
candidate_push(&base.join(&binary_name), &mut candidates);
|
||||
}
|
||||
|
||||
let mut deduped = Vec::with_capacity(candidates.len());
|
||||
for path in candidates {
|
||||
if !deduped.contains(&path) {
|
||||
deduped.push(path);
|
||||
}
|
||||
}
|
||||
deduped
|
||||
}
|
||||
|
||||
fn resolve_binary_from_candidates(candidates: &[String]) -> Option<(String, String)> {
|
||||
for (idx, candidate) in candidates.iter().enumerate() {
|
||||
let path = Path::new(candidate);
|
||||
if path.is_file() {
|
||||
let source = if idx == 0 { "user_or_default" } else { "auto_detected" };
|
||||
return Some((candidate.clone(), source.to_string()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn classify_engine_spawn_error(binary: &str, err: &std::io::Error) -> String {
|
||||
use std::io::ErrorKind;
|
||||
match err.kind() {
|
||||
ErrorKind::NotFound => format!(
|
||||
"aria2 binary not found: '{binary}'. Binary Path를 지정하거나 PATH/resources/engine 경로를 확인하세요."
|
||||
),
|
||||
ErrorKind::PermissionDenied => {
|
||||
format!("aria2 binary is not executable: '{binary}'. 실행 권한(chmod +x)을 확인하세요.")
|
||||
}
|
||||
_ => format!("failed to start aria2 engine with '{binary}': {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_local_port_open(port: u16) -> bool {
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
TcpStream::connect_timeout(&addr, std::time::Duration::from_millis(220)).is_ok()
|
||||
}
|
||||
|
||||
fn rpc_endpoint(config: &Aria2RpcConfig) -> String {
|
||||
format!(
|
||||
"http://127.0.0.1:{}/jsonrpc",
|
||||
@@ -249,6 +399,17 @@ fn map_task(task: &Value) -> Aria2TaskSummary {
|
||||
download_speed: value_to_string(task.get("downloadSpeed")),
|
||||
dir: value_to_string(task.get("dir")),
|
||||
file_name: pick_file_name(file_path),
|
||||
uri: task
|
||||
.get("files")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|files| files.first())
|
||||
.and_then(|file| file.get("uris"))
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|uris| uris.first())
|
||||
.and_then(|uri| uri.get("uri"))
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,16 +438,33 @@ fn build_rpc_options(out: Option<&String>, dir: Option<&String>, split: Option<u
|
||||
Value::Object(options)
|
||||
}
|
||||
|
||||
fn is_gid_not_found_error(message: &str) -> bool {
|
||||
let lower = message.to_ascii_lowercase();
|
||||
lower.contains("not found for gid#")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn engine_start(
|
||||
app: tauri::AppHandle,
|
||||
state: State<'_, EngineState>,
|
||||
request: EngineStartRequest,
|
||||
) -> Result<EngineStatusResponse, String> {
|
||||
let rpc_port = request.rpc_listen_port.unwrap_or(6800);
|
||||
let mut runtime = state
|
||||
.runtime
|
||||
.lock()
|
||||
.map_err(|err| format!("failed to lock engine state: {err}"))?;
|
||||
|
||||
if runtime.external_reuse {
|
||||
if let Some(port) = runtime.rpc_port {
|
||||
if is_local_port_open(port) {
|
||||
return Ok(EngineState::status(&runtime));
|
||||
}
|
||||
}
|
||||
runtime.external_reuse = false;
|
||||
runtime.rpc_port = None;
|
||||
}
|
||||
|
||||
if let Some(child) = runtime.child.as_mut() {
|
||||
match child.try_wait() {
|
||||
Ok(Some(_)) => {
|
||||
@@ -302,7 +480,31 @@ pub fn engine_start(
|
||||
}
|
||||
|
||||
let args = build_engine_args(&request);
|
||||
let binary = request.binary_path.unwrap_or_else(default_aria2_binary);
|
||||
|
||||
// Reuse existing engine when the target RPC port is already occupied.
|
||||
// This mirrors Motrix-style behavior where an already-running aria2 instance is reused.
|
||||
if is_local_port_open(rpc_port) {
|
||||
runtime.child = None;
|
||||
runtime.external_reuse = true;
|
||||
runtime.rpc_port = Some(rpc_port);
|
||||
runtime.binary_path = Some(format!("external://127.0.0.1:{rpc_port}"));
|
||||
runtime.args = args;
|
||||
runtime.started_at = Some(
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map_err(|err| format!("failed to get system time: {err}"))?
|
||||
.as_secs(),
|
||||
);
|
||||
return Ok(EngineState::status(&runtime));
|
||||
}
|
||||
|
||||
let candidates = collect_binary_candidates(&app, request.binary_path.as_deref());
|
||||
let (binary, _) = resolve_binary_from_candidates(&candidates).ok_or_else(|| {
|
||||
let sample = candidates.into_iter().take(6).collect::<Vec<String>>().join(", ");
|
||||
format!(
|
||||
"aria2 binary를 찾지 못했습니다. Binary Path를 직접 지정하세요. (검색 후보: {sample})"
|
||||
)
|
||||
})?;
|
||||
|
||||
let child = Command::new(&binary)
|
||||
.args(&args)
|
||||
@@ -310,9 +512,25 @@ pub fn engine_start(
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.spawn()
|
||||
.map_err(|err| format!("failed to start aria2 engine with '{binary}': {err}"))?;
|
||||
.map_err(|err| classify_engine_spawn_error(&binary, &err))?;
|
||||
|
||||
let mut child = child;
|
||||
std::thread::sleep(std::time::Duration::from_millis(220));
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
return Err(format!(
|
||||
"aria2 engine exited immediately (status={status}). 포트 충돌 또는 잘못된 옵션일 수 있습니다."
|
||||
));
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
return Err(format!("failed to inspect aria2 engine process: {err}"));
|
||||
}
|
||||
}
|
||||
|
||||
runtime.child = Some(child);
|
||||
runtime.external_reuse = false;
|
||||
runtime.rpc_port = Some(rpc_port);
|
||||
runtime.binary_path = Some(binary);
|
||||
runtime.args = args;
|
||||
runtime.started_at = Some(
|
||||
@@ -325,6 +543,21 @@ pub fn engine_start(
|
||||
Ok(EngineState::status(&runtime))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn detect_aria2_binary(
|
||||
app: tauri::AppHandle,
|
||||
binary_path: Option<String>,
|
||||
) -> Aria2BinaryProbeResponse {
|
||||
let candidates = collect_binary_candidates(&app, binary_path.as_deref());
|
||||
let resolved = resolve_binary_from_candidates(&candidates);
|
||||
Aria2BinaryProbeResponse {
|
||||
found: resolved.is_some(),
|
||||
binary_path: resolved.as_ref().map(|v| v.0.clone()),
|
||||
source: resolved.map(|v| v.1),
|
||||
candidates,
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn engine_stop(state: State<'_, EngineState>) -> Result<EngineStatusResponse, String> {
|
||||
let mut runtime = state
|
||||
@@ -339,6 +572,8 @@ pub fn engine_stop(state: State<'_, EngineState>) -> Result<EngineStatusResponse
|
||||
let _ = child.wait();
|
||||
}
|
||||
|
||||
runtime.external_reuse = false;
|
||||
runtime.rpc_port = None;
|
||||
runtime.started_at = None;
|
||||
Ok(EngineState::status(&runtime))
|
||||
}
|
||||
@@ -363,6 +598,15 @@ pub fn engine_status(state: State<'_, EngineState>) -> Result<EngineStatusRespon
|
||||
}
|
||||
}
|
||||
|
||||
if runtime.external_reuse {
|
||||
let alive = runtime.rpc_port.map(is_local_port_open).unwrap_or(false);
|
||||
if !alive {
|
||||
runtime.external_reuse = false;
|
||||
runtime.rpc_port = None;
|
||||
runtime.started_at = None;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(EngineState::status(&runtime))
|
||||
}
|
||||
|
||||
@@ -426,6 +670,105 @@ pub async fn aria2_list_tasks(config: Aria2RpcConfig) -> Result<Aria2TaskSnapsho
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn aria2_pause_task(request: Aria2TaskCommandRequest) -> Result<String, String> {
|
||||
let gid = request.gid.trim();
|
||||
if gid.is_empty() {
|
||||
return Err("gid is required".to_string());
|
||||
}
|
||||
let client = Client::new();
|
||||
let result = call_aria2_rpc(&client, &request.rpc, "aria2.pause", vec![json!(gid)]).await?;
|
||||
result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.pause returned unexpected result: {result}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn aria2_resume_task(request: Aria2TaskCommandRequest) -> Result<String, String> {
|
||||
let gid = request.gid.trim();
|
||||
if gid.is_empty() {
|
||||
return Err("gid is required".to_string());
|
||||
}
|
||||
let client = Client::new();
|
||||
let result = call_aria2_rpc(&client, &request.rpc, "aria2.unpause", vec![json!(gid)]).await?;
|
||||
result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.unpause returned unexpected result: {result}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn aria2_remove_task(request: Aria2TaskCommandRequest) -> Result<String, String> {
|
||||
let gid = request.gid.trim();
|
||||
if gid.is_empty() {
|
||||
return Err("gid is required".to_string());
|
||||
}
|
||||
let client = Client::new();
|
||||
match call_aria2_rpc(&client, &request.rpc, "aria2.remove", vec![json!(gid)]).await {
|
||||
Ok(result) => result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.remove returned unexpected result: {result}")),
|
||||
Err(err) if is_gid_not_found_error(&err) => {
|
||||
match call_aria2_rpc(
|
||||
&client,
|
||||
&request.rpc,
|
||||
"aria2.removeDownloadResult",
|
||||
vec![json!(gid)],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.removeDownloadResult returned unexpected result: {result}")),
|
||||
Err(fallback_err) if is_gid_not_found_error(&fallback_err) => Ok(gid.to_string()),
|
||||
Err(fallback_err) => Err(fallback_err),
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn aria2_remove_task_record(request: Aria2TaskCommandRequest) -> Result<String, String> {
|
||||
let gid = request.gid.trim();
|
||||
if gid.is_empty() {
|
||||
return Err("gid is required".to_string());
|
||||
}
|
||||
let client = Client::new();
|
||||
match call_aria2_rpc(&client, &request.rpc, "aria2.removeDownloadResult", vec![json!(gid)]).await
|
||||
{
|
||||
Ok(result) => result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.removeDownloadResult returned unexpected result: {result}")),
|
||||
Err(err) if is_gid_not_found_error(&err) => Ok(gid.to_string()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn aria2_pause_all(config: Aria2RpcConfig) -> Result<String, String> {
|
||||
let client = Client::new();
|
||||
let result = call_aria2_rpc(&client, &config, "aria2.pauseAll", vec![]).await?;
|
||||
result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.pauseAll returned unexpected result: {result}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn aria2_resume_all(config: Aria2RpcConfig) -> Result<String, String> {
|
||||
let client = Client::new();
|
||||
let result = call_aria2_rpc(&client, &config, "aria2.unpauseAll", vec![]).await?;
|
||||
result
|
||||
.as_str()
|
||||
.map(|value| value.to_string())
|
||||
.ok_or_else(|| format!("aria2.unpauseAll returned unexpected result: {result}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn load_torrent_file(path: String) -> Result<TorrentFilePayload, String> {
|
||||
if !path.to_ascii_lowercase().ends_with(".torrent") {
|
||||
@@ -445,3 +788,34 @@ pub fn load_torrent_file(path: String) -> Result<TorrentFilePayload, String> {
|
||||
size: bytes.len() as u64,
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_path_in_file_manager(path: String) -> Result<(), String> {
|
||||
let target = path.trim();
|
||||
if target.is_empty() {
|
||||
return Err("path is required".to_string());
|
||||
}
|
||||
|
||||
let mut command = if cfg!(target_os = "macos") {
|
||||
let mut cmd = Command::new("open");
|
||||
cmd.arg(target);
|
||||
cmd
|
||||
} else if cfg!(target_os = "windows") {
|
||||
let mut cmd = Command::new("explorer");
|
||||
cmd.arg(target);
|
||||
cmd
|
||||
} else {
|
||||
let mut cmd = Command::new("xdg-open");
|
||||
cmd.arg(target);
|
||||
cmd
|
||||
};
|
||||
|
||||
let status = command
|
||||
.status()
|
||||
.map_err(|err| format!("failed to open path in file manager: {err}"))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(format!("file manager command exited with status: {status}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
mod engine;
|
||||
|
||||
use engine::{
|
||||
aria2_add_torrent, aria2_add_uri, aria2_list_tasks, engine_start, engine_status, engine_stop,
|
||||
load_torrent_file, EngineState,
|
||||
aria2_add_torrent, aria2_add_uri, aria2_list_tasks, aria2_pause_all, aria2_pause_task,
|
||||
aria2_remove_task, aria2_remove_task_record, aria2_resume_all, aria2_resume_task,
|
||||
detect_aria2_binary, engine_start, engine_status, engine_stop, load_torrent_file,
|
||||
open_path_in_file_manager, EngineState,
|
||||
};
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.manage(EngineState::default())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.setup(|app| {
|
||||
if cfg!(debug_assertions) {
|
||||
app.handle().plugin(
|
||||
@@ -23,10 +26,18 @@ pub fn run() {
|
||||
engine_start,
|
||||
engine_stop,
|
||||
engine_status,
|
||||
detect_aria2_binary,
|
||||
aria2_add_torrent,
|
||||
aria2_add_uri,
|
||||
aria2_list_tasks,
|
||||
load_torrent_file
|
||||
aria2_pause_task,
|
||||
aria2_resume_task,
|
||||
aria2_remove_task,
|
||||
aria2_remove_task_record,
|
||||
aria2_pause_all,
|
||||
aria2_resume_all,
|
||||
load_torrent_file,
|
||||
open_path_in_file_manager
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"label": "main",
|
||||
"title": "gdown",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"width": 1280,
|
||||
"height": 860,
|
||||
"minWidth": 1080,
|
||||
"minHeight": 720,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
}
|
||||
@@ -26,6 +29,9 @@
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"resources": [
|
||||
"resources/engine/**/*"
|
||||
],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
|
||||
Reference in New Issue
Block a user