[Feature] Add environment variables support to rqbit binary

This commit is contained in:
Igor Katson 2024-08-26 12:07:22 +01:00
parent c12fcd7902
commit 3ff07a39d7
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
3 changed files with 69 additions and 58 deletions

40
Cargo.lock generated
View file

@ -456,9 +456,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.18" version = "4.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -466,32 +466,32 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.18" version = "4.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
"clap_lex", "clap_lex",
"strsim 0.10.0", "strsim",
] ]
[[package]] [[package]]
name = "clap_complete" name = "clap_complete"
version = "4.4.10" version = "4.5.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3" checksum = "531d7959c5bbb6e266cecdd0f20213639c3a5c3e4d615f97db87661745f781ff"
dependencies = [ dependencies = [
"clap", "clap",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.4.7" version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [ dependencies = [
"heck 0.4.1", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -499,9 +499,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.6.0" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
@ -694,7 +694,7 @@ dependencies = [
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.11.1", "strsim",
"syn", "syn",
] ]
@ -1121,12 +1121,6 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@ -2982,7 +2976,7 @@ checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776"
dependencies = [ dependencies = [
"dotenvy", "dotenvy",
"either", "either",
"heck 0.5.0", "heck",
"hex 0.4.3", "hex 0.4.3",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
@ -3120,12 +3114,6 @@ dependencies = [
"unicode-properties", "unicode-properties",
] ]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"

View file

@ -31,8 +31,8 @@ librqbit = { path = "../librqbit", default-features = false, features = [
tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
console-subscriber = { version = "0.2", optional = true } console-subscriber = { version = "0.2", optional = true }
anyhow = "1" anyhow = "1"
clap = { version = "~4.4", features = ["derive", "deprecated"] } clap = { version = "4.5", features = ["derive", "deprecated", "env"] }
clap_complete = "~4.4" clap_complete = "4.5"
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
regex = "1" regex = "1"

View file

@ -32,77 +32,99 @@ enum LogLevel {
#[command(version, author, about)] #[command(version, author, about)]
struct Opts { struct Opts {
/// The console loglevel /// The console loglevel
#[arg(value_enum, short = 'v')] #[arg(value_enum, short = 'v', env = "RQBIT_LOG_LEVEL_CONSOLE")]
log_level: Option<LogLevel>, log_level: Option<LogLevel>,
/// The log filename to also write to in addition to the console. /// The log filename to also write to in addition to the console.
#[arg(long = "log-file")] #[arg(long = "log-file", env = "RQBIT_LOG_FILE")]
log_file: Option<String>, log_file: Option<String>,
/// The value for RUST_LOG in the log file /// The value for RUST_LOG in the log file
#[arg(long = "log-file-rust-log", default_value = "librqbit=debug,info")] #[arg(
long = "log-file-rust-log",
default_value = "librqbit=debug,info",
env = "RQBIT_LOG_FILE_RUST_LOG"
)]
log_file_rust_log: String, log_file_rust_log: String,
/// The interval to poll trackers, e.g. 30s. /// The interval to poll trackers, e.g. 30s.
/// Trackers send the refresh interval when we connect to them. Often this is /// Trackers send the refresh interval when we connect to them. Often this is
/// pretty big, e.g. 30 minutes. This can force a certain value. /// pretty big, e.g. 30 minutes. This can force a certain value.
#[arg(short = 'i', long = "tracker-refresh-interval", value_parser = parse_duration::parse)] #[arg(short = 'i', long = "tracker-refresh-interval", value_parser = parse_duration::parse, env="RQBIT_TRACKER_REFRESH_INTERVAL")]
force_tracker_interval: Option<Duration>, force_tracker_interval: Option<Duration>,
/// The listen address for HTTP API /// The listen address for HTTP API
#[arg(long = "http-api-listen-addr", default_value = "127.0.0.1:3030")] #[arg(
long = "http-api-listen-addr",
default_value = "127.0.0.1:3030",
env = "RQBIT_HTTP_API_LISTEN_ADDR"
)]
http_api_listen_addr: SocketAddr, http_api_listen_addr: SocketAddr,
/// Set this flag if you want to use tokio's single threaded runtime. /// Set this flag if you want to use tokio's single threaded runtime.
/// It MAY perform better, but the main purpose is easier debugging, as time /// It MAY perform better, but the main purpose is easier debugging, as time
/// profilers work better with this one. /// profilers work better with this one.
#[arg(short, long)] #[arg(short, long, env = "RQBIT_SINGLE_THREAD_RUNTIME")]
single_thread_runtime: bool, single_thread_runtime: bool,
#[arg(long = "disable-dht")] #[arg(long = "disable-dht", env = "RQBIT_DHT_DISABLE")]
disable_dht: bool, disable_dht: bool,
/// Set this to disable DHT reading and storing it's state. /// Set this to disable DHT reading and storing it's state.
/// For now this is a useful workaround if you want to launch multiple rqbit instances, /// For now this is a useful workaround if you want to launch multiple rqbit instances,
/// otherwise DHT port will conflict. /// otherwise DHT port will conflict.
#[arg(long = "disable-dht-persistence")] #[arg(
long = "disable-dht-persistence",
env = "RQBIT_DHT_PERSISTENCE_DISABLE"
)]
disable_dht_persistence: bool, disable_dht_persistence: bool,
/// The connect timeout, e.g. 1s, 1.5s, 100ms etc. /// The connect timeout, e.g. 1s, 1.5s, 100ms etc.
#[arg(long = "peer-connect-timeout", value_parser = parse_duration::parse, default_value="2s")] #[arg(long = "peer-connect-timeout", value_parser = parse_duration::parse, default_value="2s", env="RQBIT_PEER_CONNECT_TIMEOUT")]
peer_connect_timeout: Duration, peer_connect_timeout: Duration,
/// The connect timeout, e.g. 1s, 1.5s, 100ms etc. /// The connect timeout, e.g. 1s, 1.5s, 100ms etc.
#[arg(long = "peer-read-write-timeout" , value_parser = parse_duration::parse, default_value="10s")] #[arg(long = "peer-read-write-timeout" , value_parser = parse_duration::parse, default_value="10s", env="RQBIT_PEER_READ_WRITE_TIMEOUT")]
peer_read_write_timeout: Duration, peer_read_write_timeout: Duration,
/// How many threads to spawn for the executor. /// How many threads to spawn for the executor.
#[arg(short = 't', long)] #[arg(short = 't', long, env = "RQBIT_RUNTIME_WORKER_THREADS")]
worker_threads: Option<usize>, worker_threads: Option<usize>,
// Enable to listen on 0.0.0.0 on TCP for torrent requests. // Enable to listen on 0.0.0.0 on TCP for torrent requests.
#[arg(long = "disable-tcp-listen")] #[arg(long = "disable-tcp-listen", env = "RQBIT_TCP_LISTEN_DISABLE")]
disable_tcp_listen: bool, disable_tcp_listen: bool,
/// The minimal port to listen for incoming connections. /// The minimal port to listen for incoming connections.
#[arg(long = "tcp-min-port", default_value = "4240")] #[arg(
long = "tcp-min-port",
default_value = "4240",
env = "RQBIT_TCP_LISTEN_MIN_PORT"
)]
tcp_listen_min_port: u16, tcp_listen_min_port: u16,
/// The maximal port to listen for incoming connections. /// The maximal port to listen for incoming connections.
#[arg(long = "tcp-max-port", default_value = "4260")] #[arg(
long = "tcp-max-port",
default_value = "4260",
env = "RQBIT_TCP_LISTEN_MAX_PORT"
)]
tcp_listen_max_port: u16, tcp_listen_max_port: u16,
/// If set, will try to publish the chosen port through upnp on your router. /// If set, will try to publish the chosen port through upnp on your router.
#[arg(long = "disable-upnp")] #[arg(long = "disable-upnp", env = "RQBIT_UPNP_DISABLE_PORT_FORWARD")]
disable_upnp: bool, disable_upnp: bool,
/// If set, will run a UPNP Media server and stream all the torrents through it. /// If set, will run a UPNP Media server and stream all the torrents through it.
/// Should be set to your hostname/IP as seen by your LAN neighbors. /// Should be set to your hostname/IP as seen by your LAN neighbors.
#[arg(long = "upnp-server-hostname")] #[arg(long = "upnp-server-hostname", env = "RQBIT_UPNP_SERVER_HOSTNAME")]
upnp_server_hostname: Option<String>, upnp_server_hostname: Option<String>,
/// UPNP server name that would be displayed on devices in your network. /// UPNP server name that would be displayed on devices in your network.
#[arg(long = "upnp-server-friendly-name")] #[arg(
long = "upnp-server-friendly-name",
env = "RQBIT_UPNP_SERVER_FRIENDLY_NAME"
)]
upnp_server_friendly_name: Option<String>, upnp_server_friendly_name: Option<String>,
#[command(subcommand)] #[command(subcommand)]
@ -111,14 +133,18 @@ struct Opts {
/// How many maximum blocking tokio threads to spawn to process disk reads/writes. /// How many maximum blocking tokio threads to spawn to process disk reads/writes.
/// This will indicate how many parallel reads/writes can happen at a moment in time. /// This will indicate how many parallel reads/writes can happen at a moment in time.
/// The higher the number, the more the memory usage. /// The higher the number, the more the memory usage.
#[arg(long = "max-blocking-threads", default_value = "8")] #[arg(
long = "max-blocking-threads",
default_value = "8",
env = "RQBIT_RUNTIME_MAX_BLOCKING_THREADS"
)]
max_blocking_threads: u16, max_blocking_threads: u16,
// If you set this to something, all writes to disk will happen in background and be // If you set this to something, all writes to disk will happen in background and be
// buffered in memory up to approximately the given number of megabytes. // buffered in memory up to approximately the given number of megabytes.
// //
// Might be useful for slow disks. // Might be useful for slow disks.
#[arg(long = "defer-writes-up-to")] #[arg(long = "defer-writes-up-to", env = "RQBIT_DEFER_WRITES_UP_TO")]
defer_writes_up_to: Option<usize>, defer_writes_up_to: Option<usize>,
/// Use mmap (file-backed) for storage. Any advantages are questionable and unproven. /// Use mmap (file-backed) for storage. Any advantages are questionable and unproven.
@ -130,11 +156,11 @@ struct Opts {
/// The format is socks5://[username:password]@host:port /// The format is socks5://[username:password]@host:port
/// ///
/// Alternatively, set this as an environment variable RQBIT_SOCKS_PROXY_URL /// Alternatively, set this as an environment variable RQBIT_SOCKS_PROXY_URL
#[arg(long)] #[arg(long, env = "RQBIT_SOCKS_PROXY_URL")]
socks_url: Option<String>, socks_url: Option<String>,
/// How many torrents can be initializing (rehashing) at the same time /// How many torrents can be initializing (rehashing) at the same time
#[arg(long, default_value = "5")] #[arg(long, default_value = "5", env = "RQBIT_CONCURRENT_INIT_LIMIT")]
concurrent_init_limit: usize, concurrent_init_limit: usize,
} }
@ -142,20 +168,21 @@ struct Opts {
struct ServerStartOptions { struct ServerStartOptions {
/// The output folder to write to. If not exists, it will be created. /// The output folder to write to. If not exists, it will be created.
output_folder: String, output_folder: String,
#[arg( #[arg(
long = "disable-persistence", long = "disable-persistence",
help = "Disable server persistence. It will not read or write its state to disk." help = "Disable server persistence. It will not read or write its state to disk.",
env = "RQBIT_SESSION_PERSISTENCE_DISABLE"
)] )]
/// Disable session persistence. /// Disable session persistence.
disable_persistence: bool, disable_persistence: bool,
/// The folder to store session data in. By default uses OS specific folder. /// The folder to store session data in. By default uses OS specific folder.
#[arg(long = "persistence-config")] #[arg(long = "persistence-config", env = "RQBIT_SESSION_PERSISTENCE_FOLDER")]
persistence_config: Option<String>, persistence_config: Option<String>,
/// [Experimental] if set, will try to resume quickly after restart and skip checksumming. /// [Experimental] if set, will try to resume quickly after restart and skip checksumming.
#[arg(long = "fastresume")] #[arg(long = "fastresume", env = "RQBIT_FASTRESUME")]
fastresume: bool, fastresume: bool,
} }
@ -310,10 +337,6 @@ async fn async_main(opts: Opts) -> anyhow::Result<()> {
Err(e) => warn!("failed increasing open file limit: {:#}", e), Err(e) => warn!("failed increasing open file limit: {:#}", e),
}; };
let socks_url = opts
.socks_url
.or_else(|| std::env::var("RQBIT_SOCKS_PROXY_URL").ok());
let mut sopts = SessionOptions { let mut sopts = SessionOptions {
disable_dht: opts.disable_dht, disable_dht: opts.disable_dht,
disable_dht_persistence: opts.disable_dht_persistence, disable_dht_persistence: opts.disable_dht_persistence,
@ -352,7 +375,7 @@ async fn async_main(opts: Opts) -> anyhow::Result<()> {
wrap(FilesystemStorageFactory::default()).boxed() wrap(FilesystemStorageFactory::default()).boxed()
} }
}), }),
socks_proxy_url: socks_url, socks_proxy_url: opts.socks_url,
concurrent_init_limit: Some(opts.concurrent_init_limit), concurrent_init_limit: Some(opts.concurrent_init_limit),
root_span: None, root_span: None,
fastresume: false, fastresume: false,