Rewrite to make more reliable
This commit is contained in:
parent
0e527da269
commit
1ad352967c
|
@ -17,12 +17,6 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.6.0"
|
||||
|
@ -120,25 +114,6 @@ version = "0.8.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.33"
|
||||
|
@ -193,18 +168,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -235,15 +198,6 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.29"
|
||||
|
@ -300,14 +254,15 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
|||
|
||||
[[package]]
|
||||
name = "gluetun-qbit-port-updater"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"eyre",
|
||||
"figment",
|
||||
"notify",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"stable-eyre",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -444,26 +399,6 @@ version = "0.1.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.9.0"
|
||||
|
@ -485,26 +420,6 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue-sys"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -557,7 +472,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
@ -580,25 +494,6 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "6.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
|
@ -717,9 +612,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -739,9 +634,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -818,15 +713,6 @@ version = "1.0.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.22"
|
||||
|
@ -861,18 +747,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.193"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.193"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -881,9 +767,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -944,9 +830,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.41"
|
||||
version = "2.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||
checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1004,9 +890,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.35.0"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
|
||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -1015,9 +901,21 @@ dependencies = [
|
|||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.5",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
|
@ -1126,16 +1024,6 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
|
@ -1243,15 +1131,6 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
[package]
|
||||
name = "gluetun-qbit-port-updater"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
eyre = "0.6.12"
|
||||
figment = { version = "0.10.12", features = ["env"] }
|
||||
notify = "6.1.1"
|
||||
reqwest = { version = "0.11.22", features = ["blocking"] }
|
||||
reqwest = { version = "0.11.22", features = ["blocking", "json"] }
|
||||
serde = { version = "1.0.193", features = ["serde_derive"] }
|
||||
serde_json = "1.0.117"
|
||||
stable-eyre = "0.2.2"
|
||||
tokio = { version = "1.37.0", features = ["rt", "macros", "fs"] }
|
||||
|
|
18
README.md
18
README.md
|
@ -1,14 +1,18 @@
|
|||
# Gluetun Qbittorrent Port Updater
|
||||
Automatically updates qBittorrent's listening port to the port forwarded by [Gluetun](https://github.com/qdm12/gluetun/).
|
||||
|
||||
It works by checking the port in use by qBittorrent, and reading the port file created by Gluetun. If they do not match, it updates the port that qBittorrent is using.
|
||||
|
||||
## Configuration
|
||||
Currently the only configuration method is through environmental variables:
|
||||
|
||||
| Name | Description | Example | Required |
|
||||
| Name | Description | Example | Required | Default |
|
||||
|---|---|---|---|
|
||||
| PORT_UPD_QBITTORRENT_LOGIN | The login information for the webui. | `admin` | false |
|
||||
| PORT_UPD_QBITTORRENT_PASSWORD | The password for the webui. | `adminadmin` | false |
|
||||
| PORT_UPD_QBITTORRENT_PORT | The port of the webui. | `8080` | true |
|
||||
| PORT_UPD_QBITTORRENT_HOST | The host of the webui. | `localhost` | true |
|
||||
| PORT_UPD_QBITTORRENT_HTTPS | Set to `true` if the connection to the webui is https encrypted. | `false` | true |
|
||||
| PORT_UPD_PORT_FILE | The path to the file that contains the port. | `/tmp/gluetun/forwarded_port` | true |
|
||||
| PORT_UPD_QBITTORRENT_LOGIN | The login information for the webui. | `admin` | false | empty string |
|
||||
| PORT_UPD_QBITTORRENT_PASSWORD | The password for the webui. | `adminadmin` | false | empty string |
|
||||
| PORT_UPD_QBITTORRENT_PORT | The port of the webui. | `8080` | true | |
|
||||
| PORT_UPD_QBITTORRENT_HOST | The host of the webui. | `localhost` | true | |
|
||||
| PORT_UPD_QBITTORRENT_HTTPS | Set to `true` if the connection to the webui is https encrypted. | `false` | true | |
|
||||
| PORT_UPD_PORT_FILE | The path to the file that contains the port. | `/tmp/gluetun/forwarded_port` | true | |
|
||||
| PORT_UPD_MAX_FAILURES | The amount of times to recheck the port before exiting. | 10 | false | 10 |
|
||||
| PORT_UPD_RECHECK_PERIOD | The period, in second, to check the port. | 60 | false | 60 |
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use eyre::eyre;
|
||||
use reqwest::StatusCode;
|
||||
|
||||
pub struct QbitClient {
|
||||
url: String,
|
||||
username: Option<String>,
|
||||
password: Option<String>,
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl QbitClient {
|
||||
/// Create a new client and authenticate with qbittorrent
|
||||
pub fn new(full_url: String, username: Option<String>, password: Option<String>) -> Self {
|
||||
Self {
|
||||
url: full_url,
|
||||
username,
|
||||
password,
|
||||
client: reqwest::Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn login(&self) -> eyre::Result<String> {
|
||||
let login_url = format!("{}/api/v2/auth/login", self.url);
|
||||
|
||||
let mut form = HashMap::new();
|
||||
if let (Some(username), Some(password)) = (&self.username, &self.password) {
|
||||
form.insert("username", username);
|
||||
form.insert("password", password);
|
||||
}
|
||||
|
||||
let res = self.client.post(login_url)
|
||||
.form(&form)
|
||||
.send().await?;
|
||||
|
||||
let cookie = if let Some(cookie) = res.headers().get(reqwest::header::SET_COOKIE) {
|
||||
let cookies: Vec<_> = cookie.to_str().unwrap().split(";").collect();
|
||||
let sid = cookies.iter().find(|c| c.starts_with("SID=")).unwrap();
|
||||
sid[4..].to_string()
|
||||
//format!("{};", sid)
|
||||
} else if res.status() == StatusCode::FORBIDDEN {
|
||||
return Err(eyre!("Failure to auth, credentials are incorrect!"));
|
||||
} else {
|
||||
res.error_for_status()?;
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
Ok(cookie)
|
||||
}
|
||||
|
||||
pub async fn set_listen_port(&self, token: String, port: u32) -> eyre::Result<()> {
|
||||
let mut form = HashMap::new();
|
||||
let json = format!("{{\"listen_port\": \"{}\"}}", port);
|
||||
form.insert("json", json);
|
||||
|
||||
let cookie = format!("SID={};", token);
|
||||
let url = format!("{}/api/v2/app/setPreferences", self.url);
|
||||
let _body = self.client.post(url)
|
||||
.form(&form)
|
||||
.header("Cookie", cookie)
|
||||
.send().await?
|
||||
.error_for_status()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_listen_port(&self, token: String) -> eyre::Result<u32> {
|
||||
let cookie = format!("SID={};", token);
|
||||
let url = format!("{}/api/v2/app/preferences", self.url);
|
||||
let body = self.client.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.send().await?
|
||||
.error_for_status()?;
|
||||
|
||||
let json: HashMap<String, serde_json::Value> = body.json().await?;
|
||||
let port = json["listen_port"].as_u64()
|
||||
.ok_or(eyre!("listen_port preference missing"))?;
|
||||
|
||||
Ok(port as _)
|
||||
}
|
||||
}
|
123
src/main.rs
123
src/main.rs
|
@ -1,12 +1,12 @@
|
|||
use std::{path::Path, time::Duration, sync::Arc, collections::HashMap};
|
||||
use std::{path::Path, process::exit, sync::Arc, time::Duration};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use figment::{Figment, providers::Env};
|
||||
use notify::{RecursiveMode, Watcher, Event, EventKind, event::{ModifyKind, DataChange}};
|
||||
use reqwest::StatusCode;
|
||||
use serde::Deserialize;
|
||||
use stable_eyre::eyre::Report;
|
||||
|
||||
mod client;
|
||||
use client::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct Config {
|
||||
qbittorrent_login: Option<String>,
|
||||
|
@ -15,6 +15,18 @@ struct Config {
|
|||
qbittorrent_port: u32,
|
||||
qbittorrent_host: String,
|
||||
port_file: String,
|
||||
#[serde(default="default_max_failures")]
|
||||
max_failures: u32,
|
||||
#[serde(default="default_seconds_delay")]
|
||||
recheck_period: u32,
|
||||
}
|
||||
|
||||
fn default_max_failures() -> u32 {
|
||||
10
|
||||
}
|
||||
|
||||
fn default_seconds_delay() -> u32 {
|
||||
60
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
@ -31,110 +43,65 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Report> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Report> {
|
||||
stable_eyre::install()?;
|
||||
|
||||
let config: Arc<Config> = Arc::new(Figment::new()
|
||||
.merge(Env::prefixed("PORT_UPD_"))
|
||||
.extract()?);
|
||||
|
||||
let client = Arc::new(QbitClient::new(config.qbit_full_url(), config.qbittorrent_login.clone(), config.qbittorrent_password.clone()));
|
||||
|
||||
let port_path = Path::new(&config.port_file);
|
||||
while !port_path.exists() {
|
||||
println!("Couldn't find {}", config.port_file);
|
||||
println!("Could not find {}", config.port_file);
|
||||
println!("Trying again in 10 seconds");
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
}
|
||||
|
||||
/* let url = format!("{}/api/v2/app/version", config.qbit_full_url());
|
||||
while let Err(e) = reqwest::blocking::get(&url) {//.and_then(|r| r.error_for_status()) {
|
||||
println!("Couldn't reach qbittorrent at {} ({})", url, e);
|
||||
println!("Trying again in 10 seconds");
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
} */
|
||||
|
||||
let config_clone = config.clone();
|
||||
let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| {
|
||||
match res {
|
||||
Ok(e) => {
|
||||
//println!("e: {:?}", e);
|
||||
if e.kind == EventKind::Modify(ModifyKind::Data(DataChange::Content))
|
||||
|| e.kind.is_create() || e.kind.is_access() {
|
||||
|
||||
while let Err(e) = update_port(config_clone.clone()) {
|
||||
println!("Could not update qbittorrent port! ({e})");
|
||||
println!("Trying again in 10 seconds");
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => println!("watch error: {:?}", e),
|
||||
}
|
||||
})?;
|
||||
|
||||
// update the port once on start in the case that gluetun got connected before this started
|
||||
while let Err(e) = update_port(config.clone()) {
|
||||
while let Err(e) = ensure_port_sync(&client, &config).await {
|
||||
println!("Could not update qbittorrent port! ({e})");
|
||||
println!("Trying again in 10 seconds");
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
}
|
||||
|
||||
let mut fails = 0;
|
||||
loop {
|
||||
match watcher.watch(port_path, RecursiveMode::Recursive) {
|
||||
tokio::time::sleep(Duration::from_secs(config.recheck_period as _)).await;
|
||||
|
||||
match ensure_port_sync(&client, &config).await {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
println!("watch error: {:?}", e);
|
||||
|
||||
fails += 1;
|
||||
|
||||
if fails >= config.max_failures {
|
||||
println!("Exceeded max failure count, exiting...");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
println!("Trying again in 10 seconds");
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_port(config: Arc<Config>) -> anyhow::Result<()> {
|
||||
let qbit_url = config.qbit_full_url();
|
||||
|
||||
let client = reqwest::blocking::Client::new();
|
||||
|
||||
let login_url = format!("{}/api/v2/auth/login", qbit_url);
|
||||
|
||||
let mut form = HashMap::new();
|
||||
if let (Some(login), Some(pass)) = (config.qbittorrent_login.clone(),
|
||||
config.qbittorrent_password.clone()) {
|
||||
form.insert("username", login);
|
||||
form.insert("password", pass);
|
||||
}
|
||||
|
||||
let res = client.post(login_url)
|
||||
.form(&form)
|
||||
.send()?;
|
||||
|
||||
let cookie = if let Some(cookie) = res.headers().get(reqwest::header::SET_COOKIE) {
|
||||
let cookies: Vec<_> = cookie.to_str().unwrap().split(";").collect();
|
||||
let sid = cookies.iter().find(|c| c.starts_with("SID=")).unwrap();
|
||||
format!("{};", sid)
|
||||
} else if res.status() == StatusCode::FORBIDDEN {
|
||||
return Err(anyhow!("Failure to auth, credentials are incorrect!"));
|
||||
} else {
|
||||
res.error_for_status()?;
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
async fn ensure_port_sync(client: &Arc<QbitClient>, config: &Arc<Config>) -> eyre::Result<()> {
|
||||
let new_port = std::fs::read_to_string(&config.port_file)?;
|
||||
let new_port = new_port.trim();
|
||||
let new_port = new_port.trim().parse::<u32>()?;
|
||||
|
||||
let token = client.login().await?;
|
||||
|
||||
let mut form = HashMap::new();
|
||||
let json = format!("{{\"listen_port\": \"{}\"}}", new_port);
|
||||
form.insert("json", json);
|
||||
let current_port = client.get_listen_port(token.clone()).await?;
|
||||
|
||||
let url = format!("{}/api/v2/app/setPreferences", qbit_url);
|
||||
let _body = client.post(url)
|
||||
.form(&form)
|
||||
.header("Cookie", cookie)
|
||||
.send()?
|
||||
.error_for_status()?;
|
||||
|
||||
println!("Successfully updated qbittorrent to port {}", new_port);
|
||||
if new_port != current_port {
|
||||
println!("Detected port change: {}", new_port);
|
||||
client.set_listen_port(token.clone(), 0).await?;
|
||||
client.set_listen_port(token, new_port).await?;
|
||||
println!("Updated port");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue