diff --git a/.dockerignore b/.dockerignore index 73bbc30..2d4883e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ /target -Dockerfile \ No newline at end of file +Dockerfile +port-file \ No newline at end of file diff --git a/.gitignore b/.gitignore index ea8c4bf..9def2c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +port-file \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 97e7f73..2b8cd30 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,9 @@ RUN cargo build --release # Runner stage. FROM alpine +RUN apk update && \ + apk add curl + ARG UNAME=port_updater ARG UID=1000 ARG GID=1000 diff --git a/README.md b/README.md index 9f9fc6d..b941aa1 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ Currently the only configuration method is through environmental variables: | Name | Description | Example | Required | |---|---|---|---| -| 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_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 | diff --git a/src/main.rs b/src/main.rs index c248287..2ebb87f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ use std::{path::Path, time::Duration, sync::Arc, collections::HashMap}; +use anyhow::anyhow; use figment::{Figment, providers::Env}; use notify::{RecursiveMode, Watcher, Event, EventKind, event::{ModifyKind, DataChange}}; +use reqwest::StatusCode; use serde::Deserialize; #[derive(Debug, PartialEq, Deserialize)] @@ -40,11 +42,12 @@ fn main() -> anyhow::Result<()> { std::thread::sleep(Duration::from_secs(10)); } - while reqwest::blocking::get(config.qbit_full_url()).and_then(|r| r.error_for_status()).is_err() { - println!("Couldn't reach qbittorrent at {}", config.qbit_full_url()); + /* 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| { @@ -53,7 +56,12 @@ fn main() -> anyhow::Result<()> { //println!("e: {:?}", e); if e.kind == EventKind::Modify(ModifyKind::Data(DataChange::Content)) || e.kind.is_create() || e.kind.is_access() { - update_port(config_clone.clone()).unwrap(); + + 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), @@ -61,7 +69,11 @@ fn main() -> anyhow::Result<()> { })?; // update the port once on start in the case that gluetun got connected before this started - update_port(config.clone()).unwrap(); + while let Err(e) = update_port(config.clone()) { + println!("Could not update qbittorrent port! ({e})"); + println!("Trying again in 10 seconds"); + std::thread::sleep(Duration::from_secs(10)); + } loop { watcher.watch(port_path, RecursiveMode::Recursive)?; @@ -73,32 +85,30 @@ fn update_port(config: Arc) -> anyhow::Result<()> { let client = reqwest::blocking::Client::new(); - let mut cookie_header = "".to_string(); + 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()) { - - let login_url = format!("{}/api/v2/auth/login", qbit_url); - - let mut form = HashMap::new(); form.insert("username", login); form.insert("password", pass); - - let res = client.get(login_url) - .form(&form) - .send()?; - - let cookie = res.headers().get("Set-Cookie").expect("Login failed"); - let cookie = cookie.to_str().unwrap(); - - let sid_start = cookie.find("SID=").unwrap(); - let sid_end = cookie.find(";").unwrap(); - let sid = &cookie[sid_start..sid_end]; - let cookie = format!("SID={};", sid); - - cookie_header = cookie; } + 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() + }; + let new_port = std::fs::read_to_string(&config.port_file)?; let new_port = new_port.trim(); @@ -109,7 +119,7 @@ fn update_port(config: Arc) -> anyhow::Result<()> { let url = format!("{}/api/v2/app/setPreferences", qbit_url); let _body = client.post(url) .form(&form) - .header("Cookie", cookie_header) + .header("Cookie", cookie) .send()? .error_for_status()?;