use snafu::ResultExt; use qbittorrent_web_api::Api; use tokio::runtime::Builder; use crate::config::Config; use crate::error::{Error, ApiSnafu as IOError, InternalApiSnafu as ApiError}; pub struct ApiClient { pub rt: tokio::runtime::Runtime, pub api: qbittorrent_web_api::api_impl::Authenticated } impl ApiClient { pub fn from_config(config: &Config) -> Result { Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password) } pub fn new(host: &str, login: &str, password: &str) -> Result { let rt = Builder::new_current_thread() .enable_all() .build().context(IOError)?; // Call the asynchronous connect method using the runtime. let api = rt.block_on(Api::login(host, &login, &password)).context(ApiError)?; Ok(ApiClient { rt, api, }) } pub fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> { let base_call = self.api.torrent_management(); let call = if paused { base_call.add(magnet).paused("true") } else { base_call.add(magnet) }; let res = self.rt.block_on(call.send_raw()).context(ApiError)?; if res == "Ok." { Ok(()) } else { Err(Error::message(res.clone())) } } pub fn get(&self, hash: &str) -> Result, Error> { let res = self.rt.block_on(self.api.torrent_management().properties_raw(hash)).context(ApiError)?; if res == "" { Ok(None) } else { Ok(Some(res)) } } pub fn list(&self) -> Result { Ok( self.rt.block_on(self.api.torrent_management().info().send_raw()).context(ApiError)? ) } } // TODO: typestate builder https://www.greyblake.com/blog/builder-with-typestate-in-rust/ //struct ApiClientBuilder {}