Compare commits

...

2 Commits

Author SHA1 Message Date
68360c0286 async api wrapper 2022-10-27 21:22:12 +02:00
7ebcbab9ac dont warn dead code for test utils 2022-10-27 21:21:18 +02:00
3 changed files with 107 additions and 0 deletions

105
src/async_api.rs Normal file
View File

@ -0,0 +1,105 @@
use snafu::ResultExt;
use qbittorrent_web_api::Api;
use qbittorrent_web_api::api_impl::Error as QBittorrentError;
use crate::config::Config;
use crate::error::{Error, InternalApiSnafu as ApiError};
#[derive(Debug)]
pub struct UnauthenticatedRawApiClient;
impl UnauthenticatedRawApiClient {
/// Initialize a blocking runtime for the API client
pub fn new() -> UnauthenticatedRawApiClient {
UnauthenticatedRawApiClient
}
/// Login into a qBittorrent backend and return a proper ApiClient instance
pub async fn login(self, host: &str, login: &str, password: &str) -> Result<RawApiClient, QBittorrentError> {
let api = Api::login(host, login, password).await?;
Ok(RawApiClient {
api,
})
}
}
#[derive(Debug)]
pub struct RawApiClient {
api: qbittorrent_web_api::api_impl::Authenticated,
}
impl RawApiClient {
pub async fn add(&self, magnet: &str, paused: bool) -> Result<String, QBittorrentError> {
let base_call = self.api.torrent_management();
let call = if paused {
base_call.add(magnet).paused("true")
} else {
base_call.add(magnet)
};
call.send_raw().await
}
pub async fn get(&self, hash: &str) -> Result<String, QBittorrentError> {
self.api.torrent_management().properties_raw(hash).await
}
pub async fn list(&self) -> Result<String, QBittorrentError> {
self.api.torrent_management().info().send_raw().await
}
}
#[derive(Debug)]
/// ApiClient is a convenience struct around qbittorrent_web_api for use in async programs, using qbt::Error error types.
pub struct ApiClient {
pub raw_api: RawApiClient,
}
impl ApiClient {
/// Login to a qBittorrent backend and return a handle to the ApiClient
pub async fn new(host: &str, login: &str, password: &str) -> Result<ApiClient, Error> {
let unauthenticated = UnauthenticatedRawApiClient::new();
let authenticated = unauthenticated.login(host, login, password).await.map_err(|e| {
match e {
QBittorrentError::HttpError(_) => {
Error::FailedToReachAPI { source: e }
}, QBittorrentError::InvalidUsernameOrPassword => {
Error::FailedLogin { user: login.to_string() }
} _ => {
panic!("Cookie error");
}
}
})?;
Ok(ApiClient {
raw_api: authenticated,
})
}
pub async fn from_config(config: &Config) -> Result<ApiClient, Error> {
Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password).await
}
pub async fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> {
let res = self.raw_api.add(magnet, paused).await.context(ApiError)?;
if res == "Ok." {
Ok(())
} else {
Err(Error::message(res.clone()))
}
}
pub async fn get(&self, hash: &str) -> Result<Option<String>, Error> {
let res = self.raw_api.get(hash).await.context(ApiError)?;
if res == "" {
Ok(None)
} else {
Ok(Some(res))
}
}
pub async fn list(&self) -> Result<String, Error> {
self.raw_api.list().await.context(ApiError)
}
}

View File

@ -1,5 +1,6 @@
pub mod action;
pub mod api;
pub mod async_api;
pub mod config;
pub use config::Config;
pub mod cli;

View File

@ -79,6 +79,7 @@ pub fn torrent_to_magnet<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
}
// Fallible: only used in tests
#[allow(dead_code)]
pub fn find_free_port() -> u16 {
let bind = TcpListener::bind("127.0.0.1:0").unwrap();
bind.local_addr().unwrap().port()